Ignore:
File:
1 edited

Legend:

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

    r68e5406 rf3ae58b  
    5050#include <usb/usb.h>
    5151#include <usb/host/utils/malloc32.h>
     52#include <usb/host/bandwidth.h>
     53#include <usb/host/utility.h>
    5254
    5355#include "uhci_batch.h"
     56#include "transfer_list.h"
    5457#include "hc.h"
    5558
     
    103106 * @param[out] code IRQ code structure.
    104107 * @param[in] hw_res Device's resources.
    105  * @param[out] irq
    106108 *
    107109 * @return Error code.
    108110 */
    109 int uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     111int hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
    110112{
    111113        assert(code);
     
    140142        code->cmds[3].addr = (void*)&registers->usbsts;
    141143
    142         usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
     144        usb_log_debug("I/O regs at %p (size %zu), IRQ %d.",
    143145            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    144146
    145         *irq = hw_res->irqs.irqs[0];
    146         return EOK;
     147        return hw_res->irqs.irqs[0];
    147148}
    148149
     
    157158 * - resume from suspend state (not implemented)
    158159 */
    159 void 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);
     160static void hc_interrupt(bus_t *bus, uint32_t status)
     161{
     162        hc_t *instance = bus_to_hc(bus);
     163
    164164        /* Lower 2 bits are transaction error and transaction complete */
    165165        if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
    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         }
     166                transfer_list_check_finished(&instance->transfers_interrupt);
     167                transfer_list_check_finished(&instance->transfers_control_slow);
     168                transfer_list_check_finished(&instance->transfers_control_full);
     169                transfer_list_check_finished(&instance->transfers_bulk_full);
     170        }
     171
    183172        /* Resume interrupts are not supported */
    184173        if (status & UHCI_STATUS_RESUME) {
    185                 usb_log_error("Resume interrupt!\n");
     174                usb_log_error("Resume interrupt!");
    186175        }
    187176
    188177        /* Bits 4 and 5 indicate hc error */
    189178        if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
    190                 usb_log_error("UHCI hardware failure!.\n");
     179                usb_log_error("UHCI hardware failure!.");
    191180                ++instance->hw_failures;
    192181                transfer_list_abort_all(&instance->transfers_interrupt);
     
    199188                        hc_init_hw(instance);
    200189                } else {
    201                         usb_log_fatal("Too many UHCI hardware failures!.\n");
    202                         hc_fini(instance);
     190                        usb_log_fatal("Too many UHCI hardware failures!.");
     191                        hc_gone(&instance->base);
    203192                }
    204193        }
     
    216205 * interrupt fibrils.
    217206 */
    218 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    219 {
    220         assert(instance);
     207int hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
     208{
     209        hc_t *instance = hcd_to_hc(hcd);
    221210        assert(hw_res);
    222211        if (hw_res->io_ranges.count != 1 ||
     
    224213            return EINVAL;
    225214
    226         instance->hw_interrupts = interrupts;
    227215        instance->hw_failures = 0;
    228216
     
    231219            (void **) &instance->registers);
    232220        if (ret != EOK) {
    233                 usb_log_error("Failed to gain access to registers: %s.\n",
     221                usb_log_error("Failed to gain access to registers: %s.",
    234222                    str_error(ret));
    235223                return ret;
    236224        }
    237225
    238         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     226        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
    239227            hw_res->io_ranges.ranges[0].address.absolute,
    240228            hw_res->io_ranges.ranges[0].size);
     
    242230        ret = hc_init_mem_structures(instance);
    243231        if (ret != EOK) {
    244                 usb_log_error("Failed to init UHCI memory structures: %s.\n",
     232                usb_log_error("Failed to init UHCI memory structures: %s.",
    245233                    str_error(ret));
    246234                // TODO: we should disable pio here
     
    248236        }
    249237
     238        return EOK;
     239}
     240
     241int hc_start(hc_device_t *hcd)
     242{
     243        hc_t *instance = hcd_to_hc(hcd);
    250244        hc_init_hw(instance);
    251245        (void)hc_debug_checker;
    252246
    253         uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
    254 
    255         return EOK;
     247        return uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
     248}
     249
     250int hc_setup_roothub(hc_device_t *hcd)
     251{
     252        return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
    256253}
    257254
     
    260257 * @param[in] instance Host controller structure to use.
    261258 */
    262 void hc_fini(hc_t *instance)
     259int hc_gone(hc_device_t *instance)
    263260{
    264261        assert(instance);
    265262        //TODO Implement
     263        return ENOTSUP;
    266264}
    267265
     
    293291        pio_write_32(&registers->flbaseadd, pa);
    294292
    295         if (instance->hw_interrupts) {
     293        if (instance->base.irq_cap >= 0) {
    296294                /* Enable all interrupts, but resume interrupt */
    297295                pio_write_16(&instance->registers->usbintr,
     
    301299        const uint16_t cmd = pio_read_16(&registers->usbcmd);
    302300        if (cmd != 0)
    303                 usb_log_warning("Previous command value: %x.\n", cmd);
     301                usb_log_warning("Previous command value: %x.", cmd);
    304302
    305303        /* Start the hc with large(64B) packet FSBR */
     
    308306}
    309307
     308static usb_transfer_batch_t *create_transfer_batch(endpoint_t *ep)
     309{
     310        uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep);
     311        return &batch->base;
     312}
     313
     314static void destroy_transfer_batch(usb_transfer_batch_t *batch)
     315{
     316        uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch));
     317}
     318
     319static endpoint_t *endpoint_create(device_t *device, const usb_endpoint_descriptors_t *desc)
     320{
     321        endpoint_t *ep = calloc(1, sizeof(uhci_endpoint_t));
     322        if (ep)
     323                endpoint_init(ep, device, desc);
     324        return ep;
     325}
     326
     327static int endpoint_register(endpoint_t *ep)
     328{
     329        hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
     330
     331        const int err = usb2_bus_endpoint_register(&hc->bus_helper, ep);
     332        if (err)
     333                return err;
     334
     335        transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];
     336        if (!list)
     337                /*
     338                 * We don't support this combination (e.g. isochronous). Do not
     339                 * fail early, because that would block any device with these
     340                 * endpoints from connecting. Instead, make sure these transfers
     341                 * are denied soon enough with ENOTSUP not to fail on asserts.
     342                 */
     343                return EOK;
     344
     345        endpoint_set_online(ep, &list->guard);
     346        return EOK;
     347}
     348
     349static void endpoint_unregister(endpoint_t *ep)
     350{
     351        hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
     352        usb2_bus_endpoint_unregister(&hc->bus_helper, ep);
     353
     354        // Check for the roothub, as it does not schedule into lists
     355        if (ep->device->address == uhci_rh_get_address(&hc->rh)) {
     356                // FIXME: We shall check the roothub for active transfer. But
     357                // as it is polling, there is no way to make it stop doing so.
     358                // Return after rewriting uhci rh.
     359                return;
     360        }
     361
     362        transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];
     363        if (!list)
     364                /*
     365                 * We don't support this combination (e.g. isochronous),
     366                 * so no transfer can be active.
     367                 */
     368                return;
     369
     370        fibril_mutex_lock(&list->guard);
     371
     372        endpoint_set_offline_locked(ep);
     373        /* From now on, no other transfer will be scheduled. */
     374
     375        if (!ep->active_batch) {
     376                fibril_mutex_unlock(&list->guard);
     377                return;
     378        }
     379
     380        /* First, offer the batch a short chance to be finished. */
     381        endpoint_wait_timeout_locked(ep, 10000);
     382
     383        if (!ep->active_batch) {
     384                fibril_mutex_unlock(&list->guard);
     385                return;
     386        }
     387
     388        uhci_transfer_batch_t * const batch =
     389                uhci_transfer_batch_get(ep->active_batch);
     390
     391        /* Remove the batch from the schedule to stop it from being finished. */
     392        endpoint_deactivate_locked(ep);
     393        transfer_list_remove_batch(list, batch);
     394
     395        fibril_mutex_unlock(&list->guard);
     396
     397        /*
     398         * We removed the batch from software schedule only, it's still possible
     399         * that HC has it in its caches. Better wait a while before we release
     400         * the buffers.
     401         */
     402        async_usleep(20000);
     403        batch->base.error = EINTR;
     404        batch->base.transferred_size = 0;
     405        usb_transfer_batch_finish(&batch->base);
     406}
     407
     408static int device_enumerate(device_t *dev)
     409{
     410        hc_t * const hc = bus_to_hc(dev->bus);
     411        return usb2_bus_device_enumerate(&hc->bus_helper, dev);
     412}
     413
     414static void device_gone(device_t *dev)
     415{
     416        hc_t * const hc = bus_to_hc(dev->bus);
     417        usb2_bus_device_gone(&hc->bus_helper, dev);
     418}
     419
     420static int hc_status(bus_t *, uint32_t *);
     421static int hc_schedule(usb_transfer_batch_t *);
     422
     423static const bus_ops_t uhci_bus_ops = {
     424        .interrupt = hc_interrupt,
     425        .status = hc_status,
     426
     427        .device_enumerate = device_enumerate,
     428        .device_gone = device_gone,
     429
     430        .endpoint_create = endpoint_create,
     431        .endpoint_register = endpoint_register,
     432        .endpoint_unregister = endpoint_unregister,
     433
     434        .batch_create = create_transfer_batch,
     435        .batch_schedule = hc_schedule,
     436        .batch_destroy = destroy_transfer_batch,
     437};
     438
    310439/** Initialize UHCI hc memory structures.
    311440 *
     
    321450{
    322451        assert(instance);
     452
     453        usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11);
     454
     455        bus_init(&instance->bus, sizeof(device_t));
     456        instance->bus.ops = &uhci_bus_ops;
     457
     458        hc_device_setup(&instance->base, &instance->bus);
    323459
    324460        /* Init USB frame list page */
     
    327463                return ENOMEM;
    328464        }
    329         usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
     465        usb_log_debug("Initialized frame list at %p.", instance->frame_list);
    330466
    331467        /* Init transfer lists */
    332468        int ret = hc_init_transfer_lists(instance);
    333469        if (ret != EOK) {
    334                 usb_log_error("Failed to initialize transfer lists.\n");
     470                usb_log_error("Failed to initialize transfer lists.");
    335471                return_page(instance->frame_list);
    336472                return ENOMEM;
    337473        }
    338         usb_log_debug("Initialized transfer lists.\n");
     474        list_initialize(&instance->pending_endpoints);
     475        usb_log_debug("Initialized transfer lists.");
    339476
    340477
     
    366503        int ret = transfer_list_init(&instance->transfers_##type, name); \
    367504        if (ret != EOK) { \
    368                 usb_log_error("Failed to setup %s transfer list: %s.\n", \
     505                usb_log_error("Failed to setup %s transfer list: %s.", \
    369506                    name, str_error(ret)); \
    370507                transfer_list_fini(&instance->transfers_bulk_full); \
     
    411548}
    412549
    413 int uhci_hc_status(hcd_t *hcd, uint32_t *status)
    414 {
    415         assert(hcd);
     550static int hc_status(bus_t *bus, uint32_t *status)
     551{
     552        hc_t *instance = bus_to_hc(bus);
    416553        assert(status);
    417         hc_t *instance = hcd_get_driver_data(hcd);
    418         assert(instance);
    419554
    420555        *status = 0;
     
    427562}
    428563
    429 /** Schedule batch for execution.
     564/**
     565 * Schedule batch for execution.
    430566 *
    431567 * @param[in] instance UHCI structure to use.
    432568 * @param[in] batch Transfer batch to schedule.
    433569 * @return Error code
    434  *
    435  * Checks for bandwidth availability and appends the batch to the proper queue.
    436  */
    437 int 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 
     570 */
     571static int hc_schedule(usb_transfer_batch_t *batch)
     572{
    447573        uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(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;
     574        endpoint_t *ep = batch->ep;
     575        hc_t *hc = bus_to_hc(endpoint_get_bus(ep));
     576
     577        if (batch->target.address == uhci_rh_get_address(&hc->rh))
     578                return uhci_rh_schedule(&hc->rh, batch);
     579
     580        transfer_list_t * const list =
     581            hc->transfers[ep->device->speed][ep->transfer_type];
     582
     583        if (!list)
     584                return ENOTSUP;
     585
     586        int err;
     587        if ((err = uhci_transfer_batch_prepare(uhci_batch)))
     588                return err;
     589
     590        return transfer_list_add_batch(list, uhci_batch);
    459591}
    460592
     
    479611
    480612                if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
    481                         usb_log_debug2("Command: %X Status: %X Intr: %x\n",
     613                        usb_log_debug2("Command: %X Status: %X Intr: %x",
    482614                            cmd, sts, intr);
    483615                }
     
    486618                    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
    487619                if (frame_list != addr_to_phys(instance->frame_list)) {
    488                         usb_log_debug("Framelist address: %p vs. %p.\n",
     620                        usb_log_debug("Framelist address: %p vs. %p.",
    489621                            (void *) frame_list,
    490622                            (void *) addr_to_phys(instance->frame_list));
     
    497629                uintptr_t real_pa = addr_to_phys(QH(interrupt));
    498630                if (expected_pa != real_pa) {
    499                         usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.\n",
     631                        usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.",
    500632                            (void *) expected_pa, frnum, (void *) real_pa);
    501633                }
     
    504636                real_pa = addr_to_phys(QH(control_slow));
    505637                if (expected_pa != real_pa) {
    506                         usb_log_debug("Control Slow QH: %p vs. %p.\n",
     638                        usb_log_debug("Control Slow QH: %p vs. %p.",
    507639                            (void *) expected_pa, (void *) real_pa);
    508640                }
     
    511643                real_pa = addr_to_phys(QH(control_full));
    512644                if (expected_pa != real_pa) {
    513                         usb_log_debug("Control Full QH: %p vs. %p.\n",
     645                        usb_log_debug("Control Full QH: %p vs. %p.",
    514646                            (void *) expected_pa, (void *) real_pa);
    515647                }
     
    518650                real_pa = addr_to_phys(QH(bulk_full));
    519651                if (expected_pa != real_pa ) {
    520                         usb_log_debug("Bulk QH: %p vs. %p.\n",
     652                        usb_log_debug("Bulk QH: %p vs. %p.",
    521653                            (void *) expected_pa, (void *) real_pa);
    522654                }
Note: See TracChangeset for help on using the changeset viewer.