Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/uhci/hc.c

    r5a6cc679 rb7fd2a0  
    5050#include <usb/usb.h>
    5151#include <usb/host/utils/malloc32.h>
    52 #include <usb/host/bandwidth.h>
    53 #include <usb/host/utility.h>
    5452
    5553#include "uhci_batch.h"
    56 #include "transfer_list.h"
    5754#include "hc.h"
    5855
     
    110107 * @return Error code.
    111108 */
    112 errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
     109errno_t uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
    113110{
    114111        assert(code);
     
    143140        code->cmds[3].addr = (void*)&registers->usbsts;
    144141
    145         usb_log_debug("I/O regs at %p (size %zu), IRQ %d.",
     142        usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
    146143            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    147144
     
    160157 * - resume from suspend state (not implemented)
    161158 */
    162 static void hc_interrupt(bus_t *bus, uint32_t status)
    163 {
    164         hc_t *instance = bus_to_hc(bus);
    165 
     159void uhci_hc_interrupt(hcd_t *hcd, uint32_t status)
     160{
     161        assert(hcd);
     162        hc_t *instance = hcd_get_driver_data(hcd);
     163        assert(instance);
    166164        /* Lower 2 bits are transaction error and transaction complete */
    167165        if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
    168                 transfer_list_check_finished(&instance->transfers_interrupt);
    169                 transfer_list_check_finished(&instance->transfers_control_slow);
    170                 transfer_list_check_finished(&instance->transfers_control_full);
    171                 transfer_list_check_finished(&instance->transfers_bulk_full);
    172         }
    173 
     166                LIST_INITIALIZE(done);
     167                transfer_list_remove_finished(
     168                    &instance->transfers_interrupt, &done);
     169                transfer_list_remove_finished(
     170                    &instance->transfers_control_slow, &done);
     171                transfer_list_remove_finished(
     172                    &instance->transfers_control_full, &done);
     173                transfer_list_remove_finished(
     174                    &instance->transfers_bulk_full, &done);
     175
     176                list_foreach_safe(done, current, next) {
     177                        list_remove(current);
     178                        uhci_transfer_batch_t *batch =
     179                            uhci_transfer_batch_from_link(current);
     180                        uhci_transfer_batch_finish_dispose(batch);
     181                }
     182        }
    174183        /* Resume interrupts are not supported */
    175184        if (status & UHCI_STATUS_RESUME) {
    176                 usb_log_error("Resume interrupt!");
     185                usb_log_error("Resume interrupt!\n");
    177186        }
    178187
    179188        /* Bits 4 and 5 indicate hc error */
    180189        if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
    181                 usb_log_error("UHCI hardware failure!.");
     190                usb_log_error("UHCI hardware failure!.\n");
    182191                ++instance->hw_failures;
    183192                transfer_list_abort_all(&instance->transfers_interrupt);
     
    190199                        hc_init_hw(instance);
    191200                } else {
    192                         usb_log_fatal("Too many UHCI hardware failures!.");
    193                         hc_gone(&instance->base);
     201                        usb_log_fatal("Too many UHCI hardware failures!.\n");
     202                        hc_fini(instance);
    194203                }
    195204        }
     
    207216 * interrupt fibrils.
    208217 */
    209 errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
    210 {
    211         hc_t *instance = hcd_to_hc(hcd);
     218errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
     219{
     220        assert(instance);
    212221        assert(hw_res);
    213222        if (hw_res->io_ranges.count != 1 ||
     
    215224            return EINVAL;
    216225
     226        instance->hw_interrupts = interrupts;
    217227        instance->hw_failures = 0;
    218228
     
    221231            (void **) &instance->registers);
    222232        if (ret != EOK) {
    223                 usb_log_error("Failed to gain access to registers: %s.",
     233                usb_log_error("Failed to gain access to registers: %s.\n",
    224234                    str_error(ret));
    225235                return ret;
    226236        }
    227237
    228         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
     238        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
    229239            hw_res->io_ranges.ranges[0].address.absolute,
    230240            hw_res->io_ranges.ranges[0].size);
     
    232242        ret = hc_init_mem_structures(instance);
    233243        if (ret != EOK) {
    234                 usb_log_error("Failed to init UHCI memory structures: %s.",
     244                usb_log_error("Failed to init UHCI memory structures: %s.\n",
    235245                    str_error(ret));
    236246                // TODO: we should disable pio here
     
    238248        }
    239249
    240         return EOK;
    241 }
    242 
    243 int hc_start(hc_device_t *hcd)
    244 {
    245         hc_t *instance = hcd_to_hc(hcd);
    246250        hc_init_hw(instance);
    247251        (void)hc_debug_checker;
    248252
    249         return uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
    250 }
    251 
    252 int hc_setup_roothub(hc_device_t *hcd)
    253 {
    254         return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
     253        uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
     254
     255        return EOK;
    255256}
    256257
     
    259260 * @param[in] instance Host controller structure to use.
    260261 */
    261 int hc_gone(hc_device_t *instance)
     262void hc_fini(hc_t *instance)
    262263{
    263264        assert(instance);
    264265        //TODO Implement
    265         return ENOTSUP;
    266266}
    267267
     
    293293        pio_write_32(&registers->flbaseadd, pa);
    294294
    295         if (instance->base.irq_cap >= 0) {
     295        if (instance->hw_interrupts) {
    296296                /* Enable all interrupts, but resume interrupt */
    297297                pio_write_16(&instance->registers->usbintr,
     
    301301        const uint16_t cmd = pio_read_16(&registers->usbcmd);
    302302        if (cmd != 0)
    303                 usb_log_warning("Previous command value: %x.", cmd);
     303                usb_log_warning("Previous command value: %x.\n", cmd);
    304304
    305305        /* Start the hc with large(64B) packet FSBR */
     
    308308}
    309309
    310 static usb_transfer_batch_t *create_transfer_batch(endpoint_t *ep)
    311 {
    312         uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep);
    313         return &batch->base;
    314 }
    315 
    316 static void destroy_transfer_batch(usb_transfer_batch_t *batch)
    317 {
    318         uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch));
    319 }
    320 
    321 static endpoint_t *endpoint_create(device_t *device, const usb_endpoint_descriptors_t *desc)
    322 {
    323         endpoint_t *ep = calloc(1, sizeof(uhci_endpoint_t));
    324         if (ep)
    325                 endpoint_init(ep, device, desc);
    326         return ep;
    327 }
    328 
    329 static errno_t endpoint_register(endpoint_t *ep)
    330 {
    331         hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
    332 
    333         const errno_t err = usb2_bus_endpoint_register(&hc->bus_helper, ep);
    334         if (err)
    335                 return err;
    336 
    337         transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];
    338         if (!list)
    339                 /*
    340                  * We don't support this combination (e.g. isochronous). Do not
    341                  * fail early, because that would block any device with these
    342                  * endpoints from connecting. Instead, make sure these transfers
    343                  * are denied soon enough with ENOTSUP not to fail on asserts.
    344                  */
    345                 return EOK;
    346 
    347         endpoint_set_online(ep, &list->guard);
    348         return EOK;
    349 }
    350 
    351 static void endpoint_unregister(endpoint_t *ep)
    352 {
    353         hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
    354         usb2_bus_endpoint_unregister(&hc->bus_helper, ep);
    355 
    356         // Check for the roothub, as it does not schedule into lists
    357         if (ep->device->address == uhci_rh_get_address(&hc->rh)) {
    358                 // FIXME: We shall check the roothub for active transfer. But
    359                 // as it is polling, there is no way to make it stop doing so.
    360                 // Return after rewriting uhci rh.
    361                 return;
    362         }
    363 
    364         transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];
    365         if (!list)
    366                 /*
    367                  * We don't support this combination (e.g. isochronous),
    368                  * so no transfer can be active.
    369                  */
    370                 return;
    371 
    372         fibril_mutex_lock(&list->guard);
    373 
    374         endpoint_set_offline_locked(ep);
    375         /* From now on, no other transfer will be scheduled. */
    376 
    377         if (!ep->active_batch) {
    378                 fibril_mutex_unlock(&list->guard);
    379                 return;
    380         }
    381 
    382         /* First, offer the batch a short chance to be finished. */
    383         endpoint_wait_timeout_locked(ep, 10000);
    384 
    385         if (!ep->active_batch) {
    386                 fibril_mutex_unlock(&list->guard);
    387                 return;
    388         }
    389 
    390         uhci_transfer_batch_t * const batch =
    391                 uhci_transfer_batch_get(ep->active_batch);
    392 
    393         /* Remove the batch from the schedule to stop it from being finished. */
    394         endpoint_deactivate_locked(ep);
    395         transfer_list_remove_batch(list, batch);
    396 
    397         fibril_mutex_unlock(&list->guard);
    398 
    399         /*
    400          * We removed the batch from software schedule only, it's still possible
    401          * that HC has it in its caches. Better wait a while before we release
    402          * the buffers.
    403          */
    404         async_usleep(20000);
    405         batch->base.error = EINTR;
    406         batch->base.transferred_size = 0;
    407         usb_transfer_batch_finish(&batch->base);
    408 }
    409 
    410 static int device_enumerate(device_t *dev)
    411 {
    412         hc_t * const hc = bus_to_hc(dev->bus);
    413         return usb2_bus_device_enumerate(&hc->bus_helper, dev);
    414 }
    415 
    416 static void device_gone(device_t *dev)
    417 {
    418         hc_t * const hc = bus_to_hc(dev->bus);
    419         usb2_bus_device_gone(&hc->bus_helper, dev);
    420 }
    421 
    422 static int hc_status(bus_t *, uint32_t *);
    423 static int hc_schedule(usb_transfer_batch_t *);
    424 
    425 static const bus_ops_t uhci_bus_ops = {
    426         .interrupt = hc_interrupt,
    427         .status = hc_status,
    428 
    429         .device_enumerate = device_enumerate,
    430         .device_gone = device_gone,
    431 
    432         .endpoint_create = endpoint_create,
    433         .endpoint_register = endpoint_register,
    434         .endpoint_unregister = endpoint_unregister,
    435 
    436         .batch_create = create_transfer_batch,
    437         .batch_schedule = hc_schedule,
    438         .batch_destroy = destroy_transfer_batch,
    439 };
    440 
    441310/** Initialize UHCI hc memory structures.
    442311 *
     
    452321{
    453322        assert(instance);
    454 
    455         usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11);
    456 
    457         bus_init(&instance->bus, sizeof(device_t));
    458         instance->bus.ops = &uhci_bus_ops;
    459 
    460         hc_device_setup(&instance->base, &instance->bus);
    461323
    462324        /* Init USB frame list page */
     
    465327                return ENOMEM;
    466328        }
    467         usb_log_debug("Initialized frame list at %p.", instance->frame_list);
     329        usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
    468330
    469331        /* Init transfer lists */
    470332        errno_t ret = hc_init_transfer_lists(instance);
    471333        if (ret != EOK) {
    472                 usb_log_error("Failed to initialize transfer lists.");
     334                usb_log_error("Failed to initialize transfer lists.\n");
    473335                return_page(instance->frame_list);
    474336                return ENOMEM;
    475337        }
    476         list_initialize(&instance->pending_endpoints);
    477         usb_log_debug("Initialized transfer lists.");
     338        usb_log_debug("Initialized transfer lists.\n");
    478339
    479340
     
    505366        errno_t ret = transfer_list_init(&instance->transfers_##type, name); \
    506367        if (ret != EOK) { \
    507                 usb_log_error("Failed to setup %s transfer list: %s.", \
     368                usb_log_error("Failed to setup %s transfer list: %s.\n", \
    508369                    name, str_error(ret)); \
    509370                transfer_list_fini(&instance->transfers_bulk_full); \
     
    550411}
    551412
    552 static errno_t hc_status(bus_t *bus, uint32_t *status)
    553 {
    554         hc_t *instance = bus_to_hc(bus);
     413errno_t uhci_hc_status(hcd_t *hcd, uint32_t *status)
     414{
     415        assert(hcd);
    555416        assert(status);
     417        hc_t *instance = hcd_get_driver_data(hcd);
     418        assert(instance);
    556419
    557420        *status = 0;
     
    564427}
    565428
    566 /**
    567  * Schedule batch for execution.
     429/** Schedule batch for execution.
    568430 *
    569431 * @param[in] instance UHCI structure to use.
    570432 * @param[in] batch Transfer batch to schedule.
    571433 * @return Error code
    572  */
    573 static errno_t hc_schedule(usb_transfer_batch_t *batch)
    574 {
     434 *
     435 * Checks for bandwidth availability and appends the batch to the proper queue.
     436 */
     437errno_t uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     438{
     439        assert(hcd);
     440        hc_t *instance = hcd_get_driver_data(hcd);
     441        assert(instance);
     442        assert(batch);
     443
     444        if (batch->ep->address == uhci_rh_get_address(&instance->rh))
     445                return uhci_rh_schedule(&instance->rh, batch);
     446
    575447        uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
    576         endpoint_t *ep = batch->ep;
    577         hc_t *hc = bus_to_hc(endpoint_get_bus(ep));
    578 
    579         if (batch->target.address == uhci_rh_get_address(&hc->rh))
    580                 return uhci_rh_schedule(&hc->rh, batch);
    581 
    582         transfer_list_t * const list =
    583             hc->transfers[ep->device->speed][ep->transfer_type];
    584 
    585         if (!list)
    586                 return ENOTSUP;
    587 
    588         errno_t err;
    589         if ((err = uhci_transfer_batch_prepare(uhci_batch)))
    590                 return err;
    591 
    592         return transfer_list_add_batch(list, uhci_batch);
     448        if (!uhci_batch) {
     449                usb_log_error("Failed to create UHCI transfer structures.\n");
     450                return ENOMEM;
     451        }
     452
     453        transfer_list_t *list =
     454            instance->transfers[batch->ep->speed][batch->ep->transfer_type];
     455        assert(list);
     456        transfer_list_add_batch(list, uhci_batch);
     457
     458        return EOK;
    593459}
    594460
     
    613479
    614480                if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
    615                         usb_log_debug2("Command: %X Status: %X Intr: %x",
     481                        usb_log_debug2("Command: %X Status: %X Intr: %x\n",
    616482                            cmd, sts, intr);
    617483                }
     
    620486                    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
    621487                if (frame_list != addr_to_phys(instance->frame_list)) {
    622                         usb_log_debug("Framelist address: %p vs. %p.",
     488                        usb_log_debug("Framelist address: %p vs. %p.\n",
    623489                            (void *) frame_list,
    624490                            (void *) addr_to_phys(instance->frame_list));
     
    631497                uintptr_t real_pa = addr_to_phys(QH(interrupt));
    632498                if (expected_pa != real_pa) {
    633                         usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.",
     499                        usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.\n",
    634500                            (void *) expected_pa, frnum, (void *) real_pa);
    635501                }
     
    638504                real_pa = addr_to_phys(QH(control_slow));
    639505                if (expected_pa != real_pa) {
    640                         usb_log_debug("Control Slow QH: %p vs. %p.",
     506                        usb_log_debug("Control Slow QH: %p vs. %p.\n",
    641507                            (void *) expected_pa, (void *) real_pa);
    642508                }
     
    645511                real_pa = addr_to_phys(QH(control_full));
    646512                if (expected_pa != real_pa) {
    647                         usb_log_debug("Control Full QH: %p vs. %p.",
     513                        usb_log_debug("Control Full QH: %p vs. %p.\n",
    648514                            (void *) expected_pa, (void *) real_pa);
    649515                }
     
    652518                real_pa = addr_to_phys(QH(bulk_full));
    653519                if (expected_pa != real_pa ) {
    654                         usb_log_debug("Bulk QH: %p vs. %p.",
     520                        usb_log_debug("Bulk QH: %p vs. %p.\n",
    655521                            (void *) expected_pa, (void *) real_pa);
    656522                }
Note: See TracChangeset for help on using the changeset viewer.