Changeset df6ded8 in mainline for uspace/drv/bus/usb/uhci


Ignore:
Timestamp:
2018-02-28T16:37:50Z (8 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1b20da0
Parents:
f5e5f73 (diff), b2dca8de (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Jakub Jermar <jakub@…> (2018-02-28 16:06:42)
git-committer:
Jakub Jermar <jakub@…> (2018-02-28 16:37:50)
Message:

Merge github.com:helenos-xhci-team/helenos

This commit merges support for USB 3 and generally refactors, fixes,
extends and cleans up the existing USB framework.

Notable additions and features:

  • new host controller driver has been implemented to control various xHC models (among others, NEC Renesas uPD720200)
  • isochronous data transfer mode
  • support for explicit USB device removal
  • USB tablet driver
Location:
uspace/drv/bus/usb/uhci
Files:
11 edited

Legend:

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

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    34 * All rights reserved.
    45 *
     
    5051#include <usb/usb.h>
    5152#include <usb/host/utils/malloc32.h>
     53#include <usb/host/bandwidth.h>
     54#include <usb/host/utility.h>
    5255
    5356#include "uhci_batch.h"
     57#include "transfer_list.h"
    5458#include "hc.h"
    5559
     
    107111 * @return Error code.
    108112 */
    109 errno_t uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     113errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
    110114{
    111115        assert(code);
     
    140144        code->cmds[3].addr = (void*)&registers->usbsts;
    141145
    142         usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
     146        usb_log_debug("I/O regs at %p (size %zu), IRQ %d.",
    143147            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    144148
     
    157161 * - resume from suspend state (not implemented)
    158162 */
    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);
     163static void hc_interrupt(bus_t *bus, uint32_t status)
     164{
     165        hc_t *instance = bus_to_hc(bus);
     166
    164167        /* Lower 2 bits are transaction error and transaction complete */
    165168        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         }
     169                transfer_list_check_finished(&instance->transfers_interrupt);
     170                transfer_list_check_finished(&instance->transfers_control_slow);
     171                transfer_list_check_finished(&instance->transfers_control_full);
     172                transfer_list_check_finished(&instance->transfers_bulk_full);
     173        }
     174
    183175        /* Resume interrupts are not supported */
    184176        if (status & UHCI_STATUS_RESUME) {
    185                 usb_log_error("Resume interrupt!\n");
     177                usb_log_error("Resume interrupt!");
    186178        }
    187179
    188180        /* Bits 4 and 5 indicate hc error */
    189181        if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
    190                 usb_log_error("UHCI hardware failure!.\n");
     182                usb_log_error("UHCI hardware failure!.");
    191183                ++instance->hw_failures;
    192184                transfer_list_abort_all(&instance->transfers_interrupt);
     
    199191                        hc_init_hw(instance);
    200192                } else {
    201                         usb_log_fatal("Too many UHCI hardware failures!.\n");
    202                         hc_fini(instance);
     193                        usb_log_fatal("Too many UHCI hardware failures!.");
     194                        hc_gone(&instance->base);
    203195                }
    204196        }
     
    216208 * interrupt fibrils.
    217209 */
    218 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    219 {
    220         assert(instance);
     210errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
     211{
     212        hc_t *instance = hcd_to_hc(hcd);
    221213        assert(hw_res);
    222214        if (hw_res->io_ranges.count != 1 ||
     
    224216            return EINVAL;
    225217
    226         instance->hw_interrupts = interrupts;
    227218        instance->hw_failures = 0;
    228219
     
    231222            (void **) &instance->registers);
    232223        if (ret != EOK) {
    233                 usb_log_error("Failed to gain access to registers: %s.\n",
     224                usb_log_error("Failed to gain access to registers: %s.",
    234225                    str_error(ret));
    235226                return ret;
    236227        }
    237228
    238         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     229        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
    239230            hw_res->io_ranges.ranges[0].address.absolute,
    240231            hw_res->io_ranges.ranges[0].size);
     
    242233        ret = hc_init_mem_structures(instance);
    243234        if (ret != EOK) {
    244                 usb_log_error("Failed to init UHCI memory structures: %s.\n",
     235                usb_log_error("Failed to init UHCI memory structures: %s.",
    245236                    str_error(ret));
    246237                // TODO: we should disable pio here
     
    248239        }
    249240
     241        return EOK;
     242}
     243
     244int hc_start(hc_device_t *hcd)
     245{
     246        hc_t *instance = hcd_to_hc(hcd);
    250247        hc_init_hw(instance);
    251248        (void)hc_debug_checker;
    252249
    253         uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
    254 
    255         return EOK;
     250        return uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
     251}
     252
     253int hc_setup_roothub(hc_device_t *hcd)
     254{
     255        return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
    256256}
    257257
     
    260260 * @param[in] instance Host controller structure to use.
    261261 */
    262 void hc_fini(hc_t *instance)
     262int hc_gone(hc_device_t *instance)
    263263{
    264264        assert(instance);
    265265        //TODO Implement
     266        return ENOTSUP;
    266267}
    267268
     
    293294        pio_write_32(&registers->flbaseadd, pa);
    294295
    295         if (instance->hw_interrupts) {
     296        if (instance->base.irq_cap >= 0) {
    296297                /* Enable all interrupts, but resume interrupt */
    297298                pio_write_16(&instance->registers->usbintr,
     
    301302        const uint16_t cmd = pio_read_16(&registers->usbcmd);
    302303        if (cmd != 0)
    303                 usb_log_warning("Previous command value: %x.\n", cmd);
     304                usb_log_warning("Previous command value: %x.", cmd);
    304305
    305306        /* Start the hc with large(64B) packet FSBR */
     
    308309}
    309310
     311static usb_transfer_batch_t *create_transfer_batch(endpoint_t *ep)
     312{
     313        uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep);
     314        return &batch->base;
     315}
     316
     317static void destroy_transfer_batch(usb_transfer_batch_t *batch)
     318{
     319        uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch));
     320}
     321
     322static endpoint_t *endpoint_create(device_t *device, const usb_endpoint_descriptors_t *desc)
     323{
     324        endpoint_t *ep = calloc(1, sizeof(uhci_endpoint_t));
     325        if (ep)
     326                endpoint_init(ep, device, desc);
     327        return ep;
     328}
     329
     330static errno_t endpoint_register(endpoint_t *ep)
     331{
     332        hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
     333
     334        const errno_t err = usb2_bus_endpoint_register(&hc->bus_helper, ep);
     335        if (err)
     336                return err;
     337
     338        transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];
     339        if (!list)
     340                /*
     341                 * We don't support this combination (e.g. isochronous). Do not
     342                 * fail early, because that would block any device with these
     343                 * endpoints from connecting. Instead, make sure these transfers
     344                 * are denied soon enough with ENOTSUP not to fail on asserts.
     345                 */
     346                return EOK;
     347
     348        endpoint_set_online(ep, &list->guard);
     349        return EOK;
     350}
     351
     352static void endpoint_unregister(endpoint_t *ep)
     353{
     354        hc_t * const hc = bus_to_hc(endpoint_get_bus(ep));
     355        usb2_bus_endpoint_unregister(&hc->bus_helper, ep);
     356
     357        // Check for the roothub, as it does not schedule into lists
     358        if (ep->device->address == uhci_rh_get_address(&hc->rh)) {
     359                // FIXME: We shall check the roothub for active transfer. But
     360                // as it is polling, there is no way to make it stop doing so.
     361                // Return after rewriting uhci rh.
     362                return;
     363        }
     364
     365        transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type];
     366        if (!list)
     367                /*
     368                 * We don't support this combination (e.g. isochronous),
     369                 * so no transfer can be active.
     370                 */
     371                return;
     372
     373        fibril_mutex_lock(&list->guard);
     374
     375        endpoint_set_offline_locked(ep);
     376        /* From now on, no other transfer will be scheduled. */
     377
     378        if (!ep->active_batch) {
     379                fibril_mutex_unlock(&list->guard);
     380                return;
     381        }
     382
     383        /* First, offer the batch a short chance to be finished. */
     384        endpoint_wait_timeout_locked(ep, 10000);
     385
     386        if (!ep->active_batch) {
     387                fibril_mutex_unlock(&list->guard);
     388                return;
     389        }
     390
     391        uhci_transfer_batch_t * const batch =
     392                uhci_transfer_batch_get(ep->active_batch);
     393
     394        /* Remove the batch from the schedule to stop it from being finished. */
     395        endpoint_deactivate_locked(ep);
     396        transfer_list_remove_batch(list, batch);
     397
     398        fibril_mutex_unlock(&list->guard);
     399
     400        /*
     401         * We removed the batch from software schedule only, it's still possible
     402         * that HC has it in its caches. Better wait a while before we release
     403         * the buffers.
     404         */
     405        async_usleep(20000);
     406        batch->base.error = EINTR;
     407        batch->base.transferred_size = 0;
     408        usb_transfer_batch_finish(&batch->base);
     409}
     410
     411static int device_enumerate(device_t *dev)
     412{
     413        hc_t * const hc = bus_to_hc(dev->bus);
     414        return usb2_bus_device_enumerate(&hc->bus_helper, dev);
     415}
     416
     417static void device_gone(device_t *dev)
     418{
     419        hc_t * const hc = bus_to_hc(dev->bus);
     420        usb2_bus_device_gone(&hc->bus_helper, dev);
     421}
     422
     423static int hc_status(bus_t *, uint32_t *);
     424static int hc_schedule(usb_transfer_batch_t *);
     425
     426static const bus_ops_t uhci_bus_ops = {
     427        .interrupt = hc_interrupt,
     428        .status = hc_status,
     429
     430        .device_enumerate = device_enumerate,
     431        .device_gone = device_gone,
     432
     433        .endpoint_create = endpoint_create,
     434        .endpoint_register = endpoint_register,
     435        .endpoint_unregister = endpoint_unregister,
     436
     437        .batch_create = create_transfer_batch,
     438        .batch_schedule = hc_schedule,
     439        .batch_destroy = destroy_transfer_batch,
     440};
     441
    310442/** Initialize UHCI hc memory structures.
    311443 *
     
    321453{
    322454        assert(instance);
     455
     456        usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11);
     457
     458        bus_init(&instance->bus, sizeof(device_t));
     459        instance->bus.ops = &uhci_bus_ops;
     460
     461        hc_device_setup(&instance->base, &instance->bus);
    323462
    324463        /* Init USB frame list page */
     
    327466                return ENOMEM;
    328467        }
    329         usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
     468        usb_log_debug("Initialized frame list at %p.", instance->frame_list);
    330469
    331470        /* Init transfer lists */
    332471        errno_t ret = hc_init_transfer_lists(instance);
    333472        if (ret != EOK) {
    334                 usb_log_error("Failed to initialize transfer lists.\n");
     473                usb_log_error("Failed to initialize transfer lists.");
    335474                return_page(instance->frame_list);
    336475                return ENOMEM;
    337476        }
    338         usb_log_debug("Initialized transfer lists.\n");
     477        list_initialize(&instance->pending_endpoints);
     478        usb_log_debug("Initialized transfer lists.");
    339479
    340480
     
    366506        errno_t ret = transfer_list_init(&instance->transfers_##type, name); \
    367507        if (ret != EOK) { \
    368                 usb_log_error("Failed to setup %s transfer list: %s.\n", \
     508                usb_log_error("Failed to setup %s transfer list: %s.", \
    369509                    name, str_error(ret)); \
    370510                transfer_list_fini(&instance->transfers_bulk_full); \
     
    411551}
    412552
    413 errno_t uhci_hc_status(hcd_t *hcd, uint32_t *status)
    414 {
    415         assert(hcd);
     553static errno_t hc_status(bus_t *bus, uint32_t *status)
     554{
     555        hc_t *instance = bus_to_hc(bus);
    416556        assert(status);
    417         hc_t *instance = hcd_get_driver_data(hcd);
    418         assert(instance);
    419557
    420558        *status = 0;
     
    427565}
    428566
    429 /** Schedule batch for execution.
     567/**
     568 * Schedule batch for execution.
    430569 *
    431570 * @param[in] instance UHCI structure to use.
    432571 * @param[in] batch Transfer batch to schedule.
    433572 * @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 
     573 */
     574static errno_t hc_schedule(usb_transfer_batch_t *batch)
     575{
    447576        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;
     577        endpoint_t *ep = batch->ep;
     578        hc_t *hc = bus_to_hc(endpoint_get_bus(ep));
     579
     580        if (batch->target.address == uhci_rh_get_address(&hc->rh))
     581                return uhci_rh_schedule(&hc->rh, batch);
     582
     583        transfer_list_t * const list =
     584            hc->transfers[ep->device->speed][ep->transfer_type];
     585
     586        if (!list)
     587                return ENOTSUP;
     588
     589        errno_t err;
     590        if ((err = uhci_transfer_batch_prepare(uhci_batch)))
     591                return err;
     592
     593        return transfer_list_add_batch(list, uhci_batch);
    459594}
    460595
     
    479614
    480615                if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
    481                         usb_log_debug2("Command: %X Status: %X Intr: %x\n",
     616                        usb_log_debug2("Command: %X Status: %X Intr: %x",
    482617                            cmd, sts, intr);
    483618                }
     
    486621                    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
    487622                if (frame_list != addr_to_phys(instance->frame_list)) {
    488                         usb_log_debug("Framelist address: %p vs. %p.\n",
     623                        usb_log_debug("Framelist address: %p vs. %p.",
    489624                            (void *) frame_list,
    490625                            (void *) addr_to_phys(instance->frame_list));
     
    497632                uintptr_t real_pa = addr_to_phys(QH(interrupt));
    498633                if (expected_pa != real_pa) {
    499                         usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.\n",
     634                        usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.",
    500635                            (void *) expected_pa, frnum, (void *) real_pa);
    501636                }
     
    504639                real_pa = addr_to_phys(QH(control_slow));
    505640                if (expected_pa != real_pa) {
    506                         usb_log_debug("Control Slow QH: %p vs. %p.\n",
     641                        usb_log_debug("Control Slow QH: %p vs. %p.",
    507642                            (void *) expected_pa, (void *) real_pa);
    508643                }
     
    511646                real_pa = addr_to_phys(QH(control_full));
    512647                if (expected_pa != real_pa) {
    513                         usb_log_debug("Control Full QH: %p vs. %p.\n",
     648                        usb_log_debug("Control Full QH: %p vs. %p.",
    514649                            (void *) expected_pa, (void *) real_pa);
    515650                }
     
    518653                real_pa = addr_to_phys(QH(bulk_full));
    519654                if (expected_pa != real_pa ) {
    520                         usb_log_debug("Bulk QH: %p vs. %p.\n",
     655                        usb_log_debug("Bulk QH: %p vs. %p.",
    521656                            (void *) expected_pa, (void *) real_pa);
    522657                }
  • uspace/drv/bus/usb/uhci/hc.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4344#include <ddi.h>
    4445#include <usb/host/hcd.h>
     46#include <usb/host/usb2_bus.h>
    4547#include <usb/host/usb_transfer_batch.h>
    4648
     
    99101/** Main UHCI driver structure */
    100102typedef struct hc {
     103        /* Common hc_device header */
     104        hc_device_t base;
     105
    101106        uhci_rh_t rh;
     107        bus_t bus;
     108        usb2_bus_helper_t bus_helper;
     109
    102110        /** Addresses of I/O registers */
    103111        uhci_regs_t *registers;
     
    117125        /** Pointer table to the above lists, helps during scheduling */
    118126        transfer_list_t *transfers[2][4];
    119         /** Indicator of hw interrupts availability */
    120         bool hw_interrupts;
     127
     128        /**
     129         * Guard for the pending list. Can be locked under EP guard, but not
     130         * vice versa.
     131         */
     132        fibril_mutex_t guard;
     133        /** List of endpoints with a transfer scheduled */
     134        list_t pending_endpoints;
    121135
    122136        /** Number of hw failures detected. */
     
    124138} hc_t;
    125139
    126 extern errno_t hc_init(hc_t *, const hw_res_list_parsed_t *, bool);
    127 extern void hc_fini(hc_t *);
     140typedef struct uhci_endpoint {
     141        endpoint_t base;
    128142
    129 extern errno_t uhci_hc_gen_irq_code(irq_code_t *, const hw_res_list_parsed_t *, int *);
     143        bool toggle;
     144} uhci_endpoint_t;
    130145
    131 extern void uhci_hc_interrupt(hcd_t *, uint32_t);
    132 extern errno_t uhci_hc_status(hcd_t *, uint32_t *);
    133 extern errno_t uhci_hc_schedule(hcd_t *, usb_transfer_batch_t *);
     146static inline hc_t *hcd_to_hc(hc_device_t *hcd)
     147{
     148        assert(hcd);
     149        return (hc_t *) hcd;
     150}
     151
     152static inline hc_t *bus_to_hc(bus_t *bus)
     153{
     154        assert(bus);
     155        return member_to_inst(bus, hc_t, bus);
     156}
     157
     158int hc_unschedule_batch(usb_transfer_batch_t *);
     159
     160extern errno_t hc_add(hc_device_t *, const hw_res_list_parsed_t *);
     161extern errno_t hc_gen_irq_code(irq_code_t *, hc_device_t *, const hw_res_list_parsed_t *, int *);
     162extern errno_t hc_start(hc_device_t *);
     163extern errno_t hc_setup_roothub(hc_device_t *);
     164extern errno_t hc_gone(hc_device_t *);
    134165
    135166#endif
  • uspace/drv/bus/usb/uhci/hw_struct/queue_head.h

    rf5e5f73 rdf6ded8  
    4848        /** Pointer to the next entity (another QH or TD */
    4949        volatile link_pointer_t next;
    50         /** Pointer to the contained entities (execution controlled by vertical flag*/
     50        /**
     51         * Pointer to the contained entities
     52         * (execution controlled by vertical flag)
     53         */
    5154        volatile link_pointer_t element;
    52 } __attribute__((packed)) qh_t;
     55} __attribute__((packed, aligned(16))) qh_t;
    5356
    5457/** Initialize queue head structure
  • uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.c

    rf5e5f73 rdf6ded8  
    104104        instance->buffer_ptr = addr_to_phys(buffer);
    105105
    106         usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).\n",
     106        usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).",
    107107            instance, instance->next, instance->status, instance->device,
    108108            instance->buffer_ptr, buffer);
    109109        td_print_status(instance);
    110110        if (pid == USB_PID_SETUP) {
    111                 usb_log_debug2("SETUP BUFFER: %s\n",
     111                usb_log_debug2("SETUP BUFFER: %s",
    112112                    usb_debug_str_buffer(buffer, 8, 8));
    113113        }
     
    160160        assert(instance);
    161161        const uint32_t s = instance->status;
    162         usb_log_debug2("TD(%p) status(%#" PRIx32 "):%s %d,%s%s%s%s%s%s%s%s%s%s%s %zu.\n",
     162        usb_log_debug2("TD(%p) status(%#" PRIx32 "):%s %d,%s%s%s%s%s%s%s%s%s%s%s %zu.",
    163163            instance, instance->status,
    164164            (s & TD_STATUS_SPD_FLAG) ? " SPD," : "",
  • uspace/drv/bus/usb/uhci/hw_struct/transfer_descriptor.h

    rf5e5f73 rdf6ded8  
    9595         * memory just needs to be aligned. We don't use it anyway.
    9696         */
    97 } __attribute__((packed)) td_t;
     97} __attribute__((packed, aligned(16))) td_t;
    9898
    9999
  • uspace/drv/bus/usb/uhci/main.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky, Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    34 * All rights reserved.
    45 *
     
    4344#include <str_error.h>
    4445#include <usb/debug.h>
    45 #include <usb/host/ddf_helpers.h>
     46#include <usb/host/utility.h>
    4647
    4748#include "hc.h"
     
    4950#define NAME "uhci"
    5051
    51 static errno_t uhci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool);
    52 static void uhci_driver_fini(hcd_t *);
    53 static errno_t disable_legacy(ddf_dev_t *);
     52static errno_t disable_legacy(hc_device_t *);
    5453
    55 static const ddf_hc_driver_t uhci_hc_driver = {
    56         .claim = disable_legacy,
    57         .hc_speed = USB_SPEED_FULL,
    58         .irq_code_gen = uhci_hc_gen_irq_code,
    59         .init = uhci_driver_init,
    60         .fini = uhci_driver_fini,
    61         .name = "UHCI",
    62         .ops = {
    63                 .schedule    = uhci_hc_schedule,
    64                 .irq_hook    = uhci_hc_interrupt,
    65                 .status_hook = uhci_hc_status,
    66         },
     54static const hc_driver_t uhci_driver = {
     55        .name = NAME,
     56        .hc_device_size = sizeof(hc_t),
     57        .claim = disable_legacy,
     58        .irq_code_gen = hc_gen_irq_code,
     59        .hc_add = hc_add,
     60        .start = hc_start,
     61        .setup_root_hub = hc_setup_roothub,
     62        .hc_gone = hc_gone,
    6763};
    68 
    69 static errno_t uhci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq)
    70 {
    71         assert(hcd);
    72         assert(hcd_get_driver_data(hcd) == NULL);
    73 
    74         hc_t *instance = malloc(sizeof(hc_t));
    75         if (!instance)
    76                 return ENOMEM;
    77 
    78         const errno_t ret = hc_init(instance, res, irq);
    79         if (ret == EOK) {
    80                 hcd_set_implementation(hcd, instance, &uhci_hc_driver.ops);
    81         } else {
    82                 free(instance);
    83         }
    84         return ret;
    85 }
    86 
    87 static void uhci_driver_fini(hcd_t *hcd)
    88 {
    89         assert(hcd);
    90         hc_t *hc = hcd_get_driver_data(hcd);
    91         if (hc)
    92                 hc_fini(hc);
    93 
    94         hcd_set_implementation(hcd, NULL, NULL);
    95         free(hc);
    96 }
    9764
    9865/** Call the PCI driver with a request to clear legacy support register
     
    10168 * @return Error code.
    10269 */
    103 static errno_t disable_legacy(ddf_dev_t *device)
     70static errno_t disable_legacy(hc_device_t *hcd)
    10471{
    105         assert(device);
     72        assert(hcd);
    10673
    107         async_sess_t *parent_sess = ddf_dev_parent_sess_get(device);
     74        async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev);
    10875        if (parent_sess == NULL)
    10976                return ENOMEM;
     
    11380        return pci_config_space_write_16(parent_sess, 0xc0, 0xaf00);
    11481}
    115 
    116 /** Initialize a new ddf driver instance for uhci hc and hub.
    117  *
    118  * @param[in] device DDF instance of the device to initialize.
    119  * @return Error code.
    120  */
    121 static errno_t uhci_dev_add(ddf_dev_t *device)
    122 {
    123         usb_log_debug2("uhci_dev_add() called\n");
    124         assert(device);
    125         return hcd_ddf_add_hc(device, &uhci_hc_driver);
    126 }
    127 
    128 static const driver_ops_t uhci_driver_ops = {
    129         .dev_add = uhci_dev_add,
    130 };
    131 
    132 static const driver_t uhci_driver = {
    133         .name = NAME,
    134         .driver_ops = &uhci_driver_ops
    135 };
    136 
    13782
    13883/** Initialize global driver structures (NONE).
     
    14994        log_init(NAME);
    15095        logctl_set_log_level(NAME, LVL_NOTE);
    151         return ddf_driver_main(&uhci_driver);
     96        return hc_driver_main(&uhci_driver);
    15297}
    15398/**
  • uspace/drv/bus/usb/uhci/transfer_list.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    34 * All rights reserved.
    45 *
     
    4142#include <usb/host/usb_transfer_batch.h>
    4243#include <usb/host/utils/malloc32.h>
     44#include <usb/host/utility.h>
    4345
    4446#include "hw_struct/link_pointer.h"
    4547#include "transfer_list.h"
    46 
    47 static void transfer_list_remove_batch(
    48     transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch);
     48#include "hc.h"
    4949
    5050/** Initialize transfer list structures.
     
    6262        instance->queue_head = malloc32(sizeof(qh_t));
    6363        if (!instance->queue_head) {
    64                 usb_log_error("Failed to allocate queue head.\n");
     64                usb_log_error("Failed to allocate queue head.");
    6565                return ENOMEM;
    6666        }
    6767        const uint32_t queue_head_pa = addr_to_phys(instance->queue_head);
    68         usb_log_debug2("Transfer list %s setup with QH: %p (%#" PRIx32" ).\n",
     68        usb_log_debug2("Transfer list %s setup with QH: %p (%#" PRIx32" ).",
    6969            name, instance->queue_head, queue_head_pa);
    7070
     
    103103}
    104104
    105 /** Add transfer batch to the list and queue.
    106  *
    107  * @param[in] instance List to use.
    108  * @param[in] batch Transfer batch to submit.
     105/**
     106 * Add transfer batch to the list and queue.
    109107 *
    110108 * The batch is added to the end of the list and queue.
    111  */
    112 void transfer_list_add_batch(
     109 *
     110 * @param[in] instance List to use.
     111 * @param[in] batch Transfer batch to submit. After return, the batch must
     112 *                  not be used further.
     113 */
     114int transfer_list_add_batch(
    113115    transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch)
    114116{
    115117        assert(instance);
    116118        assert(uhci_batch);
    117         usb_log_debug2("Batch %p adding to queue %s.\n",
    118             uhci_batch->usb_batch, instance->name);
     119
     120        endpoint_t *ep = uhci_batch->base.ep;
    119121
    120122        fibril_mutex_lock(&instance->guard);
     123
     124        const int err = endpoint_activate_locked(ep, &uhci_batch->base);
     125        if (err) {
     126                fibril_mutex_unlock(&instance->guard);
     127                return err;
     128        }
     129
     130        usb_log_debug2("Batch %p adding to queue %s.",
     131            uhci_batch, instance->name);
    121132
    122133        /* Assume there is nothing scheduled */
     
    145156
    146157        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
    147             " scheduled in queue %s.\n", uhci_batch->usb_batch,
    148             USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch), instance->name);
     158            " scheduled in queue %s.", uhci_batch,
     159            USB_TRANSFER_BATCH_ARGS(uhci_batch->base), instance->name);
    149160        fibril_mutex_unlock(&instance->guard);
     161        return EOK;
     162}
     163
     164/**
     165 * Reset toggle on endpoint callback.
     166 */
     167static void uhci_reset_toggle(endpoint_t *ep)
     168{
     169        uhci_endpoint_t *uhci_ep = (uhci_endpoint_t *) ep;
     170        uhci_ep->toggle = 0;
    150171}
    151172
     
    155176 * @param[in] done list to fill
    156177 */
    157 void transfer_list_remove_finished(transfer_list_t *instance, list_t *done)
    158 {
    159         assert(instance);
    160         assert(done);
     178void transfer_list_check_finished(transfer_list_t *instance)
     179{
     180        assert(instance);
    161181
    162182        fibril_mutex_lock(&instance->guard);
    163         link_t *current = list_first(&instance->batch_list);
    164         while (current && current != &instance->batch_list.head) {
    165                 link_t * const next = current->next;
    166                 uhci_transfer_batch_t *batch =
    167                     uhci_transfer_batch_from_link(current);
    168 
    169                 if (uhci_transfer_batch_is_complete(batch)) {
    170                         /* Save for processing */
     183        list_foreach_safe(instance->batch_list, current, next) {
     184                uhci_transfer_batch_t *batch = uhci_transfer_batch_from_link(current);
     185
     186                if (uhci_transfer_batch_check_completed(batch)) {
     187                        assert(batch->base.ep->active_batch == &batch->base);
     188                        endpoint_deactivate_locked(batch->base.ep);
     189                        hc_reset_toggles(&batch->base, &uhci_reset_toggle);
    171190                        transfer_list_remove_batch(instance, batch);
    172                         list_append(current, done);
     191                        usb_transfer_batch_finish(&batch->base);
    173192                }
    174                 current = next;
    175193        }
    176194        fibril_mutex_unlock(&instance->guard);
     
    186204        while (!list_empty(&instance->batch_list)) {
    187205                link_t * const current = list_first(&instance->batch_list);
    188                 uhci_transfer_batch_t *batch =
    189                     uhci_transfer_batch_from_link(current);
     206                uhci_transfer_batch_t *batch = uhci_transfer_batch_from_link(current);
    190207                transfer_list_remove_batch(instance, batch);
    191                 uhci_transfer_batch_abort(batch);
    192208        }
    193209        fibril_mutex_unlock(&instance->guard);
     
    209225        assert(uhci_batch->qh);
    210226        assert(fibril_mutex_is_locked(&instance->guard));
    211 
    212         usb_log_debug2("Batch %p removing from queue %s.\n",
    213             uhci_batch->usb_batch, instance->name);
     227        assert(!list_empty(&instance->batch_list));
     228
     229        usb_log_debug2("Batch %p removing from queue %s.",
     230            uhci_batch, instance->name);
    214231
    215232        /* Assume I'm the first */
     
    233250        list_remove(&uhci_batch->link);
    234251        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " removed (%s) "
    235             "from %s, next: %x.\n", uhci_batch->usb_batch,
    236             USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch),
     252            "from %s, next: %x.", uhci_batch,
     253            USB_TRANSFER_BATCH_ARGS(uhci_batch->base),
    237254            qpos, instance->name, uhci_batch->qh->next);
    238255}
  • uspace/drv/bus/usb/uhci/transfer_list.h

    rf5e5f73 rdf6ded8  
    5656} transfer_list_t;
    5757
    58 void transfer_list_fini(transfer_list_t *instance);
    59 errno_t transfer_list_init(transfer_list_t *instance, const char *name);
    60 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next);
    61 void transfer_list_add_batch(
    62     transfer_list_t *instance, uhci_transfer_batch_t *batch);
    63 void transfer_list_remove_finished(transfer_list_t *instance, list_t *done);
    64 void transfer_list_abort_all(transfer_list_t *instance);
     58void transfer_list_fini(transfer_list_t *);
     59errno_t transfer_list_init(transfer_list_t *, const char *);
     60void transfer_list_set_next(transfer_list_t *, transfer_list_t *);
     61errno_t transfer_list_add_batch(transfer_list_t *, uhci_transfer_batch_t *);
     62void transfer_list_remove_batch(transfer_list_t *, uhci_transfer_batch_t *);
     63void transfer_list_check_finished(transfer_list_t *);
     64void transfer_list_abort_all(transfer_list_t *);
    6565
    6666#endif
  • uspace/drv/bus/usb/uhci/uhci_batch.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4647
    4748#include "uhci_batch.h"
     49#include "hc.h"
    4850#include "hw_struct/transfer_descriptor.h"
    4951
    5052#define DEFAULT_ERROR_COUNT 3
    5153
    52 /** Safely destructs uhci_transfer_batch_t structure.
     54/** Transfer batch setup table. */
     55static void (*const batch_setup[])(uhci_transfer_batch_t*);
     56
     57/** Destroys uhci_transfer_batch_t structure.
    5358 *
    5459 * @param[in] uhci_batch Instance to destroy.
    5560 */
    56 static void uhci_transfer_batch_dispose(uhci_transfer_batch_t *uhci_batch)
    57 {
    58         if (uhci_batch) {
    59                 usb_transfer_batch_destroy(uhci_batch->usb_batch);
    60                 free32(uhci_batch->device_buffer);
    61                 free(uhci_batch);
    62         }
    63 }
    64 
    65 /** Finishes usb_transfer_batch and destroys the structure.
    66  *
    67  * @param[in] uhci_batch Instance to finish and destroy.
    68  */
    69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch)
     61void uhci_transfer_batch_destroy(uhci_transfer_batch_t *uhci_batch)
    7062{
    7163        assert(uhci_batch);
    72         assert(uhci_batch->usb_batch);
    73         assert(!link_in_use(&uhci_batch->link));
    74         usb_transfer_batch_finish(uhci_batch->usb_batch,
    75             uhci_transfer_batch_data_buffer(uhci_batch));
    76         uhci_transfer_batch_dispose(uhci_batch);
    77 }
    78 
    79 /** Transfer batch setup table. */
    80 static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t);
     64        dma_buffer_free(&uhci_batch->uhci_dma_buffer);
     65        free(uhci_batch);
     66}
    8167
    8268/** Allocate memory and initialize internal data structure.
     
    8571 * @return Valid pointer if all structures were successfully created,
    8672 * NULL otherwise.
     73 */
     74uhci_transfer_batch_t * uhci_transfer_batch_create(endpoint_t *ep)
     75{
     76        uhci_transfer_batch_t *uhci_batch =
     77            calloc(1, sizeof(uhci_transfer_batch_t));
     78        if (!uhci_batch) {
     79                usb_log_error("Failed to allocate UHCI batch.");
     80                return NULL;
     81        }
     82
     83        usb_transfer_batch_init(&uhci_batch->base, ep);
     84
     85        link_initialize(&uhci_batch->link);
     86        return uhci_batch;
     87}
     88
     89/* Prepares batch for commiting.
    8790 *
    8891 * Determines the number of needed transfer descriptors (TDs).
     
    9093 * Initializes parameters needed for the transfer and callback.
    9194 */
    92 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
     95int uhci_transfer_batch_prepare(uhci_transfer_batch_t *uhci_batch)
    9396{
    9497        static_assert((sizeof(td_t) % 16) == 0);
    95 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
    96         if (ptr == NULL) { \
    97                 usb_log_error(message); \
    98                 uhci_transfer_batch_dispose(uhci_batch); \
    99                 return NULL; \
    100         } else (void)0
    101 
    102         uhci_transfer_batch_t *uhci_batch =
    103             calloc(1, sizeof(uhci_transfer_batch_t));
    104         CHECK_NULL_DISPOSE_RETURN(uhci_batch,
    105             "Failed to allocate UHCI batch.\n");
    106         link_initialize(&uhci_batch->link);
    107         uhci_batch->td_count =
    108             (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1)
    109             / usb_batch->ep->max_packet_size;
     98
     99        usb_transfer_batch_t *usb_batch = &uhci_batch->base;
     100
     101        uhci_batch->td_count = (usb_batch->size + usb_batch->ep->max_packet_size - 1)
     102                / usb_batch->ep->max_packet_size;
     103
    110104        if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
    111105                uhci_batch->td_count += 2;
    112106        }
    113107
     108        const size_t setup_size = (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL)
     109                ? USB_SETUP_PACKET_SIZE
     110                : 0;
     111
    114112        const size_t total_size = (sizeof(td_t) * uhci_batch->td_count)
    115             + sizeof(qh_t) + usb_batch->setup_size + usb_batch->buffer_size;
    116         uhci_batch->device_buffer = malloc32(total_size);
    117         CHECK_NULL_DISPOSE_RETURN(uhci_batch->device_buffer,
    118             "Failed to allocate UHCI buffer.\n");
    119         memset(uhci_batch->device_buffer, 0, total_size);
    120 
    121         uhci_batch->tds = uhci_batch->device_buffer;
    122         uhci_batch->qh =
    123             (uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count));
     113            + sizeof(qh_t) + setup_size;
     114
     115        if (dma_buffer_alloc(&uhci_batch->uhci_dma_buffer, total_size)) {
     116                usb_log_error("Failed to allocate UHCI buffer.");
     117                return ENOMEM;
     118        }
     119        memset(uhci_batch->uhci_dma_buffer.virt, 0, total_size);
     120
     121        uhci_batch->tds = uhci_batch->uhci_dma_buffer.virt;
     122        uhci_batch->qh = (qh_t *) &uhci_batch->tds[uhci_batch->td_count];
    124123
    125124        qh_init(uhci_batch->qh);
    126125        qh_set_element_td(uhci_batch->qh, &uhci_batch->tds[0]);
    127126
    128         void *dest =
    129             uhci_batch->device_buffer + (sizeof(td_t) * uhci_batch->td_count)
    130             + sizeof(qh_t);
     127        void *setup_buffer = uhci_transfer_batch_setup_buffer(uhci_batch);
     128        assert(setup_buffer == (void *) (uhci_batch->qh + 1));
    131129        /* Copy SETUP packet data to the device buffer */
    132         memcpy(dest, usb_batch->setup_buffer, usb_batch->setup_size);
    133         dest += usb_batch->setup_size;
    134         /* Copy generic data unless they are provided by the device */
    135         if (usb_batch->ep->direction != USB_DIRECTION_IN) {
    136                 memcpy(dest, usb_batch->buffer, usb_batch->buffer_size);
    137         }
    138         uhci_batch->usb_batch = usb_batch;
     130        memcpy(setup_buffer, usb_batch->setup.buffer, setup_size);
     131
    139132        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
    140             " memory structures ready.\n", usb_batch,
     133            " memory structures ready.", usb_batch,
    141134            USB_TRANSFER_BATCH_ARGS(*usb_batch));
    142135
    143         const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);
    144 
    145136        assert(batch_setup[usb_batch->ep->transfer_type]);
    146         batch_setup[usb_batch->ep->transfer_type](uhci_batch, dir);
    147 
    148         return uhci_batch;
     137        batch_setup[usb_batch->ep->transfer_type](uhci_batch);
     138
     139        return EOK;
    149140}
    150141
     
    158149 * is reached.
    159150 */
    160 bool uhci_transfer_batch_is_complete(const uhci_transfer_batch_t *uhci_batch)
     151bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *uhci_batch)
    161152{
    162153        assert(uhci_batch);
    163         assert(uhci_batch->usb_batch);
     154        usb_transfer_batch_t *batch = &uhci_batch->base;
    164155
    165156        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
    166             " checking %zu transfer(s) for completion.\n",
    167             uhci_batch->usb_batch,
    168             USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch),
     157            " checking %zu transfer(s) for completion.",
     158            uhci_batch, USB_TRANSFER_BATCH_ARGS(*batch),
    169159            uhci_batch->td_count);
    170         uhci_batch->usb_batch->transfered_size = 0;
     160        batch->transferred_size = 0;
     161
     162        uhci_endpoint_t *uhci_ep = (uhci_endpoint_t *) batch->ep;
    171163
    172164        for (size_t i = 0;i < uhci_batch->td_count; ++i) {
     
    175167                }
    176168
    177                 uhci_batch->usb_batch->error = td_status(&uhci_batch->tds[i]);
    178                 if (uhci_batch->usb_batch->error != EOK) {
    179                         assert(uhci_batch->usb_batch->ep != NULL);
     169                batch->error = td_status(&uhci_batch->tds[i]);
     170                if (batch->error != EOK) {
     171                        assert(batch->ep != NULL);
    180172
    181173                        usb_log_debug("Batch %p found error TD(%zu->%p):%"
    182                             PRIx32 ".\n", uhci_batch->usb_batch, i,
     174                            PRIx32 ".", uhci_batch, i,
    183175                            &uhci_batch->tds[i], uhci_batch->tds[i].status);
    184176                        td_print_status(&uhci_batch->tds[i]);
    185177
    186                         endpoint_toggle_set(uhci_batch->usb_batch->ep,
    187                             td_toggle(&uhci_batch->tds[i]));
    188                         if (i > 0)
    189                                 goto substract_ret;
    190                         return true;
     178                        uhci_ep->toggle = td_toggle(&uhci_batch->tds[i]);
     179                        goto substract_ret;
    191180                }
    192181
    193                 uhci_batch->usb_batch->transfered_size
     182                batch->transferred_size
    194183                    += td_act_size(&uhci_batch->tds[i]);
    195184                if (td_is_short(&uhci_batch->tds[i]))
     
    197186        }
    198187substract_ret:
    199         uhci_batch->usb_batch->transfered_size
    200             -= uhci_batch->usb_batch->setup_size;
     188        if (batch->transferred_size > 0 && batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
     189                assert(batch->transferred_size >= USB_SETUP_PACKET_SIZE);
     190                batch->transferred_size -= USB_SETUP_PACKET_SIZE;
     191        }
     192
     193        assert(batch->transferred_size <= batch->size);
     194
    201195        return true;
    202196}
     
    216210 * The last transfer is marked with IOC flag.
    217211 */
    218 static void batch_data(uhci_transfer_batch_t *uhci_batch, usb_direction_t dir)
     212static void batch_data(uhci_transfer_batch_t *uhci_batch)
    219213{
    220214        assert(uhci_batch);
    221         assert(uhci_batch->usb_batch);
    222         assert(uhci_batch->usb_batch->ep);
     215
     216        usb_direction_t dir = uhci_batch->base.dir;
    223217        assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN);
    224218
     
    226220        const usb_packet_id pid = direction_pids[dir];
    227221        const bool low_speed =
    228             uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW;
    229         const size_t mps = uhci_batch->usb_batch->ep->max_packet_size;
    230         const usb_target_t target = {{
    231             uhci_batch->usb_batch->ep->address,
    232             uhci_batch->usb_batch->ep->endpoint }};
    233 
    234         int toggle = endpoint_toggle_get(uhci_batch->usb_batch->ep);
     222            uhci_batch->base.ep->device->speed == USB_SPEED_LOW;
     223        const size_t mps = uhci_batch->base.ep->max_packet_size;
     224
     225        uhci_endpoint_t *uhci_ep = (uhci_endpoint_t *) uhci_batch->base.ep;
     226
     227        int toggle = uhci_ep->toggle;
    235228        assert(toggle == 0 || toggle == 1);
    236229
    237230        size_t td = 0;
    238         size_t remain_size = uhci_batch->usb_batch->buffer_size;
     231        size_t remain_size = uhci_batch->base.size;
    239232        char *buffer = uhci_transfer_batch_data_buffer(uhci_batch);
    240233
     
    248241                td_init(
    249242                    &uhci_batch->tds[td], DEFAULT_ERROR_COUNT, packet_size,
    250                     toggle, false, low_speed, target, pid, buffer, next_td);
     243                    toggle, false, low_speed, uhci_batch->base.target, pid, buffer, next_td);
    251244
    252245                ++td;
     
    256249        }
    257250        td_set_ioc(&uhci_batch->tds[td - 1]);
    258         endpoint_toggle_set(uhci_batch->usb_batch->ep, toggle);
     251        uhci_ep->toggle = toggle;
    259252        usb_log_debug2(
    260             "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.\n", \
    261             uhci_batch->usb_batch,
    262             usb_str_transfer_type(uhci_batch->usb_batch->ep->transfer_type),
    263             usb_str_direction(uhci_batch->usb_batch->ep->direction),
    264             USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch));
     253            "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.", \
     254            uhci_batch,
     255            usb_str_transfer_type(uhci_batch->base.ep->transfer_type),
     256            usb_str_direction(uhci_batch->base.ep->direction),
     257            USB_TRANSFER_BATCH_ARGS(uhci_batch->base));
    265258}
    266259
     
    276269 * The last transfer is marked with IOC.
    277270 */
    278 static void batch_control(uhci_transfer_batch_t *uhci_batch, usb_direction_t dir)
     271static void batch_control(uhci_transfer_batch_t *uhci_batch)
    279272{
    280273        assert(uhci_batch);
    281         assert(uhci_batch->usb_batch);
    282         assert(uhci_batch->usb_batch->ep);
     274
     275        usb_direction_t dir = uhci_batch->base.dir;
    283276        assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN);
    284277        assert(uhci_batch->td_count >= 2);
     
    291284        const usb_packet_id status_stage_pid = status_stage_pids[dir];
    292285        const bool low_speed =
    293             uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW;
    294         const size_t mps = uhci_batch->usb_batch->ep->max_packet_size;
    295         const usb_target_t target = {{
    296             uhci_batch->usb_batch->ep->address,
    297             uhci_batch->usb_batch->ep->endpoint }};
     286            uhci_batch->base.ep->device->speed == USB_SPEED_LOW;
     287        const size_t mps = uhci_batch->base.ep->max_packet_size;
     288        const usb_target_t target = uhci_batch->base.target;
    298289
    299290        /* setup stage */
    300291        td_init(
    301292            &uhci_batch->tds[0], DEFAULT_ERROR_COUNT,
    302             uhci_batch->usb_batch->setup_size, 0, false,
     293            USB_SETUP_PACKET_SIZE, 0, false,
    303294            low_speed, target, USB_PID_SETUP,
    304295            uhci_transfer_batch_setup_buffer(uhci_batch), &uhci_batch->tds[1]);
     
    307298        size_t td = 1;
    308299        unsigned toggle = 1;
    309         size_t remain_size = uhci_batch->usb_batch->buffer_size;
     300        size_t remain_size = uhci_batch->base.size;
    310301        char *buffer = uhci_transfer_batch_data_buffer(uhci_batch);
    311302
     
    333324        td_set_ioc(&uhci_batch->tds[td]);
    334325
    335         usb_log_debug2("Control last TD status: %x.\n",
     326        usb_log_debug2("Control last TD status: %x.",
    336327            uhci_batch->tds[td].status);
    337328}
    338329
    339 static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t) =
     330static void (*const batch_setup[])(uhci_transfer_batch_t*) =
    340331{
    341332        [USB_TRANSFER_CONTROL] = batch_control,
  • uspace/drv/bus/usb/uhci/uhci_batch.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4344#include <stddef.h>
    4445#include <usb/host/usb_transfer_batch.h>
     46#include <usb/host/endpoint.h>
    4547
    4648#include "hw_struct/queue_head.h"
     
    4951/** UHCI specific data required for USB transfer */
    5052typedef struct uhci_transfer_batch {
     53        usb_transfer_batch_t base;
     54
    5155        /** Queue head
    5256         * This QH is used to maintain UHCI schedule structure and the element
     
    5862        /** Number of TDs used by the transfer */
    5963        size_t td_count;
    60         /** Data buffer, must be accessible by the UHCI hw */
    61         void *device_buffer;
    62         /** Generic transfer data */
    63         usb_transfer_batch_t *usb_batch;
     64        /* Setup data */
     65        char *setup_buffer;
     66        /** Backing TDs + setup_buffer */
     67        dma_buffer_t uhci_dma_buffer;
    6468        /** List element */
    6569        link_t link;
    6670} uhci_transfer_batch_t;
    6771
    68 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *batch);
    69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch);
    70 bool uhci_transfer_batch_is_complete(const uhci_transfer_batch_t *uhci_batch);
     72uhci_transfer_batch_t *uhci_transfer_batch_create(endpoint_t *);
     73int uhci_transfer_batch_prepare(uhci_transfer_batch_t *);
     74bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *);
     75void uhci_transfer_batch_destroy(uhci_transfer_batch_t *);
    7176
    7277/** Get offset to setup buffer accessible to the HC hw.
     
    7479 * @return Pointer to the setup buffer.
    7580 */
    76 static inline void * uhci_transfer_batch_setup_buffer(
     81static inline void *uhci_transfer_batch_setup_buffer(
    7782    const uhci_transfer_batch_t *uhci_batch)
    7883{
    7984        assert(uhci_batch);
    80         assert(uhci_batch->device_buffer);
    81         return uhci_batch->device_buffer + sizeof(qh_t) +
     85        return uhci_batch->uhci_dma_buffer.virt + sizeof(qh_t) +
    8286            uhci_batch->td_count * sizeof(td_t);
    8387}
     
    8791 * @return Pointer to the data buffer.
    8892 */
    89 static inline void * uhci_transfer_batch_data_buffer(
     93static inline void *uhci_transfer_batch_data_buffer(
    9094    const uhci_transfer_batch_t *uhci_batch)
    9195{
    9296        assert(uhci_batch);
    93         assert(uhci_batch->usb_batch);
    94         return uhci_transfer_batch_setup_buffer(uhci_batch) +
    95             uhci_batch->usb_batch->setup_size;
    96 }
    97 
    98 /** Aborts the batch.
    99  * Sets error to EINTR and size off transferd data to 0, before finishing the
    100  * batch.
    101  * @param uhci_batch Batch to abort.
    102  */
    103 static inline void uhci_transfer_batch_abort(uhci_transfer_batch_t *uhci_batch)
    104 {
    105         assert(uhci_batch);
    106         assert(uhci_batch->usb_batch);
    107         uhci_batch->usb_batch->error = EINTR;
    108         uhci_batch->usb_batch->transfered_size = 0;
    109         uhci_transfer_batch_finish_dispose(uhci_batch);
     97        return uhci_batch->base.dma_buffer.virt;
    11098}
    11199
     
    120108}
    121109
     110static inline uhci_transfer_batch_t *uhci_transfer_batch_get(
     111    usb_transfer_batch_t *b)
     112{
     113        assert(b);
     114        return (uhci_transfer_batch_t *) b;
     115}
     116
    122117#endif
    123118
  • uspace/drv/bus/usb/uhci/uhci_rh.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2013 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    3940#include <usb/classes/hub.h>
    4041#include <usb/request.h>
     42#include <usb/host/endpoint.h>
    4143#include <usb/usb.h>
    4244
     
    103105        assert(batch);
    104106
    105         const usb_target_t target = {{
    106                 .address = batch->ep->address,
    107                 .endpoint = batch->ep->endpoint
    108         }};
    109107        do {
    110                 batch->error = virthub_base_request(&instance->base, target,
    111                     usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,
    112                     batch->buffer, batch->buffer_size, &batch->transfered_size);
     108                batch->error = virthub_base_request(&instance->base, batch->target,
     109                    batch->dir, (void*) batch->setup.buffer,
     110                    batch->dma_buffer.virt, batch->size, &batch->transferred_size);
    113111                if (batch->error == ENAK)
    114112                        async_usleep(instance->base.endpoint_descriptor.poll_interval * 1000);
     
    116114                //ENAK is technically an error condition
    117115        } while (batch->error == ENAK);
    118         usb_transfer_batch_finish(batch, NULL);
    119         usb_transfer_batch_destroy(batch);
     116        usb_transfer_batch_finish(batch);
    120117        return EOK;
    121118}
     
    206203        data[0] = ((value & STATUS_LINE_D_MINUS) ? 1 : 0)
    207204            | ((value & STATUS_LINE_D_PLUS) ? 2 : 0);
    208         RH_DEBUG(hub, port, "Bus state %" PRIx8 "(source %" PRIx16")\n",
     205        RH_DEBUG(hub, port, "Bus state %" PRIx8 "(source %" PRIx16")",
    209206            data[0], value);
    210207        *act_size = 1;
     
    214211#define BIT_VAL(val, bit) \
    215212        ((val & bit) ? 1 : 0)
    216 #define UHCI2USB(val, bit, feat) \
    217         (BIT_VAL(val, bit) << feat)
     213#define UHCI2USB(val, bit, mask) \
     214        (BIT_VAL(val, bit) ? (mask) : 0)
    218215
    219216/** Port status request handler.
     
    240237        const uint16_t val = pio_read_16(hub->ports[port]);
    241238        const uint32_t status = uint32_host2usb(
    242             UHCI2USB(val, STATUS_CONNECTED, USB_HUB_FEATURE_PORT_CONNECTION) |
    243             UHCI2USB(val, STATUS_ENABLED, USB_HUB_FEATURE_PORT_ENABLE) |
    244             UHCI2USB(val, STATUS_SUSPEND, USB_HUB_FEATURE_PORT_SUSPEND) |
    245             UHCI2USB(val, STATUS_IN_RESET, USB_HUB_FEATURE_PORT_RESET) |
    246             UHCI2USB(val, STATUS_ALWAYS_ONE, USB_HUB_FEATURE_PORT_POWER) |
    247             UHCI2USB(val, STATUS_LOW_SPEED, USB_HUB_FEATURE_PORT_LOW_SPEED) |
    248             UHCI2USB(val, STATUS_CONNECTED_CHANGED, USB_HUB_FEATURE_C_PORT_CONNECTION) |
    249             UHCI2USB(val, STATUS_ENABLED_CHANGED, USB_HUB_FEATURE_C_PORT_ENABLE) |
    250 //          UHCI2USB(val, STATUS_SUSPEND, USB_HUB_FEATURE_C_PORT_SUSPEND) |
    251             ((hub->reset_changed[port] ? 1 : 0) << USB_HUB_FEATURE_C_PORT_RESET)
     239            UHCI2USB(val, STATUS_CONNECTED, USB_HUB_PORT_STATUS_CONNECTION) |
     240            UHCI2USB(val, STATUS_ENABLED, USB_HUB_PORT_STATUS_ENABLE) |
     241            UHCI2USB(val, STATUS_SUSPEND, USB2_HUB_PORT_STATUS_SUSPEND) |
     242            UHCI2USB(val, STATUS_IN_RESET, USB_HUB_PORT_STATUS_RESET) |
     243            UHCI2USB(val, STATUS_ALWAYS_ONE, USB2_HUB_PORT_STATUS_POWER) |
     244            UHCI2USB(val, STATUS_LOW_SPEED, USB2_HUB_PORT_STATUS_LOW_SPEED) |
     245            UHCI2USB(val, STATUS_CONNECTED_CHANGED, USB_HUB_PORT_STATUS_C_CONNECTION) |
     246            UHCI2USB(val, STATUS_ENABLED_CHANGED, USB2_HUB_PORT_STATUS_C_ENABLE) |
     247//          UHCI2USB(val, STATUS_SUSPEND, USB2_HUB_PORT_STATUS_C_SUSPEND) |
     248            (hub->reset_changed[port] ?  USB_HUB_PORT_STATUS_C_RESET : 0)
    252249        );
    253250        RH_DEBUG(hub, port, "Port status %" PRIx32 " (source %" PRIx16
    254             "%s)\n", uint32_usb2host(status), val,
     251            "%s)", uint32_usb2host(status), val,
    255252            hub->reset_changed[port] ? "-reset" : "");
    256253        memcpy(data, &status, sizeof(status));
     
    278275        const uint16_t val = status & (~STATUS_WC_BITS);
    279276        switch (feature) {
    280         case USB_HUB_FEATURE_PORT_ENABLE:
     277        case USB2_HUB_FEATURE_PORT_ENABLE:
    281278                RH_DEBUG(hub, port, "Clear port enable (status %"
    282                     PRIx16 ")\n", status);
     279                    PRIx16 ")", status);
    283280                pio_write_16(hub->ports[port], val & ~STATUS_ENABLED);
    284281                break;
    285         case USB_HUB_FEATURE_PORT_SUSPEND:
     282        case USB2_HUB_FEATURE_PORT_SUSPEND:
    286283                RH_DEBUG(hub, port, "Clear port suspend (status %"
    287                     PRIx16 ")\n", status);
     284                    PRIx16 ")", status);
    288285                pio_write_16(hub->ports[port], val & ~STATUS_SUSPEND);
    289286                // TODO we should do resume magic
    290                 usb_log_warning("Resume is not implemented on port %u\n", port);
     287                usb_log_warning("Resume is not implemented on port %u", port);
    291288                break;
    292289        case USB_HUB_FEATURE_PORT_POWER:
    293                 RH_DEBUG(hub, port, "Clear port power (status %" PRIx16 ")\n",
     290                RH_DEBUG(hub, port, "Clear port power (status %" PRIx16 ")",
    294291                    status);
    295292                /* We are always powered */
    296                 usb_log_warning("Tried to power off port %u\n", port);
     293                usb_log_warning("Tried to power off port %u", port);
    297294                break;
    298295        case USB_HUB_FEATURE_C_PORT_CONNECTION:
    299296                RH_DEBUG(hub, port, "Clear port conn change (status %"
    300                     PRIx16 ")\n", status);
     297                    PRIx16 ")", status);
    301298                pio_write_16(hub->ports[port], val | STATUS_CONNECTED_CHANGED);
    302299                break;
    303300        case USB_HUB_FEATURE_C_PORT_RESET:
    304301                RH_DEBUG(hub, port, "Clear port reset change (status %"
    305                     PRIx16 ")\n", status);
     302                    PRIx16 ")", status);
    306303                hub->reset_changed[port] = false;
    307304                break;
    308         case USB_HUB_FEATURE_C_PORT_ENABLE:
     305        case USB2_HUB_FEATURE_C_PORT_ENABLE:
    309306                RH_DEBUG(hub, port, "Clear port enable change (status %"
    310                     PRIx16 ")\n", status);
     307                    PRIx16 ")", status);
    311308                pio_write_16(hub->ports[port], status | STATUS_ENABLED_CHANGED);
    312309                break;
    313         case USB_HUB_FEATURE_C_PORT_SUSPEND:
     310        case USB2_HUB_FEATURE_C_PORT_SUSPEND:
    314311                RH_DEBUG(hub, port, "Clear port suspend change (status %"
    315                     PRIx16 ")\n", status);
     312                    PRIx16 ")", status);
    316313                //TODO
    317314                return ENOTSUP;
    318315        case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
    319316                RH_DEBUG(hub, port, "Clear port OC change (status %"
    320                     PRIx16 ")\n", status);
     317                    PRIx16 ")", status);
    321318                /* UHCI Does not report over current */
    322319                //TODO: newer chips do, but some have broken wiring
     
    324321        default:
    325322                RH_DEBUG(hub, port, "Clear unknown feature %d (status %"
    326                     PRIx16 ")\n", feature, status);
    327                 usb_log_warning("Clearing feature %d is unsupported\n",
     323                    PRIx16 ")", feature, status);
     324                usb_log_warning("Clearing feature %d is unsupported",
    328325                    feature);
    329326                return ESTALL;
     
    352349        case USB_HUB_FEATURE_PORT_RESET:
    353350                RH_DEBUG(hub, port, "Set port reset before (status %" PRIx16
    354                     ")\n", status);
     351                    ")", status);
    355352                uhci_port_reset_enable(hub->ports[port]);
    356353                hub->reset_changed[port] = true;
    357354                RH_DEBUG(hub, port, "Set port reset after (status %" PRIx16
    358                     ")\n", pio_read_16(hub->ports[port]));
    359                 break;
    360         case USB_HUB_FEATURE_PORT_SUSPEND:
     355                    ")", pio_read_16(hub->ports[port]));
     356                break;
     357        case USB2_HUB_FEATURE_PORT_SUSPEND:
    361358                RH_DEBUG(hub, port, "Set port suspend (status %" PRIx16
    362                     ")\n", status);
     359                    ")", status);
    363360                pio_write_16(hub->ports[port],
    364361                    (status & ~STATUS_WC_BITS) | STATUS_SUSPEND);
    365                 usb_log_warning("Suspend is not implemented on port %u\n", port);
     362                usb_log_warning("Suspend is not implemented on port %u", port);
    366363                break;
    367364        case USB_HUB_FEATURE_PORT_POWER:
    368365                RH_DEBUG(hub, port, "Set port power (status %" PRIx16
    369                     ")\n", status);
     366                    ")", status);
    370367                /* We are always powered */
    371                 usb_log_warning("Tried to power port %u\n", port);
     368                usb_log_warning("Tried to power port %u", port);
    372369                break;
    373370        case USB_HUB_FEATURE_C_PORT_CONNECTION:
    374         case USB_HUB_FEATURE_C_PORT_ENABLE:
    375         case USB_HUB_FEATURE_C_PORT_SUSPEND:
     371        case USB2_HUB_FEATURE_C_PORT_ENABLE:
     372        case USB2_HUB_FEATURE_C_PORT_SUSPEND:
    376373        case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
    377374                RH_DEBUG(hub, port, "Set port change flag (status %" PRIx16
    378                     ")\n", status);
     375                    ")", status);
    379376                /* These are voluntary and don't have to be set
    380377                 * there is no way we could do it on UHCI anyway */
     
    382379        default:
    383380                RH_DEBUG(hub, port, "Set unknown feature %d (status %" PRIx16
    384                     ")\n", feature, status);
    385                 usb_log_warning("Setting feature %d is unsupported\n",
     381                    ")", feature, status);
     382                usb_log_warning("Setting feature %d is unsupported",
    386383                    feature);
    387384                return ESTALL;
     
    422419                RH_DEBUG(hub, -1, "Event mask %" PRIx8
    423420                    " (status_a %" PRIx16 "%s),"
    424                     " (status_b %" PRIx16 "%s)\n", status,
     421                    " (status_b %" PRIx16 "%s)", status,
    425422                    status_a, hub->reset_changed[0] ? "-reset" : "",
    426423                    status_b, hub->reset_changed[1] ? "-reset" : "" );
Note: See TracChangeset for help on using the changeset viewer.