Ignore:
File:
1 edited

Legend:

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

    rb7fd2a0 r5a6cc679  
    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
     
    107110 * @return Error code.
    108111 */
    109 errno_t uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     112errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
    110113{
    111114        assert(code);
     
    140143        code->cmds[3].addr = (void*)&registers->usbsts;
    141144
    142         usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
     145        usb_log_debug("I/O regs at %p (size %zu), IRQ %d.",
    143146            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    144147
     
    157160 * - resume from suspend state (not implemented)
    158161 */
    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);
     162static void hc_interrupt(bus_t *bus, uint32_t status)
     163{
     164        hc_t *instance = bus_to_hc(bus);
     165
    164166        /* Lower 2 bits are transaction error and transaction complete */
    165167        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         }
     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
    183174        /* Resume interrupts are not supported */
    184175        if (status & UHCI_STATUS_RESUME) {
    185                 usb_log_error("Resume interrupt!\n");
     176                usb_log_error("Resume interrupt!");
    186177        }
    187178
    188179        /* Bits 4 and 5 indicate hc error */
    189180        if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
    190                 usb_log_error("UHCI hardware failure!.\n");
     181                usb_log_error("UHCI hardware failure!.");
    191182                ++instance->hw_failures;
    192183                transfer_list_abort_all(&instance->transfers_interrupt);
     
    199190                        hc_init_hw(instance);
    200191                } else {
    201                         usb_log_fatal("Too many UHCI hardware failures!.\n");
    202                         hc_fini(instance);
     192                        usb_log_fatal("Too many UHCI hardware failures!.");
     193                        hc_gone(&instance->base);
    203194                }
    204195        }
     
    216207 * interrupt fibrils.
    217208 */
    218 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    219 {
    220         assert(instance);
     209errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
     210{
     211        hc_t *instance = hcd_to_hc(hcd);
    221212        assert(hw_res);
    222213        if (hw_res->io_ranges.count != 1 ||
     
    224215            return EINVAL;
    225216
    226         instance->hw_interrupts = interrupts;
    227217        instance->hw_failures = 0;
    228218
     
    231221            (void **) &instance->registers);
    232222        if (ret != EOK) {
    233                 usb_log_error("Failed to gain access to registers: %s.\n",
     223                usb_log_error("Failed to gain access to registers: %s.",
    234224                    str_error(ret));
    235225                return ret;
    236226        }
    237227
    238         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     228        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
    239229            hw_res->io_ranges.ranges[0].address.absolute,
    240230            hw_res->io_ranges.ranges[0].size);
     
    242232        ret = hc_init_mem_structures(instance);
    243233        if (ret != EOK) {
    244                 usb_log_error("Failed to init UHCI memory structures: %s.\n",
     234                usb_log_error("Failed to init UHCI memory structures: %s.",
    245235                    str_error(ret));
    246236                // TODO: we should disable pio here
     
    248238        }
    249239
     240        return EOK;
     241}
     242
     243int hc_start(hc_device_t *hcd)
     244{
     245        hc_t *instance = hcd_to_hc(hcd);
    250246        hc_init_hw(instance);
    251247        (void)hc_debug_checker;
    252248
    253         uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
    254 
    255         return EOK;
     249        return uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
     250}
     251
     252int hc_setup_roothub(hc_device_t *hcd)
     253{
     254        return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
    256255}
    257256
     
    260259 * @param[in] instance Host controller structure to use.
    261260 */
    262 void hc_fini(hc_t *instance)
     261int hc_gone(hc_device_t *instance)
    263262{
    264263        assert(instance);
    265264        //TODO Implement
     265        return ENOTSUP;
    266266}
    267267
     
    293293        pio_write_32(&registers->flbaseadd, pa);
    294294
    295         if (instance->hw_interrupts) {
     295        if (instance->base.irq_cap >= 0) {
    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.\n", cmd);
     303                usb_log_warning("Previous command value: %x.", cmd);
    304304
    305305        /* Start the hc with large(64B) packet FSBR */
     
    308308}
    309309
     310static 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
     316static void destroy_transfer_batch(usb_transfer_batch_t *batch)
     317{
     318        uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch));
     319}
     320
     321static 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
     329static 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
     351static 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
     410static 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
     416static 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
     422static int hc_status(bus_t *, uint32_t *);
     423static int hc_schedule(usb_transfer_batch_t *);
     424
     425static 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
    310441/** Initialize UHCI hc memory structures.
    311442 *
     
    321452{
    322453        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);
    323461
    324462        /* Init USB frame list page */
     
    327465                return ENOMEM;
    328466        }
    329         usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
     467        usb_log_debug("Initialized frame list at %p.", instance->frame_list);
    330468
    331469        /* Init transfer lists */
    332470        errno_t ret = hc_init_transfer_lists(instance);
    333471        if (ret != EOK) {
    334                 usb_log_error("Failed to initialize transfer lists.\n");
     472                usb_log_error("Failed to initialize transfer lists.");
    335473                return_page(instance->frame_list);
    336474                return ENOMEM;
    337475        }
    338         usb_log_debug("Initialized transfer lists.\n");
     476        list_initialize(&instance->pending_endpoints);
     477        usb_log_debug("Initialized transfer lists.");
    339478
    340479
     
    366505        errno_t ret = transfer_list_init(&instance->transfers_##type, name); \
    367506        if (ret != EOK) { \
    368                 usb_log_error("Failed to setup %s transfer list: %s.\n", \
     507                usb_log_error("Failed to setup %s transfer list: %s.", \
    369508                    name, str_error(ret)); \
    370509                transfer_list_fini(&instance->transfers_bulk_full); \
     
    411550}
    412551
    413 errno_t uhci_hc_status(hcd_t *hcd, uint32_t *status)
    414 {
    415         assert(hcd);
     552static errno_t hc_status(bus_t *bus, uint32_t *status)
     553{
     554        hc_t *instance = bus_to_hc(bus);
    416555        assert(status);
    417         hc_t *instance = hcd_get_driver_data(hcd);
    418         assert(instance);
    419556
    420557        *status = 0;
     
    427564}
    428565
    429 /** Schedule batch for execution.
     566/**
     567 * Schedule batch for execution.
    430568 *
    431569 * @param[in] instance UHCI structure to use.
    432570 * @param[in] batch Transfer batch to schedule.
    433571 * @return Error code
    434  *
    435  * Checks for bandwidth availability and appends the batch to the proper queue.
    436  */
    437 errno_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 
     572 */
     573static errno_t hc_schedule(usb_transfer_batch_t *batch)
     574{
    447575        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;
     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);
    459593}
    460594
     
    479613
    480614                if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
    481                         usb_log_debug2("Command: %X Status: %X Intr: %x\n",
     615                        usb_log_debug2("Command: %X Status: %X Intr: %x",
    482616                            cmd, sts, intr);
    483617                }
     
    486620                    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
    487621                if (frame_list != addr_to_phys(instance->frame_list)) {
    488                         usb_log_debug("Framelist address: %p vs. %p.\n",
     622                        usb_log_debug("Framelist address: %p vs. %p.",
    489623                            (void *) frame_list,
    490624                            (void *) addr_to_phys(instance->frame_list));
     
    497631                uintptr_t real_pa = addr_to_phys(QH(interrupt));
    498632                if (expected_pa != real_pa) {
    499                         usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.\n",
     633                        usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.",
    500634                            (void *) expected_pa, frnum, (void *) real_pa);
    501635                }
     
    504638                real_pa = addr_to_phys(QH(control_slow));
    505639                if (expected_pa != real_pa) {
    506                         usb_log_debug("Control Slow QH: %p vs. %p.\n",
     640                        usb_log_debug("Control Slow QH: %p vs. %p.",
    507641                            (void *) expected_pa, (void *) real_pa);
    508642                }
     
    511645                real_pa = addr_to_phys(QH(control_full));
    512646                if (expected_pa != real_pa) {
    513                         usb_log_debug("Control Full QH: %p vs. %p.\n",
     647                        usb_log_debug("Control Full QH: %p vs. %p.",
    514648                            (void *) expected_pa, (void *) real_pa);
    515649                }
     
    518652                real_pa = addr_to_phys(QH(bulk_full));
    519653                if (expected_pa != real_pa ) {
    520                         usb_log_debug("Bulk QH: %p vs. %p.\n",
     654                        usb_log_debug("Bulk QH: %p vs. %p.",
    521655                            (void *) expected_pa, (void *) real_pa);
    522656                }
Note: See TracChangeset for help on using the changeset viewer.