Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/uhci-hcd/uhci.c

    rff34e5a ra7e2f0d  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 
    29 /** @addtogroup drvusbuhci
     28/** @addtogroup usb
    3029 * @{
    3130 */
     
    3534#include <errno.h>
    3635#include <str_error.h>
    37 #include <ddf/interrupt.h>
     36#include <adt/list.h>
     37#include <libarch/ddi.h>
     38
     39#include <usb/debug.h>
     40#include <usb/usb.h>
     41#include <usb/ddfiface.h>
    3842#include <usb_iface.h>
    39 #include <usb/ddfiface.h>
    40 #include <usb/debug.h>
    4143
    4244#include "uhci.h"
    4345#include "iface.h"
    44 #include "pci.h"
    45 
    46 
    47 /** IRQ handling callback, identifies device
    48  *
    49  * @param[in] dev DDF instance of the device to use.
    50  * @param[in] iid (Unused).
    51  * @param[in] call Pointer to the call that represents interrupt.
    52  */
    53 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
    54 {
    55         assert(dev);
    56         uhci_hc_t *hc = &((uhci_t*)dev->driver_data)->hc;
    57         uint16_t status = IPC_GET_ARG1(*call);
    58         assert(hc);
    59         uhci_hc_interrupt(hc, status);
    60 }
    61 /*----------------------------------------------------------------------------*/
    62 /** Get address of the device identified by handle.
    63  *
    64  * @param[in] dev DDF instance of the device to use.
    65  * @param[in] iid (Unused).
    66  * @param[in] call Pointer to the call that represents interrupt.
     46
     47static irq_cmd_t uhci_cmds[] = {
     48        {
     49                .cmd = CMD_PIO_READ_16,
     50                .addr = NULL, /* patched for every instance */
     51                .dstarg = 1
     52        },
     53        {
     54                .cmd = CMD_PIO_WRITE_16,
     55                .addr = NULL, /* pathed for every instance */
     56                .value = 0x1f
     57        },
     58        {
     59                .cmd = CMD_ACCEPT
     60        }
     61};
     62
     63/** Gets USB address of the calling device.
     64 *
     65 * @param[in] fun UHCI hc function.
     66 * @param[in] handle Handle of the device seeking address.
     67 * @param[out] address Place to store found address.
     68 * @return Error code.
    6769 */
    6870static int usb_iface_get_address(
     
    7072{
    7173        assert(fun);
    72         device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.device_manager;
    73 
    74         usb_address_t addr = device_keeper_find(manager, handle);
     74        uhci_t *hc = fun_to_uhci(fun);
     75        assert(hc);
     76
     77        usb_address_t addr = device_keeper_find(&hc->device_manager,
     78            handle);
    7579        if (addr < 0) {
    7680                return addr;
     
    8488}
    8589/*----------------------------------------------------------------------------*/
    86 /** Gets handle of the respective hc (this or parent device).
    87  *
    88  * @param[in] root_hub_fun Root hub function seeking hc handle.
    89  * @param[out] handle Place to write the handle.
    90  * @return Error code.
    91  */
    92 static int usb_iface_get_hc_handle(
    93     ddf_fun_t *fun, devman_handle_t *handle)
    94 {
    95         assert(handle);
    96         ddf_fun_t *hc_fun = ((uhci_t*)fun->dev->driver_data)->hc_fun;
    97         assert(hc_fun != NULL);
    98 
    99         *handle = hc_fun->handle;
    100         return EOK;
    101 }
    102 /*----------------------------------------------------------------------------*/
    103 /** This iface is generic for both RH and HC. */
    104 static usb_iface_t usb_iface = {
    105         .get_hc_handle = usb_iface_get_hc_handle,
     90static usb_iface_t hc_usb_iface = {
     91        .get_hc_handle = usb_iface_get_hc_handle_hc_impl,
    10692        .get_address = usb_iface_get_address
    10793};
    10894/*----------------------------------------------------------------------------*/
    109 static ddf_dev_ops_t uhci_hc_ops = {
    110         .interfaces[USB_DEV_IFACE] = &usb_iface,
    111         .interfaces[USBHC_DEV_IFACE] = &uhci_hc_iface, /* see iface.h/c */
     95static ddf_dev_ops_t uhci_ops = {
     96        .interfaces[USB_DEV_IFACE] = &hc_usb_iface,
     97        .interfaces[USBHC_DEV_IFACE] = &uhci_iface,
    11298};
    11399/*----------------------------------------------------------------------------*/
    114 /** Get root hub hw resources (I/O registers).
    115  *
    116  * @param[in] fun Root hub function.
    117  * @return Pointer to the resource list used by the root hub.
    118  */
    119 static hw_resource_list_t *get_resource_list(ddf_fun_t *fun)
    120 {
    121         assert(fun);
    122         return &((uhci_rh_t*)fun->driver_data)->resource_list;
    123 }
    124 /*----------------------------------------------------------------------------*/
    125 static hw_res_ops_t hw_res_iface = {
    126         .get_resource_list = get_resource_list,
    127         .enable_interrupt = NULL
    128 };
    129 /*----------------------------------------------------------------------------*/
    130 static ddf_dev_ops_t uhci_rh_ops = {
    131         .interfaces[USB_DEV_IFACE] = &usb_iface,
    132         .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface
    133 };
    134 /*----------------------------------------------------------------------------*/
    135 /** Initialize hc and rh ddf structures and their respective drivers.
    136  *
    137  * @param[in] instance UHCI structure to use.
    138  * @param[in] device DDF instance of the device to use.
    139  *
    140  * This function does all the preparatory work for hc and rh drivers:
    141  *  - gets device hw resources
    142  *  - disables UHCI legacy support
    143  *  - asks for interrupt
    144  *  - registers interrupt handler
    145  */
    146 int uhci_init(uhci_t *instance, ddf_dev_t *device)
    147 {
    148         assert(instance);
    149         instance->hc_fun = NULL;
    150         instance->rh_fun = NULL;
     100static int uhci_init_transfer_lists(uhci_t *instance);
     101static int uhci_init_mem_structures(uhci_t *instance);
     102static void uhci_init_hw(uhci_t *instance);
     103
     104static int uhci_interrupt_emulator(void *arg);
     105static int uhci_debug_checker(void *arg);
     106
     107static bool allowed_usb_packet(
     108    bool low_speed, usb_transfer_type_t transfer, size_t size);
     109/*----------------------------------------------------------------------------*/
     110/** Initializes UHCI hcd driver structure
     111 *
     112 * @param[in] instance Memory place to initialize.
     113 * @param[in] dev DDF device.
     114 * @param[in] regs Address of I/O control registers.
     115 * @param[in] size Size of I/O control registers.
     116 * @return Error code.
     117 * @note Should be called only once on any structure.
     118 */
     119int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size)
     120{
     121        assert(reg_size >= sizeof(regs_t));
     122        int ret;
     123
    151124#define CHECK_RET_DEST_FUN_RETURN(ret, message...) \
    152 if (ret != EOK) { \
    153         usb_log_error(message); \
    154         if (instance->hc_fun) \
    155                 ddf_fun_destroy(instance->hc_fun); \
    156         if (instance->rh_fun) \
    157                 ddf_fun_destroy(instance->rh_fun); \
    158         return ret; \
    159 }
    160 
    161         uintptr_t io_reg_base = 0;
    162         size_t io_reg_size = 0;
    163         int irq = 0;
    164 
    165         int ret =
    166             pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq);
     125        if (ret != EOK) { \
     126                usb_log_error(message); \
     127                if (instance->ddf_instance) \
     128                        ddf_fun_destroy(instance->ddf_instance); \
     129                return ret; \
     130        } else (void) 0
     131
     132        /* Create UHCI function. */
     133        instance->ddf_instance = ddf_fun_create(dev, fun_exposed, "uhci");
     134        ret = (instance->ddf_instance == NULL) ? ENOMEM : EOK;
    167135        CHECK_RET_DEST_FUN_RETURN(ret,
    168             "Failed(%d) to get I/O addresses:.\n", ret, device->handle);
    169         usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n",
    170             io_reg_base, io_reg_size, irq);
    171 
    172         ret = pci_disable_legacy(device);
    173         CHECK_RET_DEST_FUN_RETURN(ret,
    174             "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret));
    175 
    176         bool interrupts = false;
    177         ret = pci_enable_interrupts(device);
    178         if (ret != EOK) {
    179                 usb_log_warning(
    180                     "Failed(%d) to enable interrupts, fall back to polling.\n",
    181                     ret);
    182         } else {
    183                 usb_log_debug("Hw interrupts enabled.\n");
    184                 interrupts = true;
    185         }
    186 
    187         instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci-hc");
    188         ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
    189         CHECK_RET_DEST_FUN_RETURN(ret,
    190             "Failed(%d) to create HC function.\n", ret);
    191 
    192         ret = uhci_hc_init(&instance->hc, instance->hc_fun,
    193             (void*)io_reg_base, io_reg_size, interrupts);
    194         CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret);
    195         instance->hc_fun->ops = &uhci_hc_ops;
    196         instance->hc_fun->driver_data = &instance->hc;
    197         ret = ddf_fun_bind(instance->hc_fun);
     136            "Failed to create UHCI device function.\n");
     137
     138        instance->ddf_instance->ops = &uhci_ops;
     139        instance->ddf_instance->driver_data = instance;
     140
     141        ret = ddf_fun_bind(instance->ddf_instance);
    198142        CHECK_RET_DEST_FUN_RETURN(ret,
    199143            "Failed(%d) to bind UHCI device function: %s.\n",
    200144            ret, str_error(ret));
    201 #undef CHECK_RET_HC_RETURN
    202 
    203 #define CHECK_RET_FINI_RETURN(ret, message...) \
    204 if (ret != EOK) { \
    205         usb_log_error(message); \
    206         if (instance->hc_fun) \
    207                 ddf_fun_destroy(instance->hc_fun); \
    208         if (instance->rh_fun) \
    209                 ddf_fun_destroy(instance->rh_fun); \
    210         uhci_hc_fini(&instance->hc); \
    211         return ret; \
    212 }
    213 
    214         /* It does no harm if we register this on polling */
    215         ret = register_interrupt_handler(device, irq, irq_handler,
    216             &instance->hc.interrupt_code);
    217         CHECK_RET_FINI_RETURN(ret,
    218             "Failed(%d) to register interrupt handler.\n", ret);
    219 
    220         instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh");
    221         ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
    222         CHECK_RET_FINI_RETURN(ret,
    223             "Failed(%d) to create root hub function.\n", ret);
    224 
    225         ret = uhci_rh_init(&instance->rh, instance->rh_fun,
    226             (uintptr_t)instance->hc.registers + 0x10, 4);
    227         CHECK_RET_FINI_RETURN(ret,
    228             "Failed(%d) to setup UHCI root hub.\n", ret);
    229 
    230         instance->rh_fun->ops = &uhci_rh_ops;
    231         instance->rh_fun->driver_data = &instance->rh;
    232         ret = ddf_fun_bind(instance->rh_fun);
    233         CHECK_RET_FINI_RETURN(ret,
    234             "Failed(%d) to register UHCI root hub.\n", ret);
    235 
    236         return EOK;
    237 #undef CHECK_RET_FINI_RETURN
     145
     146        /* allow access to hc control registers */
     147        regs_t *io;
     148        ret = pio_enable(regs, reg_size, (void**)&io);
     149        CHECK_RET_DEST_FUN_RETURN(ret,
     150            "Failed(%d) to gain access to registers at %p: %s.\n",
     151            ret, str_error(ret), io);
     152        instance->registers = io;
     153        usb_log_debug("Device registers at %p(%u) accessible.\n",
     154            io, reg_size);
     155
     156        ret = uhci_init_mem_structures(instance);
     157        CHECK_RET_DEST_FUN_RETURN(ret,
     158            "Failed to initialize UHCI memory structures.\n");
     159
     160        uhci_init_hw(instance);
     161        instance->cleaner =
     162            fibril_create(uhci_interrupt_emulator, instance);
     163        fibril_add_ready(instance->cleaner);
     164
     165        instance->debug_checker = fibril_create(uhci_debug_checker, instance);
     166        fibril_add_ready(instance->debug_checker);
     167
     168        usb_log_info("Started UHCI driver.\n");
     169        return EOK;
     170#undef CHECK_RET_DEST_FUN_RETURN
     171}
     172/*----------------------------------------------------------------------------*/
     173/** Initializes UHCI hcd hw resources.
     174 *
     175 * @param[in] instance UHCI structure to use.
     176 */
     177void uhci_init_hw(uhci_t *instance)
     178{
     179        assert(instance);
     180        regs_t *registers = instance->registers;
     181
     182        /* Reset everything, who knows what touched it before us */
     183        pio_write_16(&registers->usbcmd, UHCI_CMD_GLOBAL_RESET);
     184        async_usleep(10000); /* 10ms according to USB spec */
     185        pio_write_16(&registers->usbcmd, 0);
     186
     187        /* Reset hc, all states and counters */
     188        pio_write_16(&registers->usbcmd, UHCI_CMD_HCRESET);
     189        do { async_usleep(10); }
     190        while ((pio_read_16(&registers->usbcmd) & UHCI_CMD_HCRESET) != 0);
     191
     192        /* Set framelist pointer */
     193        const uint32_t pa = addr_to_phys(instance->frame_list);
     194        pio_write_32(&registers->flbaseadd, pa);
     195
     196        /* Enable all interrupts, but resume interrupt */
     197//      pio_write_16(&instance->registers->usbintr,
     198//          UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET);
     199
     200        uint16_t status = pio_read_16(&registers->usbcmd);
     201        if (status != 0)
     202                usb_log_warning("Previous command value: %x.\n", status);
     203
     204        /* Start the hc with large(64B) packet FSBR */
     205        pio_write_16(&registers->usbcmd,
     206            UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET | UHCI_CMD_CONFIGURE);
     207}
     208/*----------------------------------------------------------------------------*/
     209/** Initializes UHCI hcd memory structures.
     210 *
     211 * @param[in] instance UHCI structure to use.
     212 * @return Error code
     213 * @note Should be called only once on any structure.
     214 */
     215int uhci_init_mem_structures(uhci_t *instance)
     216{
     217        assert(instance);
     218#define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \
     219        if (ret != EOK) { \
     220                usb_log_error(message); \
     221                if (instance->interrupt_code.cmds != NULL) \
     222                        free(instance->interrupt_code.cmds); \
     223                return ret; \
     224        } else (void) 0
     225
     226        /* Init interrupt code */
     227        instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds));
     228        int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK;
     229        CHECK_RET_DEST_CMDS_RETURN(ret,
     230            "Failed to allocate interrupt cmds space.\n");
     231
     232        {
     233                irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds;
     234                memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds));
     235                interrupt_commands[0].addr =
     236                    (void*)&instance->registers->usbsts;
     237                interrupt_commands[1].addr =
     238                    (void*)&instance->registers->usbsts;
     239                instance->interrupt_code.cmdcount =
     240                    sizeof(uhci_cmds) / sizeof(irq_cmd_t);
     241        }
     242
     243        /* Init transfer lists */
     244        ret = uhci_init_transfer_lists(instance);
     245        CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to init transfer lists.\n");
     246        usb_log_debug("Initialized transfer lists.\n");
     247
     248        /* Init USB frame list page*/
     249        instance->frame_list = get_page();
     250        ret = instance ? EOK : ENOMEM;
     251        CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n");
     252        usb_log_debug("Initialized frame list.\n");
     253
     254        /* Set all frames to point to the first queue head */
     255        const uint32_t queue =
     256          instance->transfers_interrupt.queue_head_pa
     257          | LINK_POINTER_QUEUE_HEAD_FLAG;
     258
     259        unsigned i = 0;
     260        for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
     261                instance->frame_list[i] = queue;
     262        }
     263
     264        /* Init device keeper*/
     265        device_keeper_init(&instance->device_manager);
     266        usb_log_debug("Initialized device manager.\n");
     267
     268        return EOK;
     269#undef CHECK_RET_DEST_CMDS_RETURN
     270}
     271/*----------------------------------------------------------------------------*/
     272/** Initializes UHCI hcd transfer lists.
     273 *
     274 * @param[in] instance UHCI structure to use.
     275 * @return Error code
     276 * @note Should be called only once on any structure.
     277 */
     278int uhci_init_transfer_lists(uhci_t *instance)
     279{
     280        assert(instance);
     281#define CHECK_RET_CLEAR_RETURN(ret, message...) \
     282        if (ret != EOK) { \
     283                usb_log_error(message); \
     284                transfer_list_fini(&instance->transfers_bulk_full); \
     285                transfer_list_fini(&instance->transfers_control_full); \
     286                transfer_list_fini(&instance->transfers_control_slow); \
     287                transfer_list_fini(&instance->transfers_interrupt); \
     288                return ret; \
     289        } else (void) 0
     290
     291        /* initialize TODO: check errors */
     292        int ret;
     293        ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL");
     294        CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list.");
     295
     296        ret = transfer_list_init(
     297            &instance->transfers_control_full, "CONTROL_FULL");
     298        CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list.");
     299
     300        ret = transfer_list_init(
     301            &instance->transfers_control_slow, "CONTROL_SLOW");
     302        CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list.");
     303
     304        ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT");
     305        CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list.");
     306
     307        transfer_list_set_next(&instance->transfers_control_full,
     308                &instance->transfers_bulk_full);
     309        transfer_list_set_next(&instance->transfers_control_slow,
     310                &instance->transfers_control_full);
     311        transfer_list_set_next(&instance->transfers_interrupt,
     312                &instance->transfers_control_slow);
     313
     314        /*FSBR*/
     315#ifdef FSBR
     316        transfer_list_set_next(&instance->transfers_bulk_full,
     317                &instance->transfers_control_full);
     318#endif
     319
     320        /* Assign pointers to be used during scheduling */
     321        instance->transfers[USB_SPEED_FULL][USB_TRANSFER_INTERRUPT] =
     322          &instance->transfers_interrupt;
     323        instance->transfers[USB_SPEED_LOW][USB_TRANSFER_INTERRUPT] =
     324          &instance->transfers_interrupt;
     325        instance->transfers[USB_SPEED_FULL][USB_TRANSFER_CONTROL] =
     326          &instance->transfers_control_full;
     327        instance->transfers[USB_SPEED_LOW][USB_TRANSFER_CONTROL] =
     328          &instance->transfers_control_slow;
     329        instance->transfers[USB_SPEED_FULL][USB_TRANSFER_BULK] =
     330          &instance->transfers_bulk_full;
     331
     332        return EOK;
     333#undef CHECK_RET_CLEAR_RETURN
     334}
     335/*----------------------------------------------------------------------------*/
     336/** Schedules batch for execution.
     337 *
     338 * @param[in] instance UHCI structure to use.
     339 * @param[in] batch Transfer batch to schedule.
     340 * @return Error code
     341 */
     342int uhci_schedule(uhci_t *instance, batch_t *batch)
     343{
     344        assert(instance);
     345        assert(batch);
     346        const int low_speed = (batch->speed == USB_SPEED_LOW);
     347        if (!allowed_usb_packet(
     348            low_speed, batch->transfer_type, batch->max_packet_size)) {
     349                usb_log_warning(
     350                    "Invalid USB packet specified %s SPEED %d %zu.\n",
     351                    low_speed ? "LOW" : "FULL" , batch->transfer_type,
     352                    batch->max_packet_size);
     353                return ENOTSUP;
     354        }
     355        /* TODO: check available bandwith here */
     356
     357        transfer_list_t *list =
     358            instance->transfers[low_speed][batch->transfer_type];
     359        assert(list);
     360        transfer_list_add_batch(list, batch);
     361
     362        return EOK;
     363}
     364/*----------------------------------------------------------------------------*/
     365/** Takes action based on the interrupt cause.
     366 *
     367 * @param[in] instance UHCI structure to use.
     368 * @param[in] status Value of the stsatus regiser at the time of interrupt.
     369 */
     370void uhci_interrupt(uhci_t *instance, uint16_t status)
     371{
     372        assert(instance);
     373        /* TODO: Check interrupt cause here */
     374        transfer_list_remove_finished(&instance->transfers_interrupt);
     375        transfer_list_remove_finished(&instance->transfers_control_slow);
     376        transfer_list_remove_finished(&instance->transfers_control_full);
     377        transfer_list_remove_finished(&instance->transfers_bulk_full);
     378}
     379/*----------------------------------------------------------------------------*/
     380/** Polling function, emulates interrupts.
     381 *
     382 * @param[in] arg UHCI structure to use.
     383 * @return EOK
     384 */
     385int uhci_interrupt_emulator(void* arg)
     386{
     387        usb_log_debug("Started interrupt emulator.\n");
     388        uhci_t *instance = (uhci_t*)arg;
     389        assert(instance);
     390
     391        while (1) {
     392                uint16_t status = pio_read_16(&instance->registers->usbsts);
     393                if (status != 0)
     394                        usb_log_debug2("UHCI status: %x.\n", status);
     395                status |= 1;
     396                uhci_interrupt(instance, status);
     397                pio_write_16(&instance->registers->usbsts, 0x1f);
     398                async_usleep(UHCI_CLEANER_TIMEOUT);
     399        }
     400        return EOK;
     401}
     402/*---------------------------------------------------------------------------*/
     403/** Debug function, checks consistency of memory structures.
     404 *
     405 * @param[in] arg UHCI structure to use.
     406 * @return EOK
     407 */
     408int uhci_debug_checker(void *arg)
     409{
     410        uhci_t *instance = (uhci_t*)arg;
     411        assert(instance);
     412
     413#define QH(queue) \
     414        instance->transfers_##queue.queue_head
     415
     416        while (1) {
     417                const uint16_t cmd = pio_read_16(&instance->registers->usbcmd);
     418                const uint16_t sts = pio_read_16(&instance->registers->usbsts);
     419                const uint16_t intr =
     420                    pio_read_16(&instance->registers->usbintr);
     421
     422                if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
     423                        usb_log_debug2("Command: %X Status: %X Intr: %x\n",
     424                            cmd, sts, intr);
     425                }
     426
     427                uintptr_t frame_list =
     428                    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
     429                if (frame_list != addr_to_phys(instance->frame_list)) {
     430                        usb_log_debug("Framelist address: %p vs. %p.\n",
     431                            frame_list, addr_to_phys(instance->frame_list));
     432                }
     433
     434                int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff;
     435                usb_log_debug2("Framelist item: %d \n", frnum );
     436
     437                uintptr_t expected_pa = instance->frame_list[frnum] & (~0xf);
     438                uintptr_t real_pa = addr_to_phys(QH(interrupt));
     439                if (expected_pa != real_pa) {
     440                        usb_log_debug("Interrupt QH: %p vs. %p.\n",
     441                            expected_pa, real_pa);
     442                }
     443
     444                expected_pa = QH(interrupt)->next_queue & (~0xf);
     445                real_pa = addr_to_phys(QH(control_slow));
     446                if (expected_pa != real_pa) {
     447                        usb_log_debug("Control Slow QH: %p vs. %p.\n",
     448                            expected_pa, real_pa);
     449                }
     450
     451                expected_pa = QH(control_slow)->next_queue & (~0xf);
     452                real_pa = addr_to_phys(QH(control_full));
     453                if (expected_pa != real_pa) {
     454                        usb_log_debug("Control Full QH: %p vs. %p.\n",
     455                            expected_pa, real_pa);
     456                }
     457
     458                expected_pa = QH(control_full)->next_queue & (~0xf);
     459                real_pa = addr_to_phys(QH(bulk_full));
     460                if (expected_pa != real_pa ) {
     461                        usb_log_debug("Bulk QH: %p vs. %p.\n",
     462                            expected_pa, real_pa);
     463                }
     464                async_usleep(UHCI_DEBUGER_TIMEOUT);
     465        }
     466        return EOK;
     467#undef QH
     468}
     469/*----------------------------------------------------------------------------*/
     470/** Checks transfer packets, for USB validity
     471 *
     472 * @param[in] low_speed Transfer speed.
     473 * @param[in] transfer Transer type
     474 * @param[in] size Maximum size of used packets
     475 * @return EOK
     476 */
     477bool allowed_usb_packet(
     478    bool low_speed, usb_transfer_type_t transfer, size_t size)
     479{
     480        /* see USB specification chapter 5.5-5.8 for magic numbers used here */
     481        switch(transfer)
     482        {
     483        case USB_TRANSFER_ISOCHRONOUS:
     484                return (!low_speed && size < 1024);
     485        case USB_TRANSFER_INTERRUPT:
     486                return size <= (low_speed ? 8 : 64);
     487        case USB_TRANSFER_CONTROL: /* device specifies its own max size */
     488                return (size <= (low_speed ? 8 : 64));
     489        case USB_TRANSFER_BULK: /* device specifies its own max size */
     490                return (!low_speed && size <= 64);
     491        }
     492        return false;
    238493}
    239494/**
Note: See TracChangeset for help on using the changeset viewer.