Changeset df6ded8 in mainline for uspace/drv/bus


Ignore:
Timestamp:
2018-02-28T16:37:50Z (8 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/fix-logger-deadlock, 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
Files:
42 added
2 deleted
61 edited
2 moved

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/ehci/Makefile

    rf5e5f73 rdf6ded8  
    3535SOURCES = \
    3636        ehci_batch.c \
    37         ehci_endpoint.c \
     37        ehci_bus.c \
    3838        ehci_rh.c \
    3939        endpoint_list.c \
  • uspace/drv/bus/usb/ehci/ehci_batch.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2014 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4243#include <usb/usb.h>
    4344#include <usb/debug.h>
    44 #include <usb/host/utils/malloc32.h>
    4545
    4646#include "ehci_batch.h"
    47 #include "ehci_endpoint.h"
     47#include "ehci_bus.h"
    4848
    4949/* The buffer pointer list in the qTD is long enough to support a maximum
     
    5353#define EHCI_TD_MAX_TRANSFER   (16 * 1024)
    5454
    55 static void (*const batch_setup[])(ehci_transfer_batch_t*, usb_direction_t);
     55static void (*const batch_setup[])(ehci_transfer_batch_t*);
    5656
    5757/** Safely destructs ehci_transfer_batch_t structure
     
    5959 * @param[in] ehci_batch Instance to destroy.
    6060 */
    61 static void ehci_transfer_batch_dispose(ehci_transfer_batch_t *ehci_batch)
    62 {
    63         if (!ehci_batch)
    64                 return;
    65         if (ehci_batch->tds) {
    66                 for (size_t i = 0; i < ehci_batch->td_count; ++i) {
    67                         free32(ehci_batch->tds[i]);
    68                 }
    69                 free(ehci_batch->tds);
    70         }
    71         usb_transfer_batch_destroy(ehci_batch->usb_batch);
    72         free32(ehci_batch->device_buffer);
     61void ehci_transfer_batch_destroy(ehci_transfer_batch_t *ehci_batch)
     62{
     63        assert(ehci_batch);
     64        dma_buffer_free(&ehci_batch->ehci_dma_buffer);
     65        usb_log_debug2("Batch(%p): disposed", ehci_batch);
    7366        free(ehci_batch);
    74         usb_log_debug2("Batch(%p): disposed", ehci_batch);
    75 }
    76 
    77 /** Finishes usb_transfer_batch and destroys the structure.
    78  *
    79  * @param[in] uhci_batch Instance to finish and destroy.
    80  */
    81 void ehci_transfer_batch_finish_dispose(ehci_transfer_batch_t *ehci_batch)
    82 {
    83         assert(ehci_batch);
    84         assert(ehci_batch->usb_batch);
    85         usb_transfer_batch_finish(ehci_batch->usb_batch,
    86             ehci_batch->device_buffer + ehci_batch->usb_batch->setup_size);
    87         ehci_transfer_batch_dispose(ehci_batch);
    8867}
    8968
     
    9473 * NULL otherwise.
    9574 *
     75 */
     76ehci_transfer_batch_t * ehci_transfer_batch_create(endpoint_t *ep)
     77{
     78        assert(ep);
     79
     80        ehci_transfer_batch_t *ehci_batch = calloc(1, sizeof(ehci_transfer_batch_t));
     81        if (!ehci_batch) {
     82                usb_log_error("Failed to allocate EHCI batch data.");
     83                return NULL;
     84        }
     85
     86        usb_transfer_batch_init(&ehci_batch->base, ep);
     87
     88        return ehci_batch;
     89}
     90
     91/** Prepares a batch to be sent.
     92 *
    9693 * Determines the number of needed transfer descriptors (TDs).
    9794 * Prepares a transport buffer (that is accessible by the hardware).
    9895 * Initializes parameters needed for the transfer and callback.
    9996 */
    100 ehci_transfer_batch_t * ehci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
    101 {
    102         assert(usb_batch);
    103 
    104         ehci_transfer_batch_t *ehci_batch =
    105             calloc(1, sizeof(ehci_transfer_batch_t));
    106         if (!ehci_batch) {
    107                 usb_log_error("Batch %p: Failed to allocate EHCI batch data.",
    108                     usb_batch);
    109                 goto dispose;
    110         }
    111         link_initialize(&ehci_batch->link);
    112         ehci_batch->td_count =
    113             (usb_batch->buffer_size + EHCI_TD_MAX_TRANSFER - 1)
    114             / EHCI_TD_MAX_TRANSFER;
     97int ehci_transfer_batch_prepare(ehci_transfer_batch_t *ehci_batch)
     98{
     99        assert(ehci_batch);
     100
     101        const size_t setup_size = (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
     102                ? USB_SETUP_PACKET_SIZE
     103                : 0;
     104
     105        const size_t size = ehci_batch->base.size;
     106
     107        /* Add TD left over by the previous transfer */
     108        ehci_batch->qh = ehci_endpoint_get(ehci_batch->base.ep)->qh;
     109
     110        /* Determine number of TDs needed */
     111        ehci_batch->td_count = (size + EHCI_TD_MAX_TRANSFER - 1)
     112                / EHCI_TD_MAX_TRANSFER;
    115113
    116114        /* Control transfer need Setup and Status stage */
    117         if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
     115        if (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) {
    118116                ehci_batch->td_count += 2;
    119117        }
    120118
    121         ehci_batch->tds = calloc(ehci_batch->td_count, sizeof(td_t*));
    122         if (!ehci_batch->tds) {
    123                 usb_log_error("Batch %p: Failed to allocate EHCI transfer "
    124                     "descriptors.", usb_batch);
    125                 goto dispose;
    126         }
    127 
    128         /* Add TD left over by the previous transfer */
    129         ehci_batch->qh = ehci_endpoint_get(usb_batch->ep)->qh;
    130 
    131         for (unsigned i = 0; i < ehci_batch->td_count; ++i) {
    132                 ehci_batch->tds[i] = malloc32(sizeof(td_t));
    133                 if (!ehci_batch->tds[i]) {
    134                         usb_log_error("Batch %p: Failed to allocate TD %d.",
    135                             usb_batch, i);
    136                         goto dispose;
    137                 }
    138                 memset(ehci_batch->tds[i], 0, sizeof(td_t));
    139         }
    140 
    141 
    142         /* Mix setup stage and data together, we have enough space */
    143         if (usb_batch->setup_size + usb_batch->buffer_size > 0) {
    144                 /* Use one buffer for setup and data stage */
    145                 ehci_batch->device_buffer =
    146                     malloc32(usb_batch->setup_size + usb_batch->buffer_size);
    147                 if (!ehci_batch->device_buffer) {
    148                         usb_log_error("Batch %p: Failed to allocate device "
    149                             "buffer", usb_batch);
    150                         goto dispose;
    151                 }
    152                 /* Copy setup data */
    153                 memcpy(ehci_batch->device_buffer, usb_batch->setup_buffer,
    154                     usb_batch->setup_size);
    155                 /* Copy generic data */
    156                 if (usb_batch->ep->direction != USB_DIRECTION_IN)
    157                         memcpy(
    158                             ehci_batch->device_buffer + usb_batch->setup_size,
    159                             usb_batch->buffer, usb_batch->buffer_size);
    160         }
    161         ehci_batch->usb_batch = usb_batch;
    162 
    163         const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);
    164         assert(batch_setup[usb_batch->ep->transfer_type]);
    165         batch_setup[usb_batch->ep->transfer_type](ehci_batch, dir);
    166 
    167         usb_log_debug("Batch %p %s " USB_TRANSFER_BATCH_FMT " initialized.\n",
    168             usb_batch, usb_str_direction(dir),
    169             USB_TRANSFER_BATCH_ARGS(*usb_batch));
    170 
    171         return ehci_batch;
    172 dispose:
    173         ehci_transfer_batch_dispose(ehci_batch);
    174         return NULL;
     119        assert(ehci_batch->td_count > 0);
     120
     121        const size_t tds_size = ehci_batch->td_count * sizeof(td_t);
     122
     123        /* Mix setup stage and TDs together, we have enough space */
     124        if (dma_buffer_alloc(&ehci_batch->ehci_dma_buffer, tds_size + setup_size)) {
     125                usb_log_error("Batch %p: Failed to allocate device buffer",
     126                    ehci_batch);
     127                return ENOMEM;
     128        }
     129
     130        /* Clean TDs */
     131        ehci_batch->tds = ehci_batch->ehci_dma_buffer.virt;
     132        memset(ehci_batch->tds, 0, tds_size);
     133
     134        /* Copy setup data */
     135        ehci_batch->setup_buffer = ehci_batch->ehci_dma_buffer.virt + tds_size;
     136        memcpy(ehci_batch->setup_buffer, ehci_batch->base.setup.buffer, setup_size);
     137
     138        /* Generic data already prepared*/
     139        ehci_batch->data_buffer = ehci_batch->base.dma_buffer.virt;
     140
     141        if (!batch_setup[ehci_batch->base.ep->transfer_type])
     142                return ENOTSUP;
     143
     144        batch_setup[ehci_batch->base.ep->transfer_type](ehci_batch);
     145
     146        usb_log_debug("Batch %p %s " USB_TRANSFER_BATCH_FMT " initialized.",
     147            ehci_batch, usb_str_direction(ehci_batch->base.dir),
     148            USB_TRANSFER_BATCH_ARGS(ehci_batch->base));
     149
     150        return EOK;
    175151}
    176152
     
    184160 * completes with the last TD.
    185161 */
    186 bool ehci_transfer_batch_is_complete(const ehci_transfer_batch_t *ehci_batch)
    187 {
    188         assert(ehci_batch);
    189         assert(ehci_batch->usb_batch);
    190 
    191         usb_log_debug("Batch %p: checking %zu td(s) for completion.\n",
    192             ehci_batch->usb_batch, ehci_batch->td_count);
    193 
    194         usb_log_debug2("Batch %p: QH: %08x:%08x:%08x:%08x:%08x:%08x.\n",
    195             ehci_batch->usb_batch,
     162bool ehci_transfer_batch_check_completed(ehci_transfer_batch_t *ehci_batch)
     163{
     164        assert(ehci_batch);
     165
     166        usb_log_debug("Batch %p: checking %zu td(s) for completion.",
     167            ehci_batch, ehci_batch->td_count);
     168
     169        usb_log_debug2("Batch %p: QH: %08x:%08x:%08x:%08x:%08x:%08x.",
     170            ehci_batch,
    196171            ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
    197172            ehci_batch->qh->status, ehci_batch->qh->current,
     
    206181
    207182        /* Assume all data got through */
    208         ehci_batch->usb_batch->transfered_size =
    209             ehci_batch->usb_batch->buffer_size;
     183        ehci_batch->base.transferred_size = ehci_batch->base.size;
    210184
    211185        /* Check all TDs */
    212186        for (size_t i = 0; i < ehci_batch->td_count; ++i) {
    213                 assert(ehci_batch->tds[i] != NULL);
    214187                usb_log_debug("Batch %p: TD %zu: %08x:%08x:%08x.",
    215                     ehci_batch->usb_batch, i,
    216                     ehci_batch->tds[i]->status, ehci_batch->tds[i]->next,
    217                     ehci_batch->tds[i]->alternate);
    218 
    219                 ehci_batch->usb_batch->error = td_error(ehci_batch->tds[i]);
    220                 if (ehci_batch->usb_batch->error == EOK) {
     188                    ehci_batch, i,
     189                    ehci_batch->tds[i].status, ehci_batch->tds[i].next,
     190                    ehci_batch->tds[i].alternate);
     191
     192                ehci_batch->base.error = td_error(&ehci_batch->tds[i]);
     193                if (ehci_batch->base.error == EOK) {
    221194                        /* If the TD got all its data through, it will report
    222195                         * 0 bytes remain, the sole exception is INPUT with
     
    231204                         * we leave the very last(unused) TD behind.
    232205                         */
    233                         ehci_batch->usb_batch->transfered_size
    234                             -= td_remain_size(ehci_batch->tds[i]);
     206                        ehci_batch->base.transferred_size
     207                            -= td_remain_size(&ehci_batch->tds[i]);
    235208                } else {
    236209                        usb_log_debug("Batch %p found error TD(%zu):%08x: %s.",
    237                             ehci_batch->usb_batch, i,
    238                             ehci_batch->tds[i]->status,
    239                             str_error_name(ehci_batch->usb_batch->error));
     210                            ehci_batch, i,
     211                            ehci_batch->tds[i].status,
     212                            str_error_name(ehci_batch->base.error));
    240213                        /* Clear possible ED HALT */
    241214                        qh_clear_halt(ehci_batch->qh);
     
    244217        }
    245218
    246         assert(ehci_batch->usb_batch->transfered_size <=
    247             ehci_batch->usb_batch->buffer_size);
     219        assert(ehci_batch->base.transferred_size <= ehci_batch->base.size);
     220
    248221        /* Clear TD pointers */
    249222        ehci_batch->qh->next = LINK_POINTER_TERM;
    250223        ehci_batch->qh->current = LINK_POINTER_TERM;
    251         usb_log_debug("Batch %p complete: %s", ehci_batch->usb_batch,
    252             str_error(ehci_batch->usb_batch->error));
     224        usb_log_debug("Batch %p complete: %s", ehci_batch,
     225            str_error(ehci_batch->base.error));
    253226
    254227        return true;
     
    262235{
    263236        assert(ehci_batch);
    264         qh_set_next_td(ehci_batch->qh, ehci_batch->tds[0]);
     237        qh_set_next_td(ehci_batch->qh,
     238            dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[0]));
    265239}
    266240
     
    268242 *
    269243 * @param[in] ehci_batch Batch structure to use.
    270  * @param[in] dir Communication direction
    271244 *
    272245 * Setup stage with toggle 0 and direction BOTH(SETUP_PID)
    273  * Data stage with alternating toggle and direction supplied by parameter.
    274  * Status stage with toggle 1 and direction supplied by parameter.
    275  */
    276 static void batch_control(ehci_transfer_batch_t *ehci_batch, usb_direction_t dir)
    277 {
    278         assert(ehci_batch);
    279         assert(ehci_batch->usb_batch);
     246 * Data stage with alternating toggle and direction
     247 * Status stage with toggle 1 and direction
     248 */
     249static void batch_control(ehci_transfer_batch_t *ehci_batch)
     250{
     251        assert(ehci_batch);
     252
     253        usb_direction_t dir = ehci_batch->base.dir;
    280254        assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
    281255
    282         usb_log_debug2("Batch %p: Control QH(%"PRIxn"): "
    283             "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch->usb_batch,
    284             addr_to_phys(ehci_batch->qh),
     256        usb_log_debug2("Batch %p: Control QH(%p): "
     257            "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch,
     258            ehci_batch->qh,
    285259            ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
    286260            ehci_batch->qh->status, ehci_batch->qh->current,
     
    292266
    293267        int toggle = 0;
    294         const char* buffer = ehci_batch->device_buffer;
    295268        const usb_direction_t data_dir = dir;
    296269        const usb_direction_t status_dir = reverse_dir[dir];
    297270
    298271        /* Setup stage */
    299         td_init(ehci_batch->tds[0], ehci_batch->tds[1], USB_DIRECTION_BOTH,
    300             buffer, ehci_batch->usb_batch->setup_size, toggle, false);
     272        td_init(&ehci_batch->tds[0],
     273            dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[1]),
     274            dma_buffer_phys(&ehci_batch->ehci_dma_buffer, ehci_batch->setup_buffer),
     275            USB_DIRECTION_BOTH, USB_SETUP_PACKET_SIZE, toggle, false);
    301276        usb_log_debug2("Batch %p: Created CONTROL SETUP TD(%"PRIxn"): "
    302             "%08x:%08x:%08x", ehci_batch->usb_batch,
    303             addr_to_phys(ehci_batch->tds[0]),
    304             ehci_batch->tds[0]->status, ehci_batch->tds[0]->next,
    305             ehci_batch->tds[0]->alternate);
    306         buffer += ehci_batch->usb_batch->setup_size;
     277            "%08x:%08x:%08x", ehci_batch,
     278            dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[0]),
     279            ehci_batch->tds[0].status, ehci_batch->tds[0].next,
     280            ehci_batch->tds[0].alternate);
    307281
    308282        /* Data stage */
    309         size_t td_current = 1;
    310         size_t remain_size = ehci_batch->usb_batch->buffer_size;
     283        unsigned td_current = 1;
     284        size_t remain_size = ehci_batch->base.size;
     285        uintptr_t buffer = dma_buffer_phys(&ehci_batch->base.dma_buffer,
     286            ehci_batch->data_buffer);
    311287        while (remain_size > 0) {
    312                 const size_t transfer_size =
    313                     min(remain_size, EHCI_TD_MAX_TRANSFER);
     288                const size_t transfer_size = min(remain_size, EHCI_TD_MAX_TRANSFER);
    314289                toggle = 1 - toggle;
    315290
    316                 td_init(ehci_batch->tds[td_current],
    317                     ehci_batch->tds[td_current + 1], data_dir, buffer,
    318                     transfer_size, toggle, false);
     291                td_init(&ehci_batch->tds[td_current],
     292                    dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[td_current + 1]),
     293                    buffer, data_dir, transfer_size, toggle, false);
    319294                usb_log_debug2("Batch %p: Created CONTROL DATA TD(%"PRIxn"): "
    320                     "%08x:%08x:%08x", ehci_batch->usb_batch,
    321                     addr_to_phys(ehci_batch->tds[td_current]),
    322                     ehci_batch->tds[td_current]->status,
    323                     ehci_batch->tds[td_current]->next,
    324                     ehci_batch->tds[td_current]->alternate);
     295                    "%08x:%08x:%08x", ehci_batch,
     296                    dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[td_current]),
     297                    ehci_batch->tds[td_current].status,
     298                    ehci_batch->tds[td_current].next,
     299                    ehci_batch->tds[td_current].alternate);
    325300
    326301                buffer += transfer_size;
     
    332307        /* Status stage */
    333308        assert(td_current == ehci_batch->td_count - 1);
    334         td_init(ehci_batch->tds[td_current], NULL, status_dir, NULL, 0, 1, true);
    335         usb_log_debug2("Batch %p: Created CONTROL STATUS TD(%"PRIxn"): "
    336             "%08x:%08x:%08x", ehci_batch->usb_batch,
    337             addr_to_phys(ehci_batch->tds[td_current]),
    338             ehci_batch->tds[td_current]->status,
    339             ehci_batch->tds[td_current]->next,
    340             ehci_batch->tds[td_current]->alternate);
     309        td_init(&ehci_batch->tds[td_current], 0, 0, status_dir, 0, 1, true);
     310        usb_log_debug2("Batch %p: Created CONTROL STATUS TD %d(%"PRIxn"): "
     311            "%08x:%08x:%08x", ehci_batch, td_current,
     312            dma_buffer_phys(&ehci_batch->ehci_dma_buffer, &ehci_batch->tds[td_current]),
     313            ehci_batch->tds[td_current].status,
     314            ehci_batch->tds[td_current].next,
     315            ehci_batch->tds[td_current].alternate);
    341316}
    342317
     
    349324 * EHCI hw in ED.
    350325 */
    351 static void batch_data(ehci_transfer_batch_t *ehci_batch, usb_direction_t dir)
    352 {
    353         assert(ehci_batch);
    354         assert(ehci_batch->usb_batch);
    355         assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
    356 
    357         usb_log_debug2("Batch %p: Data QH(%"PRIxn"): "
    358             "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch->usb_batch,
    359             addr_to_phys(ehci_batch->qh),
     326static void batch_data(ehci_transfer_batch_t *ehci_batch)
     327{
     328        assert(ehci_batch);
     329
     330        usb_log_debug2("Batch %p: Data QH(%p): "
     331            "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch,
     332            ehci_batch->qh,
    360333            ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
    361334            ehci_batch->qh->status, ehci_batch->qh->current,
     
    363336
    364337        size_t td_current = 0;
    365         size_t remain_size = ehci_batch->usb_batch->buffer_size;
    366         char *buffer = ehci_batch->device_buffer;
     338        size_t remain_size = ehci_batch->base.size;
     339        uintptr_t buffer = dma_buffer_phys(&ehci_batch->base.dma_buffer,
     340            ehci_batch->data_buffer);
    367341        while (remain_size > 0) {
    368342                const size_t transfer_size = remain_size > EHCI_TD_MAX_TRANSFER
     
    370344
    371345                const bool last = (remain_size == transfer_size);
    372                 td_init(
    373                     ehci_batch->tds[td_current],
    374                     last ? NULL : ehci_batch->tds[td_current + 1],
    375                     dir, buffer, transfer_size, -1, last);
     346                td_init(&ehci_batch->tds[td_current],
     347                    last ? 0 : dma_buffer_phys(&ehci_batch->ehci_dma_buffer,
     348                            &ehci_batch->tds[td_current + 1]),
     349                    buffer, ehci_batch->base.dir, transfer_size, -1, last);
    376350
    377351                usb_log_debug2("Batch %p: DATA TD(%"PRIxn": %08x:%08x:%08x",
    378                     ehci_batch->usb_batch,
    379                     addr_to_phys(ehci_batch->tds[td_current]),
    380                     ehci_batch->tds[td_current]->status,
    381                     ehci_batch->tds[td_current]->next,
    382                     ehci_batch->tds[td_current]->alternate);
     352                    ehci_batch,
     353                    dma_buffer_phys(&ehci_batch->ehci_dma_buffer,
     354                        &ehci_batch->tds[td_current]),
     355                    ehci_batch->tds[td_current].status,
     356                    ehci_batch->tds[td_current].next,
     357                    ehci_batch->tds[td_current].alternate);
    383358
    384359                buffer += transfer_size;
     
    390365
    391366/** Transfer setup table. */
    392 static void (*const batch_setup[])(ehci_transfer_batch_t*, usb_direction_t) =
     367static void (*const batch_setup[])(ehci_transfer_batch_t*) =
    393368{
    394369        [USB_TRANSFER_CONTROL] = batch_control,
  • uspace/drv/bus/usb/ehci/ehci_batch.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2014 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    3940#include <stdbool.h>
    4041#include <usb/host/usb_transfer_batch.h>
     42#include <usb/dma_buffer.h>
    4143
    4244#include "hw_struct/queue_head.h"
     
    4547/** EHCI specific data required for USB transfer */
    4648typedef struct ehci_transfer_batch {
    47         /** Link */
    48         link_t link;
     49        usb_transfer_batch_t base;
     50        /** Number of TDs used by the transfer */
     51        size_t td_count;
    4952        /** Endpoint descriptor of the target endpoint. */
    5053        qh_t *qh;
    51         /** List of TDs needed for the transfer */
    52         td_t **tds;
    53         /** Number of TDs used by the transfer */
    54         size_t td_count;
    55         /** Data buffer, must be accessible by the EHCI hw. */
    56         char *device_buffer;
     54        /** Backend for TDs and setup data. */
     55        dma_buffer_t ehci_dma_buffer;
     56        /** List of TDs needed for the transfer - backed by dma_buffer */
     57        td_t *tds;
     58        /** Data buffers - backed by dma_buffer */
     59        void *setup_buffer;
     60        void *data_buffer;
    5761        /** Generic USB transfer structure */
    5862        usb_transfer_batch_t *usb_batch;
    5963} ehci_transfer_batch_t;
    6064
    61 ehci_transfer_batch_t * ehci_transfer_batch_get(usb_transfer_batch_t *batch);
    62 bool ehci_transfer_batch_is_complete(const ehci_transfer_batch_t *batch);
     65ehci_transfer_batch_t *ehci_transfer_batch_create(endpoint_t *ep);
     66int ehci_transfer_batch_prepare(ehci_transfer_batch_t *batch);
    6367void ehci_transfer_batch_commit(const ehci_transfer_batch_t *batch);
    64 void ehci_transfer_batch_finish_dispose(ehci_transfer_batch_t *batch);
     68bool ehci_transfer_batch_check_completed(ehci_transfer_batch_t *batch);
     69void ehci_transfer_batch_destroy(ehci_transfer_batch_t *batch);
    6570
    66 static inline ehci_transfer_batch_t *ehci_transfer_batch_from_link(link_t *l)
     71static inline ehci_transfer_batch_t *ehci_transfer_batch_get(
     72    usb_transfer_batch_t *usb_batch)
    6773{
    68         assert(l);
    69         return list_get_instance(l, ehci_transfer_batch_t, link);
     74        assert(usb_batch);
     75
     76        return (ehci_transfer_batch_t *) usb_batch;
    7077}
     78
    7179#endif
    7280/**
  • uspace/drv/bus/usb/ehci/ehci_bus.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    3233 * @brief EHCI driver
    3334 */
    34 #ifndef DRV_EHCI_HCD_ENDPOINT_H
    35 #define DRV_EHCI_HCD_ENDPOINT_H
     35#ifndef DRV_EHCI_HCD_BUS_H
     36#define DRV_EHCI_HCD_BUS_H
    3637
    3738#include <assert.h>
    3839#include <adt/list.h>
     40#include <usb/host/usb2_bus.h>
    3941#include <usb/host/endpoint.h>
    40 #include <usb/host/hcd.h>
     42#include <usb/dma_buffer.h>
    4143
    4244#include "hw_struct/queue_head.h"
    43 #include "hw_struct/transfer_descriptor.h"
    4445
    4546/** Connector structure linking ED to to prepared TD. */
    4647typedef struct ehci_endpoint {
    47         /** EHCI endpoint descriptor */
     48        /* Inheritance */
     49        endpoint_t base;
     50
     51        /** EHCI endpoint descriptor, backed by dma_buffer */
    4852        qh_t *qh;
    49         /** Linked list used by driver software */
    50         link_t link;
     53       
     54        dma_buffer_t dma_buffer;
     55
     56        /** Link in endpoint_list */
     57        link_t eplist_link;
     58
     59        /** Link in pending_endpoints */
     60        link_t pending_link;
    5161} ehci_endpoint_t;
    5262
    53 errno_t ehci_endpoint_init(hcd_t *hcd, endpoint_t *ep);
    54 void ehci_endpoint_fini(hcd_t *hcd, endpoint_t *ep);
     63typedef struct hc hc_t;
     64
     65typedef struct {
     66        bus_t base;
     67        usb2_bus_helper_t helper;
     68        hc_t *hc;
     69} ehci_bus_t;
     70
     71void ehci_ep_toggle_reset(endpoint_t *);
     72void ehci_bus_prepare_ops(void);
     73
     74errno_t ehci_bus_init(ehci_bus_t *, hc_t *);
    5575
    5676/** Get and convert assigned ehci_endpoint_t structure
    5777 * @param[in] ep USBD endpoint structure.
    58  * @return Pointer to assigned hcd endpoint structure
     78 * @return Pointer to assigned ehci endpoint structure
    5979 */
    60 static inline ehci_endpoint_t * ehci_endpoint_get(const endpoint_t *ep)
     80static inline ehci_endpoint_t *ehci_endpoint_get(const endpoint_t *ep)
    6181{
    6282        assert(ep);
    63         return ep->hc_data.data;
     83        return (ehci_endpoint_t *) ep;
    6484}
    6585
    66 static inline ehci_endpoint_t * ehci_endpoint_list_instance(link_t *l)
     86static inline ehci_endpoint_t *ehci_endpoint_list_instance(link_t *l)
    6787{
    68         return list_get_instance(l, ehci_endpoint_t, link);
     88        return list_get_instance(l, ehci_endpoint_t, eplist_link);
    6989}
    7090
     
    7393 * @}
    7494 */
    75 
  • uspace/drv/bus/usb/ehci/ehci_rh.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2013 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    100101 */
    101102errno_t ehci_rh_init(ehci_rh_t *instance, ehci_caps_regs_t *caps, ehci_regs_t *regs,
    102     const char *name)
     103    fibril_mutex_t *guard, const char *name)
    103104{
    104105        assert(instance);
     
    107108            (EHCI_RD(caps->hcsparams) >> EHCI_CAPS_HCS_N_PORTS_SHIFT) &
    108109            EHCI_CAPS_HCS_N_PORTS_MASK;
    109         usb_log_debug2("RH(%p): hcsparams: %x.\n", instance,
     110        usb_log_debug2("RH(%p): hcsparams: %x.", instance,
    110111            EHCI_RD(caps->hcsparams));
    111         usb_log_info("RH(%p): Found %u ports.\n", instance,
     112        usb_log_info("RH(%p): Found %u ports.", instance,
    112113            instance->port_count);
    113114
     
    127128
    128129        ehci_rh_hub_desc_init(instance, EHCI_RD(caps->hcsparams));
    129         instance->unfinished_interrupt_transfer = NULL;
     130        instance->guard = guard;
     131        instance->status_change_endpoint = NULL;
    130132
    131133        return virthub_base_init(&instance->base, name, &ops, instance,
     
    144146        assert(instance);
    145147        assert(batch);
    146         const usb_target_t target = {{
    147                 .address = batch->ep->address,
    148                 .endpoint = batch->ep->endpoint,
    149         }};
    150         batch->error = virthub_base_request(&instance->base, target,
    151             usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,
    152             batch->buffer, batch->buffer_size, &batch->transfered_size);
     148        batch->error = virthub_base_request(&instance->base, batch->target,
     149            batch->dir, (void*) batch->setup.buffer,
     150            batch->dma_buffer.virt, batch->size,
     151            &batch->transferred_size);
    153152        if (batch->error == ENAK) {
    154153                usb_log_debug("RH(%p): BATCH(%p) adding as unfinished",
    155154                    instance, batch);
    156                 /* This is safe because only status change interrupt transfers
    157                  * return NAK. The assertion holds true because the batch
    158                  * existence prevents communication with that ep */
    159                 assert(instance->unfinished_interrupt_transfer == NULL);
    160                 instance->unfinished_interrupt_transfer = batch;
     155
     156                /* Lock the HC guard */
     157                fibril_mutex_lock(instance->guard);
     158                const int err = endpoint_activate_locked(batch->ep, batch);
     159                if (err) {
     160                        fibril_mutex_unlock(batch->ep->guard);
     161                        return err;
     162                }
     163
     164                /*
     165                 * Asserting that the HC do not run two instances of the status
     166                 * change endpoint - shall be true.
     167                 */
     168                assert(!instance->status_change_endpoint);
     169
     170                endpoint_add_ref(batch->ep);
     171                instance->status_change_endpoint = batch->ep;
     172                fibril_mutex_unlock(instance->guard);
    161173        } else {
    162                 usb_transfer_batch_finish(batch, NULL);
    163                 usb_transfer_batch_destroy(batch);
    164174                usb_log_debug("RH(%p): BATCH(%p) virtual request complete: %s",
    165175                    instance, batch, str_error(batch->error));
     176                usb_transfer_batch_finish(batch);
    166177        }
    167178        return EOK;
     
    177188errno_t ehci_rh_interrupt(ehci_rh_t *instance)
    178189{
    179         //TODO atomic swap needed
    180         usb_transfer_batch_t *batch = instance->unfinished_interrupt_transfer;
    181         instance->unfinished_interrupt_transfer = NULL;
    182         usb_log_debug2("RH(%p): Interrupt. Processing batch: %p",
    183             instance, batch);
     190        fibril_mutex_lock(instance->guard);
     191        endpoint_t *ep = instance->status_change_endpoint;
     192        if (!ep) {
     193                fibril_mutex_unlock(instance->guard);
     194                return EOK;
     195        }
     196
     197        usb_transfer_batch_t * const batch = ep->active_batch;
     198        endpoint_deactivate_locked(ep);
     199        instance->status_change_endpoint = NULL;
     200        fibril_mutex_unlock(instance->guard);
     201
     202        endpoint_del_ref(ep);
     203
    184204        if (batch) {
    185                 const usb_target_t target = {{
    186                         .address = batch->ep->address,
    187                         .endpoint = batch->ep->endpoint,
    188                 }};
    189                 batch->error = virthub_base_request(&instance->base, target,
    190                     usb_transfer_batch_direction(batch),
    191                     (void*)batch->setup_buffer,
    192                     batch->buffer, batch->buffer_size, &batch->transfered_size);
    193                 usb_transfer_batch_finish(batch, NULL);
    194                 usb_transfer_batch_destroy(batch);
     205                usb_log_debug2("RH(%p): Interrupt. Processing batch: %p",
     206                    instance, batch);
     207                batch->error = virthub_base_request(&instance->base, batch->target,
     208                    batch->dir, (void*) batch->setup.buffer,
     209                    batch->dma_buffer.virt, batch->size,
     210                    &batch->transferred_size);
     211                usb_transfer_batch_finish(batch);
    195212        }
    196213        return EOK;
     
    258275
    259276#define BIT_VAL(val, bit)   ((val & bit) ? 1 : 0)
    260 #define EHCI2USB(val, bit, feat)   (BIT_VAL(val, bit) << feat)
     277#define EHCI2USB(val, bit, mask)   (BIT_VAL(val, bit) ? mask : 0)
    261278
    262279/** Port status request handler.
     
    280297        const uint32_t reg = EHCI_RD(hub->registers->portsc[port]);
    281298        const uint32_t status = uint32_host2usb(
    282             EHCI2USB(reg, USB_PORTSC_CONNECT_FLAG, USB_HUB_FEATURE_PORT_CONNECTION) |
    283             EHCI2USB(reg, USB_PORTSC_ENABLED_FLAG, USB_HUB_FEATURE_PORT_ENABLE) |
    284             EHCI2USB(reg, USB_PORTSC_SUSPEND_FLAG, USB_HUB_FEATURE_PORT_SUSPEND) |
    285             EHCI2USB(reg, USB_PORTSC_OC_ACTIVE_FLAG, USB_HUB_FEATURE_PORT_OVER_CURRENT) |
    286             EHCI2USB(reg, USB_PORTSC_PORT_RESET_FLAG, USB_HUB_FEATURE_PORT_RESET) |
    287             EHCI2USB(reg, USB_PORTSC_PORT_POWER_FLAG, USB_HUB_FEATURE_PORT_POWER) |
     299            EHCI2USB(reg, USB_PORTSC_CONNECT_FLAG, USB_HUB_PORT_STATUS_CONNECTION) |
     300            EHCI2USB(reg, USB_PORTSC_ENABLED_FLAG, USB_HUB_PORT_STATUS_ENABLE) |
     301            EHCI2USB(reg, USB_PORTSC_SUSPEND_FLAG, USB2_HUB_PORT_STATUS_SUSPEND) |
     302            EHCI2USB(reg, USB_PORTSC_OC_ACTIVE_FLAG, USB_HUB_PORT_STATUS_OC) |
     303            EHCI2USB(reg, USB_PORTSC_PORT_RESET_FLAG, USB_HUB_PORT_STATUS_RESET) |
     304            EHCI2USB(reg, USB_PORTSC_PORT_POWER_FLAG, USB2_HUB_PORT_STATUS_POWER) |
    288305            (((reg & USB_PORTSC_LINE_STATUS_MASK) == USB_PORTSC_LINE_STATUS_K) ?
    289                 (1 << USB_HUB_FEATURE_PORT_LOW_SPEED) : 0) |
    290             ((reg & USB_PORTSC_PORT_OWNER_FLAG) ? 0 : (1 << USB_HUB_FEATURE_PORT_HIGH_SPEED)) |
    291             EHCI2USB(reg, USB_PORTSC_PORT_TEST_MASK, 11) |
    292             EHCI2USB(reg, USB_PORTSC_INDICATOR_MASK, 12) |
    293             EHCI2USB(reg, USB_PORTSC_CONNECT_CH_FLAG, USB_HUB_FEATURE_C_PORT_CONNECTION) |
    294             EHCI2USB(reg, USB_PORTSC_EN_CHANGE_FLAG, USB_HUB_FEATURE_C_PORT_ENABLE) |
    295             (hub->resume_flag[port] ? (1 << USB_HUB_FEATURE_C_PORT_SUSPEND) : 0) |
    296             EHCI2USB(reg, USB_PORTSC_OC_CHANGE_FLAG, USB_HUB_FEATURE_C_PORT_OVER_CURRENT) |
    297             (hub->reset_flag[port] ? (1 << USB_HUB_FEATURE_C_PORT_RESET): 0)
     306                (USB2_HUB_PORT_STATUS_LOW_SPEED) : 0) |
     307            ((reg & USB_PORTSC_PORT_OWNER_FLAG) ? 0 : USB2_HUB_PORT_STATUS_HIGH_SPEED) |
     308            EHCI2USB(reg, USB_PORTSC_PORT_TEST_MASK, USB2_HUB_PORT_STATUS_TEST) |
     309            EHCI2USB(reg, USB_PORTSC_INDICATOR_MASK, USB2_HUB_PORT_STATUS_INDICATOR) |
     310            EHCI2USB(reg, USB_PORTSC_CONNECT_CH_FLAG, USB_HUB_PORT_STATUS_C_CONNECTION) |
     311            EHCI2USB(reg, USB_PORTSC_EN_CHANGE_FLAG, USB2_HUB_PORT_STATUS_C_ENABLE) |
     312            (hub->resume_flag[port] ? USB2_HUB_PORT_STATUS_C_SUSPEND : 0) |
     313            EHCI2USB(reg, USB_PORTSC_OC_CHANGE_FLAG, USB_HUB_PORT_STATUS_C_OC) |
     314            (hub->reset_flag[port] ? USB_HUB_PORT_STATUS_C_RESET: 0)
    298315        );
    299316        /* Note feature numbers for test and indicator feature do not
     
    396413                return EOK;
    397414
    398         case USB_HUB_FEATURE_PORT_ENABLE:         /*1*/
     415        case USB2_HUB_FEATURE_PORT_ENABLE:         /*1*/
    399416                usb_log_debug2("RH(%p-%u): Clear port enable.", hub, port);
    400417                EHCI_CLR(hub->registers->portsc[port],
     
    402419                return EOK;
    403420
    404         case USB_HUB_FEATURE_PORT_SUSPEND:        /*2*/
     421        case USB2_HUB_FEATURE_PORT_SUSPEND:        /*2*/
    405422                usb_log_debug2("RH(%p-%u): Clear port suspend.", hub, port);
    406423                /* If not in suspend it's noop */
     
    420437                    USB_PORTSC_CONNECT_CH_FLAG);
    421438                return EOK;
    422         case USB_HUB_FEATURE_C_PORT_ENABLE:       /*17*/
     439        case USB2_HUB_FEATURE_C_PORT_ENABLE:       /*17*/
    423440                usb_log_debug2("RH(%p-%u): Clear port enable change.",
    424441                    hub, port);
     
    432449                    USB_PORTSC_OC_CHANGE_FLAG);
    433450                return EOK;
    434         case USB_HUB_FEATURE_C_PORT_SUSPEND:      /*18*/
     451        case USB2_HUB_FEATURE_C_PORT_SUSPEND:      /*18*/
    435452                usb_log_debug2("RH(%p-%u): Clear port suspend change.",
    436453                    hub, port);
     
    467484        const unsigned feature = uint16_usb2host(setup_packet->value);
    468485        switch (feature) {
    469         case USB_HUB_FEATURE_PORT_ENABLE:  /*1*/
     486        case USB2_HUB_FEATURE_PORT_ENABLE:  /*1*/
    470487                usb_log_debug2("RH(%p-%u): Set port enable.", hub, port);
    471488                EHCI_SET(hub->registers->portsc[port],
    472489                    USB_PORTSC_ENABLED_FLAG);
    473490                return EOK;
    474         case USB_HUB_FEATURE_PORT_SUSPEND: /*2*/
     491        case USB2_HUB_FEATURE_PORT_SUSPEND: /*2*/
    475492                usb_log_debug2("RH(%p-%u): Set port suspend.", hub, port);
    476493                EHCI_SET(hub->registers->portsc[port],
  • uspace/drv/bus/usb/ehci/ehci_rh.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2013 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    6162                uint8_t rempow[STATUS_BYTES(EHCI_MAX_PORTS) * 2];
    6263        } __attribute__((packed)) hub_descriptor;
    63         /** interrupt transfer waiting for an actual interrupt to occur */
    64         usb_transfer_batch_t *unfinished_interrupt_transfer;
    6564        bool reset_flag[EHCI_MAX_PORTS];
    6665        bool resume_flag[EHCI_MAX_PORTS];
     66
     67        /* HC guard */
     68        fibril_mutex_t *guard;
     69
     70        /*
     71         * This is sort of hacky, but better than duplicating functionality.
     72         * We cannot simply store a pointer to a transfer in-progress, in order
     73         * to allow it to be aborted. We can however store a reference to the
     74         * Status Change Endpoint. Note that this is mixing two worlds together
     75         * - otherwise, the RH is "a device" and have no clue about HC, apart
     76         * from accessing its registers.
     77         */
     78        endpoint_t *status_change_endpoint;
     79
    6780} ehci_rh_t;
    6881
    69 errno_t ehci_rh_init(ehci_rh_t *instance, ehci_caps_regs_t *caps, ehci_regs_t *regs,
    70     const char *name);
     82errno_t ehci_rh_init(ehci_rh_t *instance, ehci_caps_regs_t *caps,
     83    ehci_regs_t *regs, fibril_mutex_t *guard, const char *name);
    7184errno_t ehci_rh_schedule(ehci_rh_t *instance, usb_transfer_batch_t *batch);
    7285errno_t ehci_rh_interrupt(ehci_rh_t *instance);
  • uspace/drv/bus/usb/ehci/endpoint_list.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2014 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    5455        assert(instance);
    5556        instance->name = name;
    56         instance->list_head = malloc32(sizeof(qh_t));
    57         if (!instance->list_head) {
     57        if (dma_buffer_alloc(&instance->dma_buffer, sizeof(qh_t))) {
    5858                usb_log_error("EPL(%p-%s): Failed to allocate list head.",
    5959                    instance, name);
    6060                return ENOMEM;
    6161        }
     62        instance->list_head = instance->dma_buffer.virt;
    6263        qh_init(instance->list_head, NULL);
    6364
     
    9596{
    9697        assert(instance);
     98        assert(instance->list_head);
    9799        assert(ep);
    98100        assert(ep->qh);
    99         usb_log_debug2("EPL(%p-%s): Append endpoint(%p).\n",
     101        usb_log_debug2("EPL(%p-%s): Append endpoint(%p).",
    100102            instance, instance->name, ep);
    101103
     
    124126        write_barrier();
    125127        /* Add to the sw list */
    126         list_append(&ep->link, &instance->endpoint_list);
     128        list_append(&ep->eplist_link, &instance->endpoint_list);
    127129
    128130        ehci_endpoint_t *first = ehci_endpoint_list_instance(
    129131            list_first(&instance->endpoint_list));
    130         usb_log_debug("EPL(%p-%s): EP(%p) added to list, first is %p(%p).\n",
     132        usb_log_debug("EPL(%p-%s): EP(%p) added to list, first is %p(%p).",
    131133            instance, instance->name, ep, first, first->qh);
    132134        if (last_qh == instance->list_head) {
    133                 usb_log_debug2("EPL(%p-%s): head EP(%p-%"PRIxn"): %x:%x.\n",
     135                usb_log_debug2("EPL(%p-%s): head EP(%p-%"PRIxn"): %x:%x.",
    134136                    instance, instance->name, last_qh,
    135137                    addr_to_phys(instance->list_head),
     
    153155        fibril_mutex_lock(&instance->guard);
    154156
    155         usb_log_debug2("EPL(%p-%s): removing EP(%p).\n",
     157        usb_log_debug2("EPL(%p-%s): removing EP(%p).",
    156158            instance, instance->name, ep);
    157159
     
    159161        qh_t *prev_qh;
    160162        /* Remove from the hardware queue */
    161         if (list_first(&instance->endpoint_list) == &ep->link) {
     163        if (list_first(&instance->endpoint_list) == &ep->eplist_link) {
    162164                /* I'm the first one here */
    163165                prev_qh = instance->list_head;
    164166                qpos = "FIRST";
    165167        } else {
    166                 prev_qh = ehci_endpoint_list_instance(ep->link.prev)->qh;
     168                prev_qh = ehci_endpoint_list_instance(ep->eplist_link.prev)->qh;
    167169                qpos = "NOT FIRST";
    168170        }
     
    172174        write_barrier();
    173175
    174         usb_log_debug("EPL(%p-%s): EP(%p) removed (%s), horizontal %x.\n",
     176        usb_log_debug("EPL(%p-%s): EP(%p) removed (%s), horizontal %x.",
    175177            instance, instance->name,  ep, qpos, ep->qh->horizontal);
    176178
    177179        /* Remove from the endpoint list */
    178         list_remove(&ep->link);
     180        list_remove(&ep->eplist_link);
    179181        fibril_mutex_unlock(&instance->guard);
    180182}
  • uspace/drv/bus/usb/ehci/endpoint_list.h

    rf5e5f73 rdf6ded8  
    3838#include <assert.h>
    3939#include <fibril_synch.h>
    40 #include <usb/host/utils/malloc32.h>
    4140
    42 #include "ehci_endpoint.h"
     41#include "ehci_bus.h"
    4342#include "hw_struct/queue_head.h"
    4443
     
    4948        /** EHCI hw structure at the beginning of the queue */
    5049        qh_t *list_head;
     50        dma_buffer_t dma_buffer;
    5151        /** Assigned name, provides nicer debug output */
    5252        const char *name;
     
    6464{
    6565        assert(instance);
    66         free32(instance->list_head);
     66        dma_buffer_free(&instance->dma_buffer);
    6767        instance->list_head = NULL;
    6868}
  • uspace/drv/bus/usb/ehci/hc.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4546#include <usb/debug.h>
    4647#include <usb/usb.h>
    47 #include <usb/host/utils/malloc32.h>
     48#include <usb/host/utility.h>
    4849
    4950#include "ehci_batch.h"
     
    8990};
    9091
    91 static void hc_start(hc_t *instance);
    9292static errno_t hc_init_memory(hc_t *instance);
    9393
     
    100100 * @return Error code.
    101101 */
    102 errno_t ehci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     102errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
    103103{
    104104        assert(code);
    105105        assert(hw_res);
     106        hc_t *instance = hcd_to_hc(hcd);
    106107
    107108        if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1)
     
    130131
    131132        memcpy(code->cmds, ehci_irq_commands, sizeof(ehci_irq_commands));
    132         ehci_caps_regs_t *caps = NULL;
    133 
    134         errno_t ret = pio_enable_range(&regs, (void**)&caps);
    135         if (ret != EOK) {
    136                 free(code->ranges);
    137                 free(code->cmds);
    138                 return ret;
    139         }
    140133
    141134        ehci_regs_t *registers =
    142             (ehci_regs_t *)(RNGABSPTR(regs) + EHCI_RD8(caps->caplength));
     135                (ehci_regs_t *)(RNGABSPTR(regs) + EHCI_RD8(instance->caps->caplength));
    143136        code->cmds[0].addr = (void *) &registers->usbsts;
    144137        code->cmds[3].addr = (void *) &registers->usbsts;
    145138        EHCI_WR(code->cmds[1].value, EHCI_USED_INTERRUPTS);
    146139
    147         usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
     140        usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.",
    148141            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    149142
     
    159152 * @return Error code
    160153 */
    161 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    162 {
    163         assert(instance);
     154errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
     155{
     156        hc_t *instance = hcd_to_hc(hcd);
    164157        assert(hw_res);
    165158        if (hw_res->mem_ranges.count != 1 ||
     
    172165        if (ret != EOK) {
    173166                usb_log_error("HC(%p): Failed to gain access to device "
    174                     "registers: %s.\n", instance, str_error(ret));
     167                    "registers: %s.", instance, str_error(ret));
    175168                return ret;
    176169        }
     170
    177171        usb_log_info("HC(%p): Device registers at %"PRIx64" (%zuB) accessible.",
    178172            instance, hw_res->mem_ranges.ranges[0].address.absolute,
     
    184178            + EHCI_RD8(instance->caps->caplength));
    185179
    186         list_initialize(&instance->pending_batches);
     180        list_initialize(&instance->pending_endpoints);
    187181        fibril_mutex_initialize(&instance->guard);
    188182        fibril_condvar_initialize(&instance->async_doorbell);
     
    197191        usb_log_info("HC(%p): Initializing RH(%p).", instance, &instance->rh);
    198192        ehci_rh_init(
    199             &instance->rh, instance->caps, instance->registers, "ehci rh");
    200         usb_log_debug("HC(%p): Starting HW.", instance);
    201         hc_start(instance);
    202 
     193            &instance->rh, instance->caps, instance->registers, &instance->guard,
     194            "ehci rh");
     195
     196        ehci_bus_init(&instance->bus, instance);
     197        hc_device_setup(hcd, (bus_t *) &instance->bus);
    203198        return EOK;
    204199}
     
    208203 * @param[in] instance Host controller structure to use.
    209204 */
    210 void hc_fini(hc_t *instance)
    211 {
    212         assert(instance);
    213         //TODO: stop the hw
    214 #if 0
    215         endpoint_list_fini(&instance->async_list);
    216         endpoint_list_fini(&instance->int_list);
    217         return_page(instance->periodic_list_base);
    218 #endif
     205int hc_gone(hc_device_t *hcd)
     206{
     207        hc_t *hc = hcd_to_hc(hcd);
     208        endpoint_list_fini(&hc->async_list);
     209        endpoint_list_fini(&hc->int_list);
     210        dma_buffer_free(&hc->dma_buffer);
     211        return EOK;
    219212};
    220213
     
    224217        assert(ep);
    225218        ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep);
    226         usb_log_debug("HC(%p) enqueue EP(%d:%d:%s:%s)\n", instance,
    227             ep->address, ep->endpoint,
     219        usb_log_debug("HC(%p) enqueue EP(%d:%d:%s:%s)", instance,
     220            ep->device->address, ep->endpoint,
    228221            usb_str_transfer_type_short(ep->transfer_type),
    229222            usb_str_direction(ep->direction));
     
    248241        assert(ep);
    249242        ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep);
    250         usb_log_debug("HC(%p) dequeue EP(%d:%d:%s:%s)\n", instance,
    251             ep->address, ep->endpoint,
     243        usb_log_debug("HC(%p) dequeue EP(%d:%d:%s:%s)", instance,
     244            ep->device->address, ep->endpoint,
    252245            usb_str_transfer_type_short(ep->transfer_type),
    253246            usb_str_direction(ep->direction));
     
    273266}
    274267
    275 errno_t ehci_hc_status(hcd_t *hcd, uint32_t *status)
    276 {
    277         assert(hcd);
    278         hc_t *instance = hcd_get_driver_data(hcd);
    279         assert(instance);
     268errno_t ehci_hc_status(bus_t *bus_base, uint32_t *status)
     269{
     270        assert(bus_base);
    280271        assert(status);
     272
     273        ehci_bus_t *bus = (ehci_bus_t *) bus_base;
     274        hc_t *hc = bus->hc;
     275        assert(hc);
     276
    281277        *status = 0;
    282         if (instance->registers) {
    283                 *status = EHCI_RD(instance->registers->usbsts);
    284                 EHCI_WR(instance->registers->usbsts, *status);
    285         }
    286         usb_log_debug2("HC(%p): Read status: %x", instance, *status);
     278        if (hc->registers) {
     279                *status = EHCI_RD(hc->registers->usbsts);
     280                EHCI_WR(hc->registers->usbsts, *status);
     281        }
     282        usb_log_debug2("HC(%p): Read status: %x", hc, *status);
    287283        return EOK;
    288284}
     
    294290 * @return Error code.
    295291 */
    296 errno_t ehci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    297 {
    298         assert(hcd);
    299         hc_t *instance = hcd_get_driver_data(hcd);
    300         assert(instance);
     292errno_t ehci_hc_schedule(usb_transfer_batch_t *batch)
     293{
     294        assert(batch);
     295
     296        ehci_bus_t *bus = (ehci_bus_t *) endpoint_get_bus(batch->ep);
     297        hc_t *hc = bus->hc;
     298        assert(hc);
    301299
    302300        /* Check for root hub communication */
    303         if (batch->ep->address == ehci_rh_get_address(&instance->rh)) {
     301        if (batch->target.address == ehci_rh_get_address(&hc->rh)) {
    304302                usb_log_debug("HC(%p): Scheduling BATCH(%p) for RH(%p)",
    305                     instance, batch, &instance->rh);
    306                 return ehci_rh_schedule(&instance->rh, batch);
    307         }
     303                    hc, batch, &hc->rh);
     304                return ehci_rh_schedule(&hc->rh, batch);
     305        }
     306
     307        endpoint_t * const ep = batch->ep;
     308        ehci_endpoint_t * const ehci_ep = ehci_endpoint_get(ep);
    308309        ehci_transfer_batch_t *ehci_batch = ehci_transfer_batch_get(batch);
    309         if (!ehci_batch)
    310                 return ENOMEM;
    311 
    312         fibril_mutex_lock(&instance->guard);
    313         usb_log_debug2("HC(%p): Appending BATCH(%p)", instance, batch);
    314         list_append(&ehci_batch->link, &instance->pending_batches);
    315         usb_log_debug("HC(%p): Committing BATCH(%p)", instance, batch);
     310
     311        int err;
     312
     313        if ((err = ehci_transfer_batch_prepare(ehci_batch)))
     314                return err;
     315
     316        fibril_mutex_lock(&hc->guard);
     317
     318        if ((err = endpoint_activate_locked(ep, batch))) {
     319                fibril_mutex_unlock(&hc->guard);
     320                return err;
     321        }
     322
     323        usb_log_debug("HC(%p): Committing BATCH(%p)", hc, batch);
    316324        ehci_transfer_batch_commit(ehci_batch);
    317325
    318         fibril_mutex_unlock(&instance->guard);
     326        /* Enqueue endpoint to the checked list */
     327        usb_log_debug2("HC(%p): Appending BATCH(%p)", hc, batch);
     328        list_append(&ehci_ep->pending_link, &hc->pending_endpoints);
     329
     330        fibril_mutex_unlock(&hc->guard);
    319331        return EOK;
    320332}
     
    325337 * @param[in] status Value of the status register at the time of interrupt.
    326338 */
    327 void ehci_hc_interrupt(hcd_t *hcd, uint32_t status)
    328 {
    329         assert(hcd);
    330         hc_t *instance = hcd_get_driver_data(hcd);
    331         status = EHCI_RD(status);
    332         assert(instance);
    333 
    334         usb_log_debug2("HC(%p): Interrupt: %"PRIx32, instance, status);
     339void ehci_hc_interrupt(bus_t *bus_base, uint32_t status)
     340{
     341        assert(bus_base);
     342
     343        ehci_bus_t *bus = (ehci_bus_t *) bus_base;
     344        hc_t *hc = bus->hc;
     345        assert(hc);
     346
     347        usb_log_debug2("HC(%p): Interrupt: %"PRIx32, hc, status);
    335348        if (status & USB_STS_PORT_CHANGE_FLAG) {
    336                 ehci_rh_interrupt(&instance->rh);
     349                ehci_rh_interrupt(&hc->rh);
    337350        }
    338351
    339352        if (status & USB_STS_IRQ_ASYNC_ADVANCE_FLAG) {
    340                 fibril_mutex_lock(&instance->guard);
    341                 usb_log_debug2("HC(%p): Signaling doorbell", instance);
    342                 fibril_condvar_broadcast(&instance->async_doorbell);
    343                 fibril_mutex_unlock(&instance->guard);
     353                fibril_mutex_lock(&hc->guard);
     354                usb_log_debug2("HC(%p): Signaling doorbell", hc);
     355                fibril_condvar_broadcast(&hc->async_doorbell);
     356                fibril_mutex_unlock(&hc->guard);
    344357        }
    345358
    346359        if (status & (USB_STS_IRQ_FLAG | USB_STS_ERR_IRQ_FLAG)) {
    347                 fibril_mutex_lock(&instance->guard);
    348 
    349                 usb_log_debug2("HC(%p): Scanning %lu pending batches", instance,
    350                         list_count(&instance->pending_batches));
    351                 list_foreach_safe(instance->pending_batches, current, next) {
    352                         ehci_transfer_batch_t *batch =
    353                             ehci_transfer_batch_from_link(current);
    354 
    355                         if (ehci_transfer_batch_is_complete(batch)) {
     360                fibril_mutex_lock(&hc->guard);
     361
     362                usb_log_debug2("HC(%p): Scanning %lu pending endpoints", hc,
     363                        list_count(&hc->pending_endpoints));
     364                list_foreach_safe(hc->pending_endpoints, current, next) {
     365                        ehci_endpoint_t *ep
     366                                = list_get_instance(current, ehci_endpoint_t, pending_link);
     367
     368                        ehci_transfer_batch_t *batch
     369                                = ehci_transfer_batch_get(ep->base.active_batch);
     370                        assert(batch);
     371
     372                        if (ehci_transfer_batch_check_completed(batch)) {
     373                                endpoint_deactivate_locked(&ep->base);
    356374                                list_remove(current);
    357                                 ehci_transfer_batch_finish_dispose(batch);
     375                                hc_reset_toggles(&batch->base, &ehci_ep_toggle_reset);
     376                                usb_transfer_batch_finish(&batch->base);
    358377                        }
    359378                }
    360                 fibril_mutex_unlock(&instance->guard);
     379                fibril_mutex_unlock(&hc->guard);
     380
     381
    361382        }
    362383
    363384        if (status & USB_STS_HOST_ERROR_FLAG) {
    364                 usb_log_fatal("HCD(%p): HOST SYSTEM ERROR!", instance);
     385                usb_log_fatal("HCD(%p): HOST SYSTEM ERROR!", hc);
    365386                //TODO do something here
    366387        }
     
    371392 * @param[in] instance EHCI hc driver structure.
    372393 */
    373 void hc_start(hc_t *instance)
    374 {
    375         assert(instance);
     394int hc_start(hc_device_t *hcd)
     395{
     396        hc_t *instance = hcd_to_hc(hcd);
     397        usb_log_debug("HC(%p): Starting HW.", instance);
     398
    376399        /* Turn off the HC if it's running, Reseting a running device is
    377400         * undefined */
     
    404427
    405428        /* Enable periodic list */
    406         assert(instance->periodic_list_base);
     429        assert(instance->periodic_list);
    407430        uintptr_t phys_base =
    408             addr_to_phys((void*)instance->periodic_list_base);
     431            addr_to_phys((void*)instance->periodic_list);
    409432        assert((phys_base & USB_PERIODIC_LIST_BASE_MASK) == phys_base);
    410433        EHCI_WR(instance->registers->periodiclistbase, phys_base);
     
    425448        usb_log_debug("HC(%p): HW started.", instance);
    426449
    427         usb_log_debug2("HC(%p): Registers: \n"
    428             "\tUSBCMD(%p): %x(0x00080000 = at least 1ms between interrupts)\n"
    429             "\tUSBSTS(%p): %x(0x00001000 = HC halted)\n"
    430             "\tUSBINT(%p): %x(0x0 = no interrupts).\n"
    431             "\tCONFIG(%p): %x(0x0 = ports controlled by companion hc).\n",
     450        usb_log_debug2("HC(%p): Registers: "
     451            "\tUSBCMD(%p): %x(0x00080000 = at least 1ms between interrupts)"
     452            "\tUSBSTS(%p): %x(0x00001000 = HC halted)"
     453            "\tUSBINT(%p): %x(0x0 = no interrupts)."
     454            "\tCONFIG(%p): %x(0x0 = ports controlled by companion hc).",
    432455            instance,
    433456            &instance->registers->usbcmd, EHCI_RD(instance->registers->usbcmd),
     
    438461        EHCI_WR(instance->registers->usbsts, EHCI_RD(instance->registers->usbsts));
    439462        EHCI_WR(instance->registers->usbintr, EHCI_USED_INTERRUPTS);
     463
     464        return EOK;
     465}
     466
     467/**
     468 * Setup roothub as a virtual hub.
     469 */
     470int hc_setup_roothub(hc_device_t *hcd)
     471{
     472        return hc_setup_virtual_root_hub(hcd, USB_SPEED_HIGH);
    440473}
    441474
     
    473506
    474507        /* Take 1024 periodic list heads, we ignore low mem options */
    475         instance->periodic_list_base = get_page();
    476         if (!instance->periodic_list_base) {
     508        if (dma_buffer_alloc(&instance->dma_buffer, PAGE_SIZE)) {
    477509                usb_log_error("HC(%p): Failed to get ISO schedule page.",
    478510                    instance);
     
    481513                return ENOMEM;
    482514        }
     515        instance->periodic_list = instance->dma_buffer.virt;
    483516
    484517        usb_log_debug2("HC(%p): Initializing Periodic list.", instance);
    485         for (unsigned i = 0;
    486             i < PAGE_SIZE/sizeof(instance->periodic_list_base[0]); ++i)
     518        for (unsigned i = 0; i < PAGE_SIZE/sizeof(link_pointer_t); ++i)
    487519        {
    488520                /* Disable everything for now */
    489                 instance->periodic_list_base[i] =
     521                instance->periodic_list[i] =
    490522                    LINK_POINTER_QH(addr_to_phys(instance->int_list.list_head));
    491523        }
  • uspace/drv/bus/usb/ehci/hc.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    5556/** Main EHCI driver structure */
    5657typedef struct hc {
     58        /* Common device header */
     59        hc_device_t base;
     60
    5761        /** Memory mapped CAPS register area */
    5862        ehci_caps_regs_t *caps;
     
    6064        ehci_regs_t *registers;
    6165
    62         /** Iso transfer list */
    63         link_pointer_t *periodic_list_base;
     66        /** Iso transfer list, backed by dma_buffer */
     67        link_pointer_t *periodic_list;
     68
     69        dma_buffer_t dma_buffer;
    6470
    6571        /** CONTROL and BULK schedules */
     
    7076
    7177        /** List of active transfers */
    72         list_t pending_batches;
     78        list_t pending_endpoints;
    7379
    7480        /** Guards schedule and endpoint manipulation */
     
    8086        /** USB hub emulation structure */
    8187        ehci_rh_t rh;
     88
     89        /** USB bookkeeping */
     90        ehci_bus_t bus;
    8291} hc_t;
    8392
    84 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts);
    85 void hc_fini(hc_t *instance);
     93static inline hc_t *hcd_to_hc(hc_device_t *hcd)
     94{
     95        assert(hcd);
     96        return (hc_t *) hcd;
     97}
    8698
    87 void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep);
    88 void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep);
     99void hc_enqueue_endpoint(hc_t *, const endpoint_t *);
     100void hc_dequeue_endpoint(hc_t *, const endpoint_t *);
    89101
    90 errno_t ehci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq);
     102/* Boottime operations */
     103extern errno_t hc_add(hc_device_t *, const hw_res_list_parsed_t *);
     104extern errno_t hc_start(hc_device_t *);
     105extern errno_t hc_setup_roothub(hc_device_t *);
     106extern errno_t hc_gen_irq_code(irq_code_t *, hc_device_t *,
     107    const hw_res_list_parsed_t *, int *);
     108extern errno_t hc_gone(hc_device_t *);
    91109
    92 void ehci_hc_interrupt(hcd_t *hcd, uint32_t status);
    93 errno_t ehci_hc_status(hcd_t *hcd, uint32_t *status);
    94 errno_t ehci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
     110/** Runtime operations */
     111extern void ehci_hc_interrupt(bus_t *, uint32_t);
     112extern errno_t ehci_hc_status(bus_t *, uint32_t *);
     113extern errno_t ehci_hc_schedule(usb_transfer_batch_t *);
     114
    95115#endif
    96116/**
  • uspace/drv/bus/usb/ehci/hw_struct/iso_transfer_descriptor.h

    rf5e5f73 rdf6ded8  
    7272        /* 64 bit struct only */
    7373        volatile uint32_t extended_bp[7];
    74 } itd_t;
     74} __attribute__((packed, aligned(32))) itd_t;
    7575#endif
    7676/**
  • uspace/drv/bus/usb/ehci/hw_struct/queue_head.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2013 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    3738#include <mem.h>
    3839#include <macros.h>
     40#include <usb/host/bus.h>
    3941
    4042#include "mem_access.h"
     
    6365                return;
    6466        }
    65         assert(ep->speed < ARRAY_SIZE(speed));
     67        assert(ep->device->speed < ARRAY_SIZE(speed));
    6668        EHCI_MEM32_WR(instance->ep_char,
    67             QH_EP_CHAR_ADDR_SET(ep->address) |
     69            QH_EP_CHAR_ADDR_SET(ep->device->address) |
    6870            QH_EP_CHAR_EP_SET(ep->endpoint) |
    69             speed[ep->speed] |
    70             QH_EP_CHAR_MAX_LENGTH_SET(ep->max_packet_size)
    71         );
     71            speed[ep->device->speed] |
     72            QH_EP_CHAR_MAX_LENGTH_SET(ep->max_packet_size));
    7273        if (ep->transfer_type == USB_TRANSFER_CONTROL) {
    73                 if (ep->speed != USB_SPEED_HIGH)
     74                if (ep->device->speed != USB_SPEED_HIGH)
    7475                        EHCI_MEM32_SET(instance->ep_char, QH_EP_CHAR_C_FLAG);
    7576                /* Let BULK and INT use queue head managed toggle,
     
    7879        }
    7980        uint32_t ep_cap = QH_EP_CAP_C_MASK_SET(3 << 2) |
    80                     QH_EP_CAP_MULTI_SET(ep->packets);
    81         if (ep->speed != USB_SPEED_HIGH) {
     81            QH_EP_CAP_MULTI_SET(ep->packets_per_uframe);
     82        if (usb_speed_is_11(ep->device->speed)) {
     83                assert(ep->device->tt.dev != NULL);
    8284                ep_cap |=
    83                     QH_EP_CAP_TT_PORT_SET(ep->tt.port) |
    84                     QH_EP_CAP_TT_ADDR_SET(ep->tt.address);
     85                    QH_EP_CAP_TT_PORT_SET(ep->device->tt.port) |
     86                    QH_EP_CAP_TT_ADDR_SET(ep->device->tt.dev->address);
    8587        }
    8688        if (ep->transfer_type == USB_TRANSFER_INTERRUPT) {
  • uspace/drv/bus/usb/ehci/hw_struct/queue_head.h

    rf5e5f73 rdf6ded8  
    143143        /* 64 bit struct only */
    144144        volatile uint32_t extended_bp[5];
    145 } qh_t;
     145} __attribute__((packed, aligned(32))) qh_t;
    146146
    147147static inline void qh_append_qh(qh_t *qh, const qh_t *next)
     
    193193}
    194194
    195 static inline void qh_set_next_td(qh_t *qh, td_t *td)
     195static inline void qh_set_next_td(qh_t *qh, uintptr_t td)
    196196{
    197197        assert(qh);
    198198        assert(td);
    199         EHCI_MEM32_WR(qh->next, LINK_POINTER_TD(addr_to_phys(td)));
     199        EHCI_MEM32_WR(qh->next, LINK_POINTER_TD(td));
    200200}
    201201
  • uspace/drv/bus/usb/ehci/hw_struct/split_iso_transfer_descriptor.h

    rf5e5f73 rdf6ded8  
    8989        /* 64 bit struct only */
    9090        volatile uint32_t extended_bp[2];
    91 } sitd_t;
     91} __attribute__((packed, aligned(32))) sitd_t;
    9292#endif
    9393/**
  • uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2014 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    3940
    4041#include <usb/usb.h>
    41 #include <usb/host/utils/malloc32.h>
    4242
    4343#include "mem_access.h"
     
    7070};
    7171
     72#include <usb/debug.h>
     73
    7274/**
    7375 * Initialize EHCI TD.
    7476 * @param instance TD structure to initialize.
    75  * @param next Next TD in ED list.
     77 * @param next_phys Next TD in ED list.
    7678 * @param direction Used to determine PID, BOTH means setup PID.
    7779 * @param buffer Pointer to the first byte of transferred data.
     
    8082 *        any other value means that ED toggle will be used.
    8183 */
    82 void td_init(td_t *instance, const td_t *next,
    83     usb_direction_t direction, const void *buffer, size_t size, int toggle,
    84     bool ioc)
     84void td_init(td_t *instance, uintptr_t next_phys, uintptr_t buffer,
     85    usb_direction_t direction, size_t size, int toggle, bool ioc)
    8586{
    8687        assert(instance);
     
    9899        }
    99100
    100         if (buffer != NULL) {
     101        if (buffer != 0) {
    101102                assert(size != 0);
    102103                for (unsigned i = 0; (i < ARRAY_SIZE(instance->buffer_pointer))
    103104                    && size; ++i) {
    104                         const uintptr_t page =
    105                             (addr_to_phys(buffer) & TD_BUFFER_POINTER_MASK);
    106                         const size_t offset =
    107                             ((uintptr_t)buffer & TD_BUFFER_POINTER_OFFSET_MASK);
     105                        const uintptr_t offset = buffer & TD_BUFFER_POINTER_OFFSET_MASK;
    108106                        assert(offset == 0 || i == 0);
    109                         size -= min((4096 - offset), size);
    110                         buffer += min((4096 - offset), size);
    111                         EHCI_MEM32_WR(instance->buffer_pointer[i],
    112                             page | offset);
     107                        const size_t this_size = min(size, 4096 - offset);
     108                        EHCI_MEM32_WR(instance->buffer_pointer[i], buffer);
     109                        size -= this_size;
     110                        buffer += this_size;
    113111                }
    114112        }
    115113
    116         EHCI_MEM32_WR(instance->next, next ?
    117             LINK_POINTER_TD(addr_to_phys(next)) : LINK_POINTER_TERM);
     114        EHCI_MEM32_WR(instance->next, next_phys ?
     115            LINK_POINTER_TD(next_phys) : LINK_POINTER_TERM);
    118116
    119117        EHCI_MEM32_WR(instance->alternate, LINK_POINTER_TERM);
  • uspace/drv/bus/usb/ehci/hw_struct/transfer_descriptor.h

    rf5e5f73 rdf6ded8  
    3737#include <stddef.h>
    3838#include <stdint.h>
     39#include <macros.h>
    3940#include "link_pointer.h"
    4041#include "mem_access.h"
     
    7576        /* 64 bit struct only */
    7677        volatile uint32_t extended_bp[5];
    77 } td_t;
     78
     79} __attribute__((packed,aligned(32))) td_t;
     80
     81static_assert(sizeof(td_t) % 32 == 0);
    7882
    7983static inline bool td_active(const td_t *td)
     
    9296errno_t td_error(const td_t *td);
    9397
    94 void td_init(td_t *td, const td_t *next, usb_direction_t dir, const void * buf,
     98void td_init(td_t *td, uintptr_t next_phys, uintptr_t buf, usb_direction_t dir,
    9599    size_t buf_size, int toggle, bool ioc);
    96100
  • uspace/drv/bus/usb/ehci/main.c

    rf5e5f73 rdf6ded8  
    22 * Copyright (c) 2011 Jan Vesely
    33 * Copyright (c) 2011 Vojtech Horky
     4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    45 * All rights reserved.
    56 *
     
    3536 */
    3637
    37 #include <ddf/driver.h>
    38 #include <ddf/interrupt.h>
    39 #include <device/hw_res.h>
    40 #include <errno.h>
    41 #include <str_error.h>
    4238#include <io/logctl.h>
    43 
    44 #include <usb_iface.h>
    45 #include <usb/debug.h>
    46 #include <usb/host/ddf_helpers.h>
     39#include <usb/host/hcd.h>
    4740
    4841#include "res.h"
    4942#include "hc.h"
    50 #include "ehci_endpoint.h"
    5143
    5244#define NAME "ehci"
    5345
    54 static errno_t ehci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool);
    55 static void ehci_driver_fini(hcd_t *);
     46static const hc_driver_t ehci_driver = {
     47        .name = NAME,
     48        .hc_device_size = sizeof(hc_t),
    5649
    57 static const ddf_hc_driver_t ehci_hc_driver = {
     50        .hc_add = hc_add,
     51        .irq_code_gen = hc_gen_irq_code,
    5852        .claim = disable_legacy,
    59         .hc_speed = USB_SPEED_HIGH,
    60         .irq_code_gen = ehci_hc_gen_irq_code,
    61         .init = ehci_driver_init,
    62         .fini = ehci_driver_fini,
    63         .name = "EHCI-PCI",
    64         .ops = {
    65                 .schedule       = ehci_hc_schedule,
    66                 .ep_add_hook    = ehci_endpoint_init,
    67                 .ep_remove_hook = ehci_endpoint_fini,
    68                 .irq_hook       = ehci_hc_interrupt,
    69                 .status_hook    = ehci_hc_status,
    70         }
     53        .start = hc_start,
     54        .setup_root_hub = hc_setup_roothub,
     55        .hc_gone = hc_gone,
    7156};
    72 
    73 
    74 static errno_t ehci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res,
    75     bool irq)
    76 {
    77         assert(hcd);
    78         assert(hcd_get_driver_data(hcd) == NULL);
    79 
    80         hc_t *instance = malloc(sizeof(hc_t));
    81         if (!instance)
    82                 return ENOMEM;
    83 
    84         const errno_t ret = hc_init(instance, res, irq);
    85         if (ret == EOK) {
    86                 hcd_set_implementation(hcd, instance, &ehci_hc_driver.ops);
    87         } else {
    88                 free(instance);
    89         }
    90         return ret;
    91 }
    92 
    93 static void ehci_driver_fini(hcd_t *hcd)
    94 {
    95         assert(hcd);
    96         hc_t *hc = hcd_get_driver_data(hcd);
    97         if (hc)
    98                 hc_fini(hc);
    99 
    100         free(hc);
    101         hcd_set_implementation(hcd, NULL, NULL);
    102 }
    103 
    104 /** Initializes a new ddf driver instance of EHCI hcd.
    105  *
    106  * @param[in] device DDF instance of the device to initialize.
    107  * @return Error code.
    108  */
    109 static errno_t ehci_dev_add(ddf_dev_t *device)
    110 {
    111         usb_log_debug("ehci_dev_add() called\n");
    112         assert(device);
    113 
    114         return hcd_ddf_add_hc(device, &ehci_hc_driver);
    115 
    116 }
    117 
    118 
    119 static const driver_ops_t ehci_driver_ops = {
    120         .dev_add = ehci_dev_add,
    121 };
    122 
    123 static const driver_t ehci_driver = {
    124         .name = NAME,
    125         .driver_ops = &ehci_driver_ops
    126 };
    127 
    12857
    12958/** Initializes global driver structures (NONE).
     
    13968        log_init(NAME);
    14069        logctl_set_log_level(NAME, LVL_NOTE);
    141         return ddf_driver_main(&ehci_driver);
     70        return hc_driver_main(&ehci_driver);
    14271}
    14372
  • uspace/drv/bus/usb/ehci/res.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4546#include <pci_dev_iface.h>
    4647
     48#include "hc.h"
    4749#include "res.h"
    4850#include "ehci_regs.h"
     
    7375            eecp + USBLEGSUP_OFFSET, &usblegsup);
    7476        if (ret != EOK) {
    75                 usb_log_error("Failed to read USBLEGSUP: %s.\n", str_error(ret));
    76                 return ret;
    77         }
    78         usb_log_debug2("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
     77                usb_log_error("Failed to read USBLEGSUP: %s.", str_error(ret));
     78                return ret;
     79        }
     80        usb_log_debug2("USBLEGSUP: %" PRIx32 ".", usblegsup);
    7981
    8082        /* Request control from firmware/BIOS by writing 1 to highest
    8183         * byte. (OS Control semaphore)*/
    82         usb_log_debug("Requesting OS control.\n");
     84        usb_log_debug("Requesting OS control.");
    8385        ret = pci_config_space_write_8(parent_sess,
    8486            eecp + USBLEGSUP_OFFSET + 3, 1);
    8587        if (ret != EOK) {
    86                 usb_log_error("Failed to request OS EHCI control: %s.\n",
     88                usb_log_error("Failed to request OS EHCI control: %s.",
    8789                    str_error(ret));
    8890                return ret;
     
    102104
    103105        if ((usblegsup & USBLEGSUP_BIOS_CONTROL) == 0) {
    104                 usb_log_info("BIOS released control after %zu usec.\n", wait);
     106                usb_log_info("BIOS released control after %zu usec.", wait);
    105107                return EOK;
    106108        }
     
    108110        /* BIOS failed to hand over control, this should not happen. */
    109111        usb_log_warning( "BIOS failed to release control after "
    110             "%zu usecs, force it.\n", wait);
     112            "%zu usecs, force it.", wait);
    111113        ret = pci_config_space_write_32(parent_sess,
    112114            eecp + USBLEGSUP_OFFSET, USBLEGSUP_OS_CONTROL);
    113115        if (ret != EOK) {
    114                 usb_log_error("Failed to force OS control: %s.\n",
     116                usb_log_error("Failed to force OS control: %s.",
    115117                    str_error(ret));
    116118                return ret;
     
    129131                    eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
    130132                if (ret != EOK) {
    131                         usb_log_error("Failed to get USBLEGCTLSTS: %s.\n",
     133                        usb_log_error("Failed to get USBLEGCTLSTS: %s.",
    132134                            str_error(ret));
    133135                        return ret;
    134136                }
    135                 usb_log_debug2("USBLEGCTLSTS: %" PRIx32 ".\n", usblegctlsts);
     137                usb_log_debug2("USBLEGCTLSTS: %" PRIx32 ".", usblegctlsts);
    136138                /*
    137139                 * Zero SMI enables in legacy control register.
     
    142144                    eecp + USBLEGCTLSTS_OFFSET, 0xe0000000);
    143145                if (ret != EOK) {
    144                         usb_log_error("Failed to zero USBLEGCTLSTS: %s\n",
     146                        usb_log_error("Failed to zero USBLEGCTLSTS: %s",
    145147                            str_error(ret));
    146148                        return ret;
     
    152154                    eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts);
    153155                if (ret != EOK) {
    154                         usb_log_error("Failed to get USBLEGCTLSTS 2: %s.\n",
     156                        usb_log_error("Failed to get USBLEGCTLSTS 2: %s.",
    155157                            str_error(ret));
    156158                        return ret;
    157159                }
    158                 usb_log_debug2("Zeroed USBLEGCTLSTS: %" PRIx32 ".\n",
     160                usb_log_debug2("Zeroed USBLEGCTLSTS: %" PRIx32 ".",
    159161                    usblegctlsts);
    160162        }
     
    164166            eecp + USBLEGSUP_OFFSET, &usblegsup);
    165167        if (ret != EOK) {
    166                 usb_log_error("Failed to read USBLEGSUP: %s.\n",
    167                     str_error(ret));
    168                 return ret;
    169         }
    170         usb_log_debug2("USBLEGSUP: %" PRIx32 ".\n", usblegsup);
     168                usb_log_error("Failed to read USBLEGSUP: %s.",
     169                    str_error(ret));
     170                return ret;
     171        }
     172        usb_log_debug2("USBLEGSUP: %" PRIx32 ".", usblegsup);
    171173        return ret;
    172174}
    173175
    174 errno_t disable_legacy(ddf_dev_t *device)
     176errno_t disable_legacy(hc_device_t *hcd)
    175177{
    176         assert(device);
    177 
    178         async_sess_t *parent_sess = ddf_dev_parent_sess_get(device);
     178        hc_t *hc = hcd_to_hc(hcd);
     179
     180        async_sess_t *parent_sess = ddf_dev_parent_sess_get(hcd->ddf_dev);
    179181        if (parent_sess == NULL)
    180182                return ENOMEM;
    181183
    182         usb_log_debug("Disabling EHCI legacy support.\n");
    183 
    184         hw_res_list_parsed_t res;
    185         hw_res_list_parsed_init(&res);
    186         errno_t ret = hw_res_get_list_parsed(parent_sess, &res, 0);
    187         if (ret != EOK) {
    188                 usb_log_error("Failed to get resource list: %s\n",
    189                     str_error(ret));
    190                 goto clean;
    191         }
    192 
    193         if (res.mem_ranges.count < 1) {
    194                 usb_log_error("Incorrect mem range count: %zu",
    195                     res.mem_ranges.count);
    196                 ret = EINVAL;
    197                 goto clean;
    198         }
    199 
    200         /* Map EHCI registers */
    201         void *regs = NULL;
    202         ret = pio_enable_range(&res.mem_ranges.ranges[0], &regs);
    203         if (ret != EOK) {
    204                 usb_log_error("Failed to map registers %p: %s.\n",
    205                     RNGABSPTR(res.mem_ranges.ranges[0]), str_error(ret));
    206                 goto clean;
    207         }
    208 
    209         usb_log_debug("Registers mapped at: %p.\n", regs);
    210 
    211         ehci_caps_regs_t *ehci_caps = regs;
    212 
    213         const uint32_t hcc_params = EHCI_RD(ehci_caps->hccparams);
    214         usb_log_debug2("Value of hcc params register: %x.\n", hcc_params);
     184        usb_log_debug("Disabling EHCI legacy support.");
     185
     186        const uint32_t hcc_params = EHCI_RD(hc->caps->hccparams);
     187        usb_log_debug2("Value of hcc params register: %x.", hcc_params);
    215188
    216189        /* Read value of EHCI Extended Capabilities Pointer
     
    218191        const uint32_t eecp =
    219192            (hcc_params >> EHCI_CAPS_HCC_EECP_SHIFT) & EHCI_CAPS_HCC_EECP_MASK;
    220         usb_log_debug2("Value of EECP: %x.\n", eecp);
    221 
    222         ret = disable_extended_caps(parent_sess, eecp);
    223         if (ret != EOK) {
    224                 usb_log_error("Failed to disable extended capabilities: %s.\n",
     193        usb_log_debug2("Value of EECP: %x.", eecp);
     194
     195        int ret = disable_extended_caps(parent_sess, eecp);
     196        if (ret != EOK) {
     197                usb_log_error("Failed to disable extended capabilities: %s.",
    225198                    str_error(ret));
    226199                    goto clean;
    227200        }
    228201clean:
    229         //TODO unmap registers
    230         hw_res_list_parsed_clean(&res);
     202        async_hangup(parent_sess);
    231203        return ret;
    232204}
  • uspace/drv/bus/usb/ehci/res.h

    rf5e5f73 rdf6ded8  
    3636#define DRV_EHCI_PCI_H
    3737
    38 #include <ddf/driver.h>
    39 #include <device/hw_res_parsed.h>
     38typedef struct hc_device hc_device_t;
    4039
    41 extern errno_t disable_legacy(ddf_dev_t *);
     40extern errno_t disable_legacy(hc_device_t *);
    4241
    4342#endif
  • uspace/drv/bus/usb/ohci/Makefile

    rf5e5f73 rdf6ded8  
    3838        main.c \
    3939        ohci_batch.c \
    40         ohci_endpoint.c \
     40        ohci_bus.c \
    4141        ohci_rh.c \
    4242        hw_struct/endpoint_descriptor.c \
  • uspace/drv/bus/usb/ohci/endpoint_list.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    5758        instance->list_head = malloc32(sizeof(ed_t));
    5859        if (!instance->list_head) {
    59                 usb_log_error("Failed to allocate list head.\n");
     60                usb_log_error("Failed to allocate list head.");
    6061                return ENOMEM;
    6162        }
    6263        instance->list_head_pa = addr_to_phys(instance->list_head);
    63         usb_log_debug2("Transfer list %s setup with ED: %p(0x%0" PRIx32 ")).\n",
     64        usb_log_debug2("Transfer list %s setup with ED: %p(0x%0" PRIx32 ")).",
    6465            name, instance->list_head, instance->list_head_pa);
    6566
     
    9697        assert(instance);
    9798        assert(ep);
    98         usb_log_debug2("Queue %s: Adding endpoint(%p).\n", instance->name, ep);
     99        usb_log_debug2("Queue %s: Adding endpoint(%p).", instance->name, ep);
    99100
    100101        fibril_mutex_lock(&instance->guard);
     
    108109                /* There are active EDs, get the last one */
    109110                ohci_endpoint_t *last = list_get_instance(
    110                     list_last(&instance->endpoint_list), ohci_endpoint_t, link);
     111                    list_last(&instance->endpoint_list), ohci_endpoint_t, eplist_link);
    111112                last_ed = last->ed;
    112113        }
     
    122123
    123124        /* Add to the sw list */
    124         list_append(&ep->link, &instance->endpoint_list);
     125        list_append(&ep->eplist_link, &instance->endpoint_list);
    125126
    126127        ohci_endpoint_t *first = list_get_instance(
    127             list_first(&instance->endpoint_list), ohci_endpoint_t, link);
    128         usb_log_debug("HCD EP(%p) added to list %s, first is %p(%p).\n",
     128            list_first(&instance->endpoint_list), ohci_endpoint_t, eplist_link);
     129        usb_log_debug("HCD EP(%p) added to list %s, first is %p(%p).",
    129130                ep, instance->name, first, first->ed);
    130131        if (last_ed == instance->list_head) {
    131                 usb_log_debug2("%s head ED(%p-0x%0" PRIx32 "): %x:%x:%x:%x.\n",
     132                usb_log_debug2("%s head ED(%p-0x%0" PRIx32 "): %x:%x:%x:%x.",
    132133                    instance->name, last_ed, instance->list_head_pa,
    133134                    last_ed->status, last_ed->td_tail, last_ed->td_head,
     
    151152        fibril_mutex_lock(&instance->guard);
    152153
    153         usb_log_debug2("Queue %s: removing endpoint(%p).\n", instance->name, ep);
     154        usb_log_debug2("Queue %s: removing endpoint(%p).", instance->name, ep);
    154155
    155156        const char *qpos = NULL;
    156157        ed_t *prev_ed;
    157158        /* Remove from the hardware queue */
    158         if (list_first(&instance->endpoint_list) == &ep->link) {
     159        if (list_first(&instance->endpoint_list) == &ep->eplist_link) {
    159160                /* I'm the first one here */
    160161                prev_ed = instance->list_head;
     
    162163        } else {
    163164                ohci_endpoint_t *prev =
    164                     list_get_instance(ep->link.prev, ohci_endpoint_t, link);
     165                    list_get_instance(ep->eplist_link.prev, ohci_endpoint_t, eplist_link);
    165166                prev_ed = prev->ed;
    166167                qpos = "NOT FIRST";
     
    171172        write_barrier();
    172173
    173         usb_log_debug("HCD EP(%p) removed (%s) from %s, next %x.\n",
     174        usb_log_debug("HCD EP(%p) removed (%s) from %s, next %x.",
    174175            ep, qpos, instance->name, ep->ed->next);
    175176
    176177        /* Remove from the endpoint list */
    177         list_remove(&ep->link);
     178        list_remove(&ep->eplist_link);
    178179        fibril_mutex_unlock(&instance->guard);
    179180}
  • uspace/drv/bus/usb/ohci/endpoint_list.h

    rf5e5f73 rdf6ded8  
    4141#include <usb/host/utils/malloc32.h>
    4242
    43 #include "ohci_endpoint.h"
     43#include "ohci_bus.h"
    4444#include "hw_struct/endpoint_descriptor.h"
    4545
  • uspace/drv/bus/usb/ohci/hc.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4546
    4647#include <usb/debug.h>
     48#include <usb/host/utility.h>
    4749#include <usb/usb.h>
    4850
    49 #include "ohci_endpoint.h"
     51#include "ohci_bus.h"
    5052#include "ohci_batch.h"
    5153
     
    8991};
    9092
    91 static void hc_gain_control(hc_t *instance);
    92 static void hc_start(hc_t *instance);
    9393static errno_t hc_init_transfer_lists(hc_t *instance);
    9494static errno_t hc_init_memory(hc_t *instance);
     
    103103 * @return Error code.
    104104 */
    105 errno_t ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)
     105errno_t hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res, int *irq)
    106106{
    107107        assert(code);
     
    138138        OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS);
    139139
    140         usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
     140        usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.",
    141141            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    142142
     
    152152 * @return Error code
    153153 */
    154 errno_t hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    155 {
    156         assert(instance);
     154errno_t hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res)
     155{
     156        hc_t *instance = hcd_to_hc(hcd);
    157157        assert(hw_res);
    158158        if (hw_res->mem_ranges.count != 1 ||
     
    163163            (void **) &instance->registers);
    164164        if (ret != EOK) {
    165                 usb_log_error("Failed to gain access to registers: %s.\n",
     165                usb_log_error("Failed to gain access to registers: %s.",
    166166                    str_error(ret));
    167167                return ret;
    168168        }
    169         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     169        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.",
    170170            hw_res->mem_ranges.ranges[0].address.absolute,
    171171            hw_res->mem_ranges.ranges[0].size);
    172172
    173         list_initialize(&instance->pending_batches);
     173        list_initialize(&instance->pending_endpoints);
    174174        fibril_mutex_initialize(&instance->guard);
    175         instance->hw_interrupts = interrupts;
    176175
    177176        ret = hc_init_memory(instance);
    178177        if (ret != EOK) {
    179                 usb_log_error("Failed to create OHCI memory structures: %s.\n",
     178                usb_log_error("Failed to create OHCI memory structures: %s.",
    180179                    str_error(ret));
    181180                // TODO: We should disable pio access here
     
    183182        }
    184183
    185         hc_gain_control(instance);
    186 
    187         ohci_rh_init(&instance->rh, instance->registers, "ohci rh");
    188         hc_start(instance);
    189 
    190184        return EOK;
    191185}
     
    195189 * @param[in] instance Host controller structure to use.
    196190 */
    197 void hc_fini(hc_t *instance)
     191int hc_gone(hc_device_t *instance)
    198192{
    199193        assert(instance);
    200194        /* TODO: implement*/
    201 };
     195        return ENOTSUP;
     196}
    202197
    203198void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
     
    269264}
    270265
    271 errno_t ohci_hc_status(hcd_t *hcd, uint32_t *status)
    272 {
    273         assert(hcd);
     266errno_t ohci_hc_status(bus_t *bus_base, uint32_t *status)
     267{
     268        assert(bus_base);
    274269        assert(status);
    275         hc_t *instance = hcd_get_driver_data(hcd);
    276         assert(instance);
    277 
    278         if (instance->registers){
    279                 *status = OHCI_RD(instance->registers->interrupt_status);
    280                 OHCI_WR(instance->registers->interrupt_status, *status);
     270
     271        ohci_bus_t *bus = (ohci_bus_t *) bus_base;
     272        hc_t *hc = bus->hc;
     273        assert(hc);
     274
     275        if (hc->registers){
     276                *status = OHCI_RD(hc->registers->interrupt_status);
     277                OHCI_WR(hc->registers->interrupt_status, *status);
    281278        }
    282279        return EOK;
     
    289286 * @return Error code.
    290287 */
    291 errno_t ohci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    292 {
    293         assert(hcd);
    294         hc_t *instance = hcd_get_driver_data(hcd);
    295         assert(instance);
     288errno_t ohci_hc_schedule(usb_transfer_batch_t *batch)
     289{
     290        assert(batch);
     291
     292        ohci_bus_t *bus = (ohci_bus_t *) endpoint_get_bus(batch->ep);
     293        hc_t *hc = bus->hc;
     294        assert(hc);
    296295
    297296        /* Check for root hub communication */
    298         if (batch->ep->address == ohci_rh_get_address(&instance->rh)) {
    299                 usb_log_debug("OHCI root hub request.\n");
    300                 return ohci_rh_schedule(&instance->rh, batch);
    301         }
     297        if (batch->target.address == ohci_rh_get_address(&hc->rh)) {
     298                usb_log_debug("OHCI root hub request.");
     299                return ohci_rh_schedule(&hc->rh, batch);
     300        }
     301
     302        endpoint_t *ep = batch->ep;
     303        ohci_endpoint_t * const ohci_ep = ohci_endpoint_get(ep);
    302304        ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);
    303         if (!ohci_batch)
    304                 return ENOMEM;
    305 
    306         fibril_mutex_lock(&instance->guard);
    307         list_append(&ohci_batch->link, &instance->pending_batches);
     305        int err;
     306
     307        if ((err = ohci_transfer_batch_prepare(ohci_batch)))
     308                return err;
     309
     310        fibril_mutex_lock(&hc->guard);
     311        if ((err = endpoint_activate_locked(ep, batch))) {
     312                fibril_mutex_unlock(&hc->guard);
     313                return err;
     314        }
     315
    308316        ohci_transfer_batch_commit(ohci_batch);
     317        list_append(&ohci_ep->pending_link, &hc->pending_endpoints);
     318        fibril_mutex_unlock(&hc->guard);
    309319
    310320        /* Control and bulk schedules need a kick to start working */
     
    312322        {
    313323        case USB_TRANSFER_CONTROL:
    314                 OHCI_SET(instance->registers->command_status, CS_CLF);
     324                OHCI_SET(hc->registers->command_status, CS_CLF);
    315325                break;
    316326        case USB_TRANSFER_BULK:
    317                 OHCI_SET(instance->registers->command_status, CS_BLF);
     327                OHCI_SET(hc->registers->command_status, CS_BLF);
    318328                break;
    319329        default:
    320330                break;
    321331        }
    322         fibril_mutex_unlock(&instance->guard);
     332
    323333        return EOK;
    324334}
     
    329339 * @param[in] status Value of the status register at the time of interrupt.
    330340 */
    331 void ohci_hc_interrupt(hcd_t *hcd, uint32_t status)
    332 {
    333         assert(hcd);
    334         hc_t *instance = hcd_get_driver_data(hcd);
     341void ohci_hc_interrupt(bus_t *bus_base, uint32_t status)
     342{
     343        assert(bus_base);
     344
     345        ohci_bus_t *bus = (ohci_bus_t *) bus_base;
     346        hc_t *hc = bus->hc;
     347        assert(hc);
     348
    335349        status = OHCI_RD(status);
    336         assert(instance);
     350        assert(hc);
    337351        if ((status & ~I_SF) == 0) /* ignore sof status */
    338352                return;
    339         usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status);
     353        usb_log_debug2("OHCI(%p) interrupt: %x.", hc, status);
    340354        if (status & I_RHSC)
    341                 ohci_rh_interrupt(&instance->rh);
     355                ohci_rh_interrupt(&hc->rh);
    342356
    343357        if (status & I_WDH) {
    344                 fibril_mutex_lock(&instance->guard);
    345                 usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).\n", instance->hcca,
    346                     OHCI_RD(instance->registers->hcca),
    347                     (void *) addr_to_phys(instance->hcca));
    348                 usb_log_debug2("Periodic current: %#" PRIx32 ".\n",
    349                     OHCI_RD(instance->registers->periodic_current));
    350 
    351                 link_t *current = list_first(&instance->pending_batches);
    352                 while (current && current != &instance->pending_batches.head) {
    353                         link_t *next = current->next;
    354                         ohci_transfer_batch_t *batch =
    355                             ohci_transfer_batch_from_link(current);
    356 
    357                         if (ohci_transfer_batch_is_complete(batch)) {
     358                fibril_mutex_lock(&hc->guard);
     359                usb_log_debug2("HCCA: %p-%#" PRIx32 " (%p).", hc->hcca,
     360                    OHCI_RD(hc->registers->hcca),
     361                    (void *) addr_to_phys(hc->hcca));
     362                usb_log_debug2("Periodic current: %#" PRIx32 ".",
     363                    OHCI_RD(hc->registers->periodic_current));
     364
     365                list_foreach_safe(hc->pending_endpoints, current, next) {
     366                        ohci_endpoint_t *ep
     367                                = list_get_instance(current, ohci_endpoint_t, pending_link);
     368
     369                        ohci_transfer_batch_t *batch
     370                                = ohci_transfer_batch_get(ep->base.active_batch);
     371                        assert(batch);
     372
     373                        if (ohci_transfer_batch_check_completed(batch)) {
     374                                endpoint_deactivate_locked(&ep->base);
    358375                                list_remove(current);
    359                                 ohci_transfer_batch_finish_dispose(batch);
     376                                hc_reset_toggles(&batch->base, &ohci_ep_toggle_reset);
     377                                usb_transfer_batch_finish(&batch->base);
    360378                        }
    361 
    362                         current = next;
    363379                }
    364                 fibril_mutex_unlock(&instance->guard);
     380                fibril_mutex_unlock(&hc->guard);
    365381        }
    366382
    367383        if (status & I_UE) {
    368                 usb_log_fatal("Error like no other!\n");
    369                 hc_start(instance);
     384                usb_log_fatal("Error like no other!");
     385                hc_start(&hc->base);
    370386        }
    371387
     
    379395 * @param[in] instance OHCI hc driver structure.
    380396 */
    381 void hc_gain_control(hc_t *instance)
    382 {
    383         assert(instance);
    384 
    385         usb_log_debug("Requesting OHCI control.\n");
     397int hc_gain_control(hc_device_t *hcd)
     398{
     399        hc_t *instance = hcd_to_hc(hcd);
     400
     401        usb_log_debug("Requesting OHCI control.");
    386402        if (OHCI_RD(instance->registers->revision) & R_LEGACY_FLAG) {
    387403                /* Turn off legacy emulation, it should be enough to zero
     
    392408                volatile uint32_t *ohci_emulation_reg =
    393409                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
    394                 usb_log_debug("OHCI legacy register %p: %x.\n",
     410                usb_log_debug("OHCI legacy register %p: %x.",
    395411                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    396412                /* Zero everything but A20State */
     
    398414                OHCI_CLR(*ohci_emulation_reg, ~0x100);
    399415                usb_log_debug(
    400                     "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
     416                    "OHCI legacy register (should be 0 or 0x100) %p: %x.",
    401417                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    402418        }
     
    404420        /* Interrupt routing enabled => smm driver is active */
    405421        if (OHCI_RD(instance->registers->control) & C_IR) {
    406                 usb_log_debug("SMM driver: request ownership change.\n");
     422                usb_log_debug("SMM driver: request ownership change.");
    407423                // TODO: should we ack interrupts before doing this?
    408424                OHCI_SET(instance->registers->command_status, CS_OCR);
     
    411427                        async_usleep(1000);
    412428                }
    413                 usb_log_info("SMM driver: Ownership taken.\n");
     429                usb_log_info("SMM driver: Ownership taken.");
    414430                C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
    415431                async_usleep(50000);
    416                 return;
     432                return EOK;
    417433        }
    418434
     
    420436        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    421437        if (hc_status != C_HCFS_RESET) {
    422                 usb_log_debug("BIOS driver found.\n");
     438                usb_log_debug("BIOS driver found.");
    423439                if (hc_status == C_HCFS_OPERATIONAL) {
    424                         usb_log_info("BIOS driver: HC operational.\n");
    425                         return;
     440                        usb_log_info("BIOS driver: HC operational.");
     441                        return EOK;
    426442                }
    427443                /* HC is suspended assert resume for 20ms */
    428444                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    429445                async_usleep(20000);
    430                 usb_log_info("BIOS driver: HC resumed.\n");
    431                 return;
     446                usb_log_info("BIOS driver: HC resumed.");
     447                return EOK;
    432448        }
    433449
    434450        /* HC is in reset (hw startup) => no other driver
    435451         * maintain reset for at least the time specified in USB spec (50 ms)*/
    436         usb_log_debug("Host controller found in reset state.\n");
     452        usb_log_debug("Host controller found in reset state.");
    437453        async_usleep(50000);
     454        return EOK;
    438455}
    439456
     
    442459 * @param[in] instance OHCI hc driver structure.
    443460 */
    444 void hc_start(hc_t *instance)
    445 {
     461int hc_start(hc_device_t *hcd)
     462{
     463        hc_t *instance = hcd_to_hc(hcd);
     464        ohci_rh_init(&instance->rh, instance->registers, &instance->guard, "ohci rh");
     465
    446466        /* OHCI guide page 42 */
    447467        assert(instance);
    448         usb_log_debug2("Started hc initialization routine.\n");
     468        usb_log_debug2("Started hc initialization routine.");
    449469
    450470        /* Save contents of fm_interval register */
    451471        const uint32_t fm_interval = OHCI_RD(instance->registers->fm_interval);
    452         usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);
     472        usb_log_debug2("Old value of HcFmInterval: %x.", fm_interval);
    453473
    454474        /* Reset hc */
    455         usb_log_debug2("HC reset.\n");
     475        usb_log_debug2("HC reset.");
    456476        size_t time = 0;
    457477        OHCI_WR(instance->registers->command_status, CS_HCR);
     
    460480                time += 10;
    461481        }
    462         usb_log_debug2("HC reset complete in %zu us.\n", time);
     482        usb_log_debug2("HC reset complete in %zu us.", time);
    463483
    464484        /* Restore fm_interval */
     
    467487
    468488        /* hc is now in suspend state */
    469         usb_log_debug2("HC should be in suspend state(%x).\n",
     489        usb_log_debug2("HC should be in suspend state(%x).",
    470490            OHCI_RD(instance->registers->control));
    471491
     
    476496        OHCI_WR(instance->registers->bulk_head,
    477497            instance->lists[USB_TRANSFER_BULK].list_head_pa);
    478         usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").\n",
     498        usb_log_debug2("Bulk HEAD set to: %p (%#" PRIx32 ").",
    479499            instance->lists[USB_TRANSFER_BULK].list_head,
    480500            instance->lists[USB_TRANSFER_BULK].list_head_pa);
     
    482502        OHCI_WR(instance->registers->control_head,
    483503            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
    484         usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").\n",
     504        usb_log_debug2("Control HEAD set to: %p (%#" PRIx32 ").",
    485505            instance->lists[USB_TRANSFER_CONTROL].list_head,
    486506            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
     
    488508        /* Enable queues */
    489509        OHCI_SET(instance->registers->control, (C_PLE | C_IE | C_CLE | C_BLE));
    490         usb_log_debug("Queues enabled(%x).\n",
     510        usb_log_debug("Queues enabled(%x).",
    491511            OHCI_RD(instance->registers->control));
    492512
    493513        /* Enable interrupts */
    494         if (instance->hw_interrupts) {
     514        if (instance->base.irq_cap >= 0) {
    495515                OHCI_WR(instance->registers->interrupt_enable,
    496516                    OHCI_USED_INTERRUPTS);
    497                 usb_log_debug("Enabled interrupts: %x.\n",
     517                usb_log_debug("Enabled interrupts: %x.",
    498518                    OHCI_RD(instance->registers->interrupt_enable));
    499519                OHCI_WR(instance->registers->interrupt_enable, I_MI);
     
    505525        OHCI_WR(instance->registers->periodic_start,
    506526            ((frame_length / 10) * 9) & PS_MASK << PS_SHIFT);
    507         usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n",
     527        usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).",
    508528            OHCI_RD(instance->registers->periodic_start),
    509529            OHCI_RD(instance->registers->periodic_start), frame_length);
    510530        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    511         usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
     531        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).",
    512532            OHCI_RD(instance->registers->control));
     533
     534        return EOK;
     535}
     536
     537/**
     538 * Setup roothub as a virtual hub.
     539 */
     540int hc_setup_roothub(hc_device_t *hcd)
     541{
     542        return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL);
    513543}
    514544
     
    526556        const errno_t ret = endpoint_list_init(&instance->lists[type], name); \
    527557        if (ret != EOK) { \
    528                 usb_log_error("Failed to setup %s endpoint list: %s.\n", \
     558                usb_log_error("Failed to setup %s endpoint list: %s.", \
    529559                    name, str_error(ret)); \
    530560                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
     
    558588        memset(&instance->rh, 0, sizeof(instance->rh));
    559589        /* Init queues */
    560         const errno_t ret = hc_init_transfer_lists(instance);
     590        errno_t ret = hc_init_transfer_lists(instance);
    561591        if (ret != EOK) {
    562592                return ret;
     
    567597        if (instance->hcca == NULL)
    568598                return ENOMEM;
    569         usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
     599        usb_log_debug2("OHCI HCCA initialized at %p.", instance->hcca);
    570600
    571601        for (unsigned i = 0; i < HCCA_INT_EP_COUNT; ++i) {
     
    573603                    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    574604        }
    575         usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").\n",
     605        usb_log_debug2("Interrupt HEADs set to: %p (%#" PRIx32 ").",
    576606            instance->lists[USB_TRANSFER_INTERRUPT].list_head,
    577607            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    578608
     609        if ((ret = ohci_bus_init(&instance->bus, instance))) {
     610                usb_log_error("HC(%p): Failed to setup bus : %s",
     611                    instance, str_error(ret));
     612                return ret;
     613        }
     614
     615        hc_device_setup(&instance->base, (bus_t *) &instance->bus);
     616
    579617        return EOK;
    580618}
  • uspace/drv/bus/usb/ohci/hc.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    5253#include "ohci_regs.h"
    5354#include "ohci_rh.h"
     55#include "ohci_bus.h"
    5456#include "endpoint_list.h"
    5557#include "hw_struct/hcca.h"
     
    5759/** Main OHCI driver structure */
    5860typedef struct hc {
     61        /** Common hcd header */
     62        hc_device_t base;
     63
    5964        /** Memory mapped I/O registers area */
    6065        ohci_regs_t *registers;
     66       
    6167        /** Host controller communication area structure */
    6268        hcca_t *hcca;
     
    6470        /** Transfer schedules */
    6571        endpoint_list_t lists[4];
    66         /** List of active transfers */
    67         list_t pending_batches;
    6872
    69         /** Fibril for periodic checks if interrupts can't be used */
    70         fid_t interrupt_emulator;
     73        /** List of active endpoints */
     74        list_t pending_endpoints;
    7175
    7276        /** Guards schedule and endpoint manipulation */
    7377        fibril_mutex_t guard;
    7478
    75         /** interrupts available */
    76         bool hw_interrupts;
    77 
    7879        /** USB hub emulation structure */
    7980        ohci_rh_t rh;
     81
     82        /** USB bookkeeping */
     83        ohci_bus_t bus;
    8084} hc_t;
    8185
    82 extern errno_t hc_init(hc_t *, const hw_res_list_parsed_t *, bool);
    83 extern void hc_fini(hc_t *);
     86static inline hc_t *hcd_to_hc(hc_device_t *hcd)
     87{
     88        assert(hcd);
     89        return (hc_t *) hcd;
     90}
     91
     92extern errno_t hc_add(hc_device_t *, const hw_res_list_parsed_t *);
     93extern errno_t hc_gen_irq_code(irq_code_t *, hc_device_t *,
     94    const hw_res_list_parsed_t *, int *);
     95extern errno_t hc_gain_control(hc_device_t *);
     96extern errno_t hc_start(hc_device_t *);
     97extern errno_t hc_setup_roothub(hc_device_t *);
     98extern errno_t hc_gone(hc_device_t *);
    8499
    85100extern void hc_enqueue_endpoint(hc_t *, const endpoint_t *);
    86101extern void hc_dequeue_endpoint(hc_t *, const endpoint_t *);
    87102
    88 errno_t ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq);
    89 
    90 extern void ohci_hc_interrupt(hcd_t *, uint32_t);
    91 extern errno_t ohci_hc_status(hcd_t *, uint32_t *);
    92 extern errno_t ohci_hc_schedule(hcd_t *, usb_transfer_batch_t *);
     103extern errno_t ohci_hc_schedule(usb_transfer_batch_t *);
     104extern errno_t ohci_hc_status(bus_t *, uint32_t *);
     105extern void ohci_hc_interrupt(bus_t *, uint32_t);
    93106
    94107#endif
  • uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.c

    rf5e5f73 rdf6ded8  
    4040#include <usb/usb.h>
    4141#include <usb/host/utils/malloc32.h>
     42#include <usb/host/endpoint.h>
     43#include <usb/host/bus.h>
    4244
    4345#include "mem_access.h"
     
    7981        /* Status: address, endpoint nr, direction mask and max packet size. */
    8082        OHCI_MEM32_WR(instance->status,
    81             ((ep->address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)
     83            ((ep->device->address & ED_STATUS_FA_MASK) << ED_STATUS_FA_SHIFT)
    8284            | ((ep->endpoint & ED_STATUS_EN_MASK) << ED_STATUS_EN_SHIFT)
    8385            | ((dir[ep->direction] & ED_STATUS_D_MASK) << ED_STATUS_D_SHIFT)
    84             | ((ep->max_packet_size & ED_STATUS_MPS_MASK)
    85                 << ED_STATUS_MPS_SHIFT));
     86            | ((ep->max_packet_size & ED_STATUS_MPS_MASK) << ED_STATUS_MPS_SHIFT));
    8687
    8788        /* Low speed flag */
    88         if (ep->speed == USB_SPEED_LOW)
     89        if (ep->device->speed == USB_SPEED_LOW)
    8990                OHCI_MEM32_SET(instance->status, ED_STATUS_S_FLAG);
    9091
     
    9899        OHCI_MEM32_WR(instance->td_head, pa & ED_TDHEAD_PTR_MASK);
    99100        OHCI_MEM32_WR(instance->td_tail, pa & ED_TDTAIL_PTR_MASK);
    100 
    101         /* Set toggle bit */
    102         if (ep->toggle)
    103                 OHCI_MEM32_SET(instance->td_head, ED_TDHEAD_TOGGLE_CARRY);
    104 
    105101}
    106102/**
  • uspace/drv/bus/usb/ohci/hw_struct/endpoint_descriptor.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    106107#define ED_NEXT_PTR_MASK (0xfffffff0)
    107108#define ED_NEXT_PTR_SHIFT (0)
    108 } __attribute__((packed)) ed_t;
     109} __attribute__((packed, aligned(32))) ed_t;
    109110
    110111void ed_init(ed_t *instance, const endpoint_t *ep, const td_t *td);
     
    162163        assert(instance);
    163164        return OHCI_MEM32_RD(instance->td_head) & ED_TDHEAD_PTR_MASK;
     165}
     166
     167/**
     168 * Set the HeadP of ED. Do not call unless the ED is Halted.
     169 * @param instance ED
     170 */
     171static inline void ed_set_head_td(ed_t *instance, const td_t *td)
     172{
     173        assert(instance);
     174        const uintptr_t pa = addr_to_phys(td);
     175        OHCI_MEM32_WR(instance->td_head, pa & ED_TDHEAD_PTR_MASK);
    164176}
    165177
     
    192204{
    193205        assert(instance);
    194         return (OHCI_MEM32_RD(instance->td_head) & ED_TDHEAD_TOGGLE_CARRY) ? 1 : 0;
     206        return !!(OHCI_MEM32_RD(instance->td_head) & ED_TDHEAD_TOGGLE_CARRY);
    195207}
    196208
  • uspace/drv/bus/usb/ohci/hw_struct/iso_transfer_descriptor.h

    rf5e5f73 rdf6ded8  
    6969#define ITD_OFFSET_CC_SHIFT (12)
    7070
    71 } __attribute__((packed)) itd_t;
     71} __attribute__((packed, aligned(32))) itd_t;
    7272
    7373#endif
  • uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.c

    rf5e5f73 rdf6ded8  
    8888        }
    8989
     90        td_set_next(instance, next);
     91}
     92
     93void td_set_next(td_t *instance, const td_t *next)
     94{
    9095        OHCI_MEM32_WR(instance->next, addr_to_phys(next) & TD_NEXT_PTR_MASK);
     96}
    9197
    92 }
    9398/**
    9499 * @}
  • uspace/drv/bus/usb/ohci/hw_struct/transfer_descriptor.h

    rf5e5f73 rdf6ded8  
    9090         */
    9191        volatile uint32_t be;
    92 } __attribute__((packed)) td_t;
     92} __attribute__((packed, aligned(32))) td_t;
    9393
    94 void td_init(td_t *instance, const td_t *next,
    95     usb_direction_t dir, const void *buffer, size_t size, int toggle);
     94void td_init(td_t *, const td_t *, usb_direction_t, const void *, size_t, int);
     95void td_set_next(td_t *, const td_t *);
    9696
    9797/**
     
    103103{
    104104        assert(instance);
    105         const int cc =(OHCI_MEM32_RD(instance->status)
    106             >> TD_STATUS_CC_SHIFT) & TD_STATUS_CC_MASK;
     105        const int cc = (OHCI_MEM32_RD(instance->status) >> TD_STATUS_CC_SHIFT)
     106                & TD_STATUS_CC_MASK;
    107107        /* This value is changed on transfer completion,
    108108         * either to CC_NOERROR or and error code.
  • uspace/drv/bus/usb/ohci/main.c

    rf5e5f73 rdf6ded8  
    22 * Copyright (c) 2011 Jan Vesely
    33 * Copyright (c) 2011 Vojtech Horky
     4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    45 * All rights reserved.
    56 *
     
    3940#include <errno.h>
    4041#include <io/log.h>
     42#include <io/logctl.h>
    4143#include <str_error.h>
    4244
    4345#include <usb/debug.h>
    44 #include <usb/host/ddf_helpers.h>
    4546
    4647#include "hc.h"
     48#include "ohci_bus.h"
    4749
    4850#define NAME "ohci"
    49 static errno_t ohci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool);
    50 static void ohci_driver_fini(hcd_t *);
    5151
    52 static const ddf_hc_driver_t ohci_hc_driver = {
    53         .hc_speed = USB_SPEED_FULL,
    54         .irq_code_gen = ohci_hc_gen_irq_code,
    55         .init = ohci_driver_init,
    56         .fini = ohci_driver_fini,
    57         .name = "OHCI",
    58         .ops = {
    59                 .schedule       = ohci_hc_schedule,
    60                 .ep_add_hook    = ohci_endpoint_init,
    61                 .ep_remove_hook = ohci_endpoint_fini,
    62                 .irq_hook       = ohci_hc_interrupt,
    63                 .status_hook    = ohci_hc_status,
    64         },
    65 };
     52static const hc_driver_t ohci_driver = {
     53        .name = NAME,
     54        .hc_device_size = sizeof(hc_t),
    6655
    67 
    68 static errno_t ohci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq)
    69 {
    70         assert(hcd);
    71         assert(hcd_get_driver_data(hcd) == NULL);
    72 
    73         hc_t *instance = malloc(sizeof(hc_t));
    74         if (!instance)
    75                 return ENOMEM;
    76 
    77         const errno_t ret = hc_init(instance, res, irq);
    78         if (ret == EOK) {
    79                 hcd_set_implementation(hcd, instance, &ohci_hc_driver.ops);
    80         } else {
    81                 free(instance);
    82         }
    83         return ret;
    84 }
    85 
    86 static void ohci_driver_fini(hcd_t *hcd)
    87 {
    88         assert(hcd);
    89         hc_t *hc = hcd_get_driver_data(hcd);
    90         if (hc)
    91                 hc_fini(hc);
    92 
    93         hcd_set_implementation(hcd, NULL, NULL);
    94         free(hc);
    95 }
    96 
    97 /** Initializes a new ddf driver instance of OHCI hcd.
    98  *
    99  * @param[in] device DDF instance of the device to initialize.
    100  * @return Error code.
    101  */
    102 static errno_t ohci_dev_add(ddf_dev_t *device)
    103 {
    104         usb_log_debug("ohci_dev_add() called\n");
    105         assert(device);
    106         return hcd_ddf_add_hc(device, &ohci_hc_driver);
    107 }
    108 
    109 static const driver_ops_t ohci_driver_ops = {
    110         .dev_add = ohci_dev_add,
    111 };
    112 
    113 static const driver_t ohci_driver = {
    114         .name = NAME,
    115         .driver_ops = &ohci_driver_ops
     56        .hc_add = hc_add,
     57        .irq_code_gen = hc_gen_irq_code,
     58        .claim = hc_gain_control,
     59        .start = hc_start,
     60        .setup_root_hub = hc_setup_roothub,
     61        .hc_gone = hc_gone,
    11662};
    11763
     
    12773{
    12874        log_init(NAME);
    129         return ddf_driver_main(&ohci_driver);
     75        logctl_set_log_level(NAME, LVL_NOTE);
     76        return hc_driver_main(&ohci_driver);
    13077}
    13178
  • uspace/drv/bus/usb/ohci/ohci_batch.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4546
    4647#include "ohci_batch.h"
    47 #include "ohci_endpoint.h"
    48 
    49 static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t);
     48#include "ohci_bus.h"
     49
     50static void (*const batch_setup[])(ohci_transfer_batch_t*);
    5051
    5152/** Safely destructs ohci_transfer_batch_t structure
     
    5354 * @param[in] ohci_batch Instance to destroy.
    5455 */
    55 static void ohci_transfer_batch_dispose(ohci_transfer_batch_t *ohci_batch)
    56 {
    57         if (!ohci_batch)
    58                 return;
    59         if (ohci_batch->tds) {
    60                 const ohci_endpoint_t *ohci_ep =
    61                     ohci_endpoint_get(ohci_batch->usb_batch->ep);
    62                 assert(ohci_ep);
    63                 for (unsigned i = 0; i < ohci_batch->td_count; ++i) {
    64                         if (ohci_batch->tds[i] != ohci_ep->td)
    65                                 free32(ohci_batch->tds[i]);
    66                 }
    67                 free(ohci_batch->tds);
    68         }
    69         usb_transfer_batch_destroy(ohci_batch->usb_batch);
    70         free32(ohci_batch->device_buffer);
     56void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch)
     57{
     58        assert(ohci_batch);
     59        dma_buffer_free(&ohci_batch->ohci_dma_buffer);
    7160        free(ohci_batch);
    7261}
    7362
    74 /** Finishes usb_transfer_batch and destroys the structure.
    75  *
    76  * @param[in] uhci_batch Instance to finish and destroy.
    77  */
    78 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *ohci_batch)
    79 {
    80         assert(ohci_batch);
    81         assert(ohci_batch->usb_batch);
    82         usb_transfer_batch_finish(ohci_batch->usb_batch,
    83             ohci_batch->device_buffer + ohci_batch->usb_batch->setup_size);
    84         ohci_transfer_batch_dispose(ohci_batch);
    85 }
    86 
    8763/** Allocate memory and initialize internal data structure.
    8864 *
    89  * @param[in] usb_batch Pointer to generic USB batch structure.
     65 * @param[in] ep Endpoint for which the batch will be created
    9066 * @return Valid pointer if all structures were successfully created,
    9167 * NULL otherwise.
    92  *
    93  * Determines the number of needed transfer descriptors (TDs).
    94  * Prepares a transport buffer (that is accessible by the hardware).
    95  * Initializes parameters needed for the transfer and callback.
    96  */
    97 ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
    98 {
    99         assert(usb_batch);
     68 */
     69ohci_transfer_batch_t * ohci_transfer_batch_create(endpoint_t *ep)
     70{
     71        assert(ep);
    10072
    10173        ohci_transfer_batch_t *ohci_batch =
     
    10375        if (!ohci_batch) {
    10476                usb_log_error("Failed to allocate OHCI batch data.");
    105                 goto dispose;
    106         }
    107         link_initialize(&ohci_batch->link);
    108         ohci_batch->td_count =
    109             (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1)
     77                return NULL;
     78        }
     79
     80        usb_transfer_batch_init(&ohci_batch->base, ep);
     81
     82        return ohci_batch;
     83}
     84
     85/** Prepares a batch to be sent.
     86 *
     87 * Determines the number of needed transfer descriptors (TDs).
     88 * Prepares a transport buffer (that is accessible by the hardware).
     89 * Initializes parameters needed for the transfer and callback.
     90 */
     91int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch)
     92{
     93        assert(ohci_batch);
     94        usb_transfer_batch_t *usb_batch = &ohci_batch->base;
     95
     96        if (!batch_setup[usb_batch->ep->transfer_type])
     97                return ENOTSUP;
     98
     99        ohci_batch->td_count = (usb_batch->size + OHCI_TD_MAX_TRANSFER - 1)
    110100            / OHCI_TD_MAX_TRANSFER;
    111101        /* Control transfer need Setup and Status stage */
     
    114104        }
    115105
    116         /* We need an extra place for TD that was left at ED */
    117         ohci_batch->tds = calloc(ohci_batch->td_count + 1, sizeof(td_t*));
    118         if (!ohci_batch->tds) {
    119                 usb_log_error("Failed to allocate OHCI transfer descriptors.");
    120                 goto dispose;
    121         }
    122 
    123         /* Add TD left over by the previous transfer */
    124         ohci_batch->ed = ohci_endpoint_get(usb_batch->ep)->ed;
    125         ohci_batch->tds[0] = ohci_endpoint_get(usb_batch->ep)->td;
    126 
    127         for (unsigned i = 1; i <= ohci_batch->td_count; ++i) {
    128                 ohci_batch->tds[i] = malloc32(sizeof(td_t));
    129                 if (!ohci_batch->tds[i]) {
    130                         usb_log_error("Failed to allocate TD %d.", i);
    131                         goto dispose;
    132                 }
    133         }
    134 
    135 
    136         /* NOTE: OHCI is capable of handling buffer that crosses page boundaries
    137          * it is, however, not capable of handling buffer that occupies more
    138          * than two pages (the first page is computed using start pointer, the
    139          * other using the end pointer) */
    140         if (usb_batch->setup_size + usb_batch->buffer_size > 0) {
    141                 /* Use one buffer for setup and data stage */
    142                 ohci_batch->device_buffer =
    143                     malloc32(usb_batch->setup_size + usb_batch->buffer_size);
    144                 if (!ohci_batch->device_buffer) {
    145                         usb_log_error("Failed to allocate device buffer");
    146                         goto dispose;
    147                 }
    148                 /* Copy setup data */
    149                 memcpy(ohci_batch->device_buffer, usb_batch->setup_buffer,
    150                     usb_batch->setup_size);
    151                 /* Copy generic data */
    152                 if (usb_batch->ep->direction != USB_DIRECTION_IN)
    153                         memcpy(
    154                             ohci_batch->device_buffer + usb_batch->setup_size,
    155                             usb_batch->buffer, usb_batch->buffer_size);
    156         }
    157         ohci_batch->usb_batch = usb_batch;
    158 
    159         const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);
    160         assert(batch_setup[usb_batch->ep->transfer_type]);
    161         batch_setup[usb_batch->ep->transfer_type](ohci_batch, dir);
    162 
    163         return ohci_batch;
    164 dispose:
    165         ohci_transfer_batch_dispose(ohci_batch);
    166         return NULL;
     106        /* Alloc one more to NULL terminate */
     107        ohci_batch->tds = calloc(ohci_batch->td_count + 1, sizeof(td_t *));
     108        if (!ohci_batch->tds)
     109                return ENOMEM;
     110
     111        const size_t td_size = ohci_batch->td_count * sizeof(td_t);
     112        const size_t setup_size = (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL)
     113                ? USB_SETUP_PACKET_SIZE
     114                : 0;
     115
     116        if (dma_buffer_alloc(&ohci_batch->ohci_dma_buffer, td_size + setup_size)) {
     117                usb_log_error("Failed to allocate OHCI DMA buffer.");
     118                return ENOMEM;
     119        }
     120
     121        td_t *tds = ohci_batch->ohci_dma_buffer.virt;
     122
     123        for (size_t i = 0; i < ohci_batch->td_count; i++)
     124                ohci_batch->tds[i] = &tds[i];
     125
     126        /* Presence of this terminator makes TD initialization easier */
     127        ohci_batch->tds[ohci_batch->td_count] = NULL;
     128
     129        ohci_batch->setup_buffer = (void *) (&tds[ohci_batch->td_count]);
     130        memcpy(ohci_batch->setup_buffer, usb_batch->setup.buffer, setup_size);
     131
     132        ohci_batch->data_buffer = usb_batch->dma_buffer.virt;
     133
     134        batch_setup[usb_batch->ep->transfer_type](ohci_batch);
     135
     136        return EOK;
    167137}
    168138
     
    176146 * completes with the last TD.
    177147 */
    178 bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *ohci_batch)
    179 {
    180         assert(ohci_batch);
    181         assert(ohci_batch->usb_batch);
    182 
    183         usb_log_debug("Batch %p checking %zu td(s) for completion.\n",
    184             ohci_batch->usb_batch, ohci_batch->td_count);
    185         usb_log_debug2("ED: %08x:%08x:%08x:%08x.\n",
    186             ohci_batch->ed->status, ohci_batch->ed->td_head,
    187             ohci_batch->ed->td_tail, ohci_batch->ed->next);
    188 
    189         if (!ed_inactive(ohci_batch->ed) && ed_transfer_pending(ohci_batch->ed))
     148bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *ohci_batch)
     149{
     150        assert(ohci_batch);
     151
     152        usb_transfer_batch_t *usb_batch = &ohci_batch->base;
     153        ohci_endpoint_t *ohci_ep = ohci_endpoint_get(usb_batch->ep);
     154        assert(ohci_ep);
     155
     156        usb_log_debug("Batch %p checking %zu td(s) for completion.",
     157            ohci_batch, ohci_batch->td_count);
     158        usb_log_debug2("ED: %08x:%08x:%08x:%08x.",
     159            ohci_ep->ed->status, ohci_ep->ed->td_head,
     160            ohci_ep->ed->td_tail, ohci_ep->ed->next);
     161
     162        if (!ed_inactive(ohci_ep->ed) && ed_transfer_pending(ohci_ep->ed))
    190163                return false;
    191164
     
    194167
    195168        /* Assume all data got through */
    196         ohci_batch->usb_batch->transfered_size =
    197             ohci_batch->usb_batch->buffer_size;
    198 
    199         /* Assume we will leave the last(unused) TD behind */
    200         unsigned leave_td = ohci_batch->td_count;
     169        usb_batch->transferred_size = usb_batch->size;
    201170
    202171        /* Check all TDs */
    203172        for (size_t i = 0; i < ohci_batch->td_count; ++i) {
    204173                assert(ohci_batch->tds[i] != NULL);
    205                 usb_log_debug("TD %zu: %08x:%08x:%08x:%08x.\n", i,
     174                usb_log_debug("TD %zu: %08x:%08x:%08x:%08x.", i,
    206175                    ohci_batch->tds[i]->status, ohci_batch->tds[i]->cbp,
    207176                    ohci_batch->tds[i]->next, ohci_batch->tds[i]->be);
    208177
    209                 ohci_batch->usb_batch->error = td_error(ohci_batch->tds[i]);
    210                 if (ohci_batch->usb_batch->error == EOK) {
     178                usb_batch->error = td_error(ohci_batch->tds[i]);
     179                if (usb_batch->error == EOK) {
    211180                        /* If the TD got all its data through, it will report
    212181                         * 0 bytes remain, the sole exception is INPUT with
     
    221190                         * we leave the very last(unused) TD behind.
    222191                         */
    223                         ohci_batch->usb_batch->transfered_size
     192                        usb_batch->transferred_size
    224193                            -= td_remain_size(ohci_batch->tds[i]);
    225194                } else {
    226                         usb_log_debug("Batch %p found error TD(%zu):%08x.\n",
    227                             ohci_batch->usb_batch, i,
    228                             ohci_batch->tds[i]->status);
     195                        usb_log_debug("Batch %p found error TD(%zu):%08x.",
     196                            ohci_batch, i, ohci_batch->tds[i]->status);
    229197
    230198                        /* ED should be stopped because of errors */
    231                         assert((ohci_batch->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0);
    232 
    233                         /* Now we have a problem: we don't know what TD
    234                          * the head pointer points to, the retiring rules
    235                          * described in specs say it should be the one after
    236                          * the failed one so set the tail pointer accordingly.
    237                          * It will be the one TD we leave behind.
     199                        assert((ohci_ep->ed->td_head & ED_TDHEAD_HALTED_FLAG) != 0);
     200
     201                        /* We don't care where the processing stopped, we just
     202                         * need to make sure it's not using any of the TDs owned
     203                         * by the transfer.
     204                         *
     205                         * As the chain is terminated by a TD in ownership of
     206                         * the EP, set it.
    238207                         */
    239                         leave_td = i + 1;
    240 
    241                         /* Check TD assumption */
    242                         assert(ed_head_td(ohci_batch->ed) ==
    243                             addr_to_phys(ohci_batch->tds[leave_td]));
    244 
    245                         /* Set tail to the same TD */
    246                         ed_set_tail_td(ohci_batch->ed,
    247                             ohci_batch->tds[leave_td]);
    248 
    249                         /* Clear possible ED HALT */
    250                         ed_clear_halt(ohci_batch->ed);
     208                        ed_set_head_td(ohci_ep->ed, ohci_ep->tds[0]);
     209
     210                        /* Clear the halted condition for the next transfer */
     211                        ed_clear_halt(ohci_ep->ed);
    251212                        break;
    252213                }
    253214        }
    254         assert(ohci_batch->usb_batch->transfered_size <=
    255             ohci_batch->usb_batch->buffer_size);
    256 
    257         /* Store the remaining TD */
    258         ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->usb_batch->ep);
    259         assert(ohci_ep);
    260         ohci_ep->td = ohci_batch->tds[leave_td];
     215        assert(usb_batch->transferred_size <= usb_batch->size);
    261216
    262217        /* Make sure that we are leaving the right TD behind */
    263         assert(addr_to_phys(ohci_ep->td) == ed_head_td(ohci_batch->ed));
    264         assert(addr_to_phys(ohci_ep->td) == ed_tail_td(ohci_batch->ed));
     218        assert(addr_to_phys(ohci_ep->tds[0]) == ed_tail_td(ohci_ep->ed));
     219        assert(ed_tail_td(ohci_ep->ed) == ed_head_td(ohci_ep->ed));
    265220
    266221        return true;
     
    274229{
    275230        assert(ohci_batch);
    276         ed_set_tail_td(ohci_batch->ed, ohci_batch->tds[ohci_batch->td_count]);
     231
     232        ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->base.ep);
     233
     234        usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.", ohci_ep->ed,
     235            ohci_ep->ed->status, ohci_ep->ed->td_tail,
     236            ohci_ep->ed->td_head, ohci_ep->ed->next);
     237
     238        /*
     239         * According to spec, we need to copy the first TD to the currently
     240         * enqueued one.
     241         */
     242        memcpy(ohci_ep->tds[0], ohci_batch->tds[0], sizeof(td_t));
     243        ohci_batch->tds[0] = ohci_ep->tds[0];
     244
     245        td_t *last = ohci_batch->tds[ohci_batch->td_count - 1];
     246        td_set_next(last, ohci_ep->tds[1]);
     247
     248        ed_set_tail_td(ohci_ep->ed, ohci_ep->tds[1]);
     249
     250        /* Swap the EP TDs for the next transfer */
     251        td_t *tmp = ohci_ep->tds[0];
     252        ohci_ep->tds[0] = ohci_ep->tds[1];
     253        ohci_ep->tds[1] = tmp;
    277254}
    278255
     
    286263 * Status stage with toggle 1 and direction supplied by parameter.
    287264 */
    288 static void batch_control(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir)
    289 {
    290         assert(ohci_batch);
    291         assert(ohci_batch->usb_batch);
     265static void batch_control(ohci_transfer_batch_t *ohci_batch)
     266{
     267        assert(ohci_batch);
     268
     269        usb_direction_t dir = ohci_batch->base.dir;
    292270        assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
    293         usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
    294             ohci_batch->ed->status, ohci_batch->ed->td_tail,
    295             ohci_batch->ed->td_head, ohci_batch->ed->next);
     271
    296272        static const usb_direction_t reverse_dir[] = {
    297273                [USB_DIRECTION_IN]  = USB_DIRECTION_OUT,
     
    300276
    301277        int toggle = 0;
    302         const char* buffer = ohci_batch->device_buffer;
    303278        const usb_direction_t data_dir = dir;
    304279        const usb_direction_t status_dir = reverse_dir[dir];
     
    307282        td_init(
    308283            ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH,
    309             buffer, ohci_batch->usb_batch->setup_size, toggle);
    310         usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.\n",
     284            ohci_batch->setup_buffer, USB_SETUP_PACKET_SIZE, toggle);
     285        usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.",
    311286            ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp,
    312287            ohci_batch->tds[0]->next, ohci_batch->tds[0]->be);
    313         buffer += ohci_batch->usb_batch->setup_size;
    314288
    315289        /* Data stage */
    316290        size_t td_current = 1;
    317         size_t remain_size = ohci_batch->usb_batch->buffer_size;
     291        const char* buffer = ohci_batch->data_buffer;
     292        size_t remain_size = ohci_batch->base.size;
    318293        while (remain_size > 0) {
    319294                const size_t transfer_size =
     
    324299                    ohci_batch->tds[td_current + 1],
    325300                    data_dir, buffer, transfer_size, toggle);
    326                 usb_log_debug("Created CONTROL DATA TD: %08x:%08x:%08x:%08x.\n",
     301                usb_log_debug("Created CONTROL DATA TD: %08x:%08x:%08x:%08x.",
    327302                    ohci_batch->tds[td_current]->status,
    328303                    ohci_batch->tds[td_current]->cbp,
     
    340315        td_init(ohci_batch->tds[td_current], ohci_batch->tds[td_current + 1],
    341316            status_dir, NULL, 0, 1);
    342         usb_log_debug("Created CONTROL STATUS TD: %08x:%08x:%08x:%08x.\n",
     317        usb_log_debug("Created CONTROL STATUS TD: %08x:%08x:%08x:%08x.",
    343318            ohci_batch->tds[td_current]->status,
    344319            ohci_batch->tds[td_current]->cbp,
     
    346321            ohci_batch->tds[td_current]->be);
    347322        usb_log_debug2(
    348             "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.\n", \
    349             ohci_batch->usb_batch,
    350             usb_str_transfer_type(ohci_batch->usb_batch->ep->transfer_type),
     323            "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.", \
     324            &ohci_batch->base,
     325            usb_str_transfer_type(ohci_batch->base.ep->transfer_type),
    351326            usb_str_direction(dir),
    352             USB_TRANSFER_BATCH_ARGS(*ohci_batch->usb_batch));
     327            USB_TRANSFER_BATCH_ARGS(ohci_batch->base));
    353328}
    354329
     
    361336 * OHCI hw in ED.
    362337 */
    363 static void batch_data(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir)
    364 {
    365         assert(ohci_batch);
    366         assert(ohci_batch->usb_batch);
     338static void batch_data(ohci_transfer_batch_t *ohci_batch)
     339{
     340        assert(ohci_batch);
     341
     342        usb_direction_t dir = ohci_batch->base.dir;
    367343        assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
    368         usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
    369             ohci_batch->ed->status, ohci_batch->ed->td_tail,
    370             ohci_batch->ed->td_head, ohci_batch->ed->next);
    371344
    372345        size_t td_current = 0;
    373         size_t remain_size = ohci_batch->usb_batch->buffer_size;
    374         char *buffer = ohci_batch->device_buffer;
     346        size_t remain_size = ohci_batch->base.size;
     347        char *buffer = ohci_batch->data_buffer;
    375348        while (remain_size > 0) {
    376349                const size_t transfer_size = remain_size > OHCI_TD_MAX_TRANSFER
     
    381354                    dir, buffer, transfer_size, -1);
    382355
    383                 usb_log_debug("Created DATA TD: %08x:%08x:%08x:%08x.\n",
     356                usb_log_debug("Created DATA TD: %08x:%08x:%08x:%08x.",
    384357                    ohci_batch->tds[td_current]->status,
    385358                    ohci_batch->tds[td_current]->cbp,
     
    393366        }
    394367        usb_log_debug2(
    395             "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.\n", \
    396             ohci_batch->usb_batch,
    397             usb_str_transfer_type(ohci_batch->usb_batch->ep->transfer_type),
     368            "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.", \
     369            &ohci_batch->base,
     370            usb_str_transfer_type(ohci_batch->base.ep->transfer_type),
    398371            usb_str_direction(dir),
    399             USB_TRANSFER_BATCH_ARGS(*ohci_batch->usb_batch));
     372            USB_TRANSFER_BATCH_ARGS(ohci_batch->base));
    400373}
    401374
    402375/** Transfer setup table. */
    403 static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t) =
     376static void (*const batch_setup[])(ohci_transfer_batch_t*) =
    404377{
    405378        [USB_TRANSFER_CONTROL] = batch_control,
  • uspace/drv/bus/usb/ohci/ohci_batch.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    3839#include <assert.h>
    3940#include <stdbool.h>
     41#include <usb/dma_buffer.h>
    4042#include <usb/host/usb_transfer_batch.h>
    4143
     
    4547/** OHCI specific data required for USB transfer */
    4648typedef struct ohci_transfer_batch {
    47         /** Link */
    48         link_t link;
    49         /** Endpoint descriptor of the target endpoint. */
    50         ed_t *ed;
    51         /** List of TDs needed for the transfer */
    52         td_t **tds;
     49        usb_transfer_batch_t base;
     50
    5351        /** Number of TDs used by the transfer */
    5452        size_t td_count;
    55         /** Data buffer, must be accessible by the OHCI hw. */
    56         char *device_buffer;
    57         /** Generic USB transfer structure */
    58         usb_transfer_batch_t *usb_batch;
     53
     54        /**
     55         * List of TDs needed for the transfer - together with setup data
     56         * backed by the dma buffer. Note that the TD pointers are pointing to
     57         * the DMA buffer initially, but as the scheduling must use the first TD
     58         * from EP, it is replaced.
     59         */
     60        td_t **tds;
     61        char *setup_buffer;
     62        char *data_buffer;
     63
     64        dma_buffer_t ohci_dma_buffer;
    5965} ohci_transfer_batch_t;
    6066
    61 ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *batch);
    62 bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *batch);
     67ohci_transfer_batch_t *ohci_transfer_batch_create(endpoint_t *batch);
     68int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch);
    6369void ohci_transfer_batch_commit(const ohci_transfer_batch_t *batch);
    64 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *batch);
     70bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *batch);
     71void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch);
    6572
    66 static inline ohci_transfer_batch_t *ohci_transfer_batch_from_link(link_t *l)
     73static inline ohci_transfer_batch_t *ohci_transfer_batch_get(
     74    usb_transfer_batch_t *usb_batch)
    6775{
    68         assert(l);
    69         return list_get_instance(l, ohci_transfer_batch_t, link);
     76        assert(usb_batch);
     77
     78        return (ohci_transfer_batch_t *) usb_batch;
    7079}
     80
    7181#endif
    7282/**
  • uspace/drv/bus/usb/ohci/ohci_bus.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    3233 * @brief OHCI driver
    3334 */
    34 #ifndef DRV_OHCI_HCD_ENDPOINT_H
    35 #define DRV_OHCI_HCD_ENDPOINT_H
     35#ifndef DRV_OHCI_HCD_BUS_H
     36#define DRV_OHCI_HCD_BUS_H
    3637
    3738#include <assert.h>
    3839#include <adt/list.h>
    39 #include <usb/host/endpoint.h>
    40 #include <usb/host/hcd.h>
     40#include <usb/dma_buffer.h>
     41#include <usb/host/usb2_bus.h>
    4142
    4243#include "hw_struct/endpoint_descriptor.h"
    4344#include "hw_struct/transfer_descriptor.h"
    4445
    45 /** Connector structure linking ED to to prepared TD. */
     46/**
     47 * Connector structure linking ED to to prepared TD.
     48 *
     49 * OHCI requires new transfers to be appended at the end of a queue. But it has
     50 * a weird semantics of a leftover TD, which serves as a placeholder. This left
     51 * TD is overwritten with first TD of a new transfer, and the spare one is used
     52 * as the next placeholder. Then the two are swapped for the next transaction.
     53 */
    4654typedef struct ohci_endpoint {
     55        endpoint_t base;
     56
    4757        /** OHCI endpoint descriptor */
    4858        ed_t *ed;
    49         /** Currently enqueued transfer descriptor */
    50         td_t *td;
    51         /** Linked list used by driver software */
    52         link_t link;
     59        /** TDs to be used at the beginning and end of transaction */
     60        td_t *tds [2];
     61
     62        /** Buffer to back ED + 2 TD */
     63        dma_buffer_t dma_buffer;
     64
     65        /** Link in endpoint_list*/
     66        link_t eplist_link;
     67        /** Link in pending_endpoints */
     68        link_t pending_link;
    5369} ohci_endpoint_t;
    5470
    55 errno_t ohci_endpoint_init(hcd_t *hcd, endpoint_t *ep);
    56 void ohci_endpoint_fini(hcd_t *hcd, endpoint_t *ep);
     71typedef struct hc hc_t;
     72
     73typedef struct {
     74        bus_t base;
     75        usb2_bus_helper_t helper;
     76        hc_t *hc;
     77} ohci_bus_t;
     78
     79errno_t ohci_bus_init(ohci_bus_t *, hc_t *);
     80void ohci_ep_toggle_reset(endpoint_t *);
    5781
    5882/** Get and convert assigned ohci_endpoint_t structure
     
    6387{
    6488        assert(ep);
    65         return ep->hc_data.data;
     89        return (ohci_endpoint_t *) ep;
    6690}
    6791
  • uspace/drv/bus/usb/ohci/ohci_rh.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2013 Jan Vesely
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    109110 * initializes internal virtual hub.
    110111 */
    111 errno_t ohci_rh_init(ohci_rh_t *instance, ohci_regs_t *regs, const char *name)
     112errno_t ohci_rh_init(ohci_rh_t *instance, ohci_regs_t *regs,
     113    fibril_mutex_t *guard, const char *name)
    112114{
    113115        assert(instance);
    114116        instance->registers = regs;
    115117        instance->port_count = OHCI_RD(regs->rh_desc_a) & RHDA_NDS_MASK;
    116         usb_log_debug2("rh_desc_a: %x.\n", OHCI_RD(regs->rh_desc_a));
     118        usb_log_debug2("rh_desc_a: %x.", OHCI_RD(regs->rh_desc_a));
    117119        if (instance->port_count > OHCI_MAX_PORTS) {
    118120                usb_log_warning("OHCI specification does not allow %d ports. "
    119                     "Max %d ports will be used.\n", instance->port_count,
     121                    "Max %d ports will be used.", instance->port_count,
    120122                    OHCI_MAX_PORTS);
    121123                instance->port_count = OHCI_MAX_PORTS;
    122124        }
    123         usb_log_info("%s: Found %u ports.\n", name, instance->port_count);
     125        usb_log_info("%s: Found %u ports.", name, instance->port_count);
    124126
    125127#if defined OHCI_POWER_SWITCH_no
    126         usb_log_info("%s: Set power mode to no power switching.\n", name);
     128        usb_log_info("%s: Set power mode to no power switching.", name);
    127129        /* Set port power mode to no power-switching. (always on) */
    128130        OHCI_SET(regs->rh_desc_a, RHDA_NPS_FLAG);
     
    132134
    133135#elif defined OHCI_POWER_SWITCH_ganged
    134         usb_log_info("%s: Set power mode to ganged power switching.\n", name);
     136        usb_log_info("%s: Set power mode to ganged power switching.", name);
    135137        /* Set port power mode to ganged power-switching. */
    136138        OHCI_CLR(regs->rh_desc_a, RHDA_NPS_FLAG);
     
    144146        OHCI_CLR(regs->rh_desc_a, RHDA_OCPM_FLAG);
    145147#else
    146         usb_log_info("%s: Set power mode to per-port power switching.\n", name);
     148        usb_log_info("%s: Set power mode to per-port power switching.", name);
    147149        /* Set port power mode to per port power-switching. */
    148150        OHCI_CLR(regs->rh_desc_a, RHDA_NPS_FLAG);
     
    162164
    163165        ohci_rh_hub_desc_init(instance);
    164         instance->unfinished_interrupt_transfer = NULL;
     166        instance->status_change_endpoint = NULL;
     167        instance->guard = guard;
    165168        return virthub_base_init(&instance->base, name, &ops, instance,
    166169            NULL, &instance->hub_descriptor.header, HUB_STATUS_CHANGE_PIPE);
     
    178181        assert(instance);
    179182        assert(batch);
    180         const usb_target_t target = {{
    181                 .address = batch->ep->address,
    182                 .endpoint = batch->ep->endpoint,
    183         }};
    184         batch->error = virthub_base_request(&instance->base, target,
    185             usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,
    186             batch->buffer, batch->buffer_size, &batch->transfered_size);
     183        batch->error = virthub_base_request(&instance->base, batch->target,
     184            batch->dir, &batch->setup.packet,
     185            batch->dma_buffer.virt, batch->size, &batch->transferred_size);
    187186        if (batch->error == ENAK) {
    188                 /* This is safe because only status change interrupt transfers
    189                  * return NAK. The assertion holds true because the batch
    190                  * existence prevents communication with that ep */
    191                 assert(instance->unfinished_interrupt_transfer == NULL);
    192                 instance->unfinished_interrupt_transfer = batch;
     187                /* Lock the HC guard */
     188                fibril_mutex_lock(instance->guard);
     189                const int err = endpoint_activate_locked(batch->ep, batch);
     190                if (err) {
     191                        fibril_mutex_unlock(batch->ep->guard);
     192                        return err;
     193                }
     194
     195                /*
     196                 * Asserting that the HC do not run two instances of the status
     197                 * change endpoint - shall be true.
     198                 */
     199                assert(!instance->status_change_endpoint);
     200
     201                endpoint_add_ref(batch->ep);
     202                instance->status_change_endpoint = batch->ep;
     203                fibril_mutex_unlock(instance->guard);
    193204        } else {
    194                 usb_transfer_batch_finish(batch, NULL);
    195                 usb_transfer_batch_destroy(batch);
     205                usb_transfer_batch_finish(batch);
    196206        }
    197207        return EOK;
     
    207217errno_t ohci_rh_interrupt(ohci_rh_t *instance)
    208218{
    209         //TODO atomic swap needed
    210         usb_transfer_batch_t *batch = instance->unfinished_interrupt_transfer;
    211         instance->unfinished_interrupt_transfer = NULL;
     219        fibril_mutex_lock(instance->guard);
     220        endpoint_t *ep = instance->status_change_endpoint;
     221        if (!ep) {
     222                fibril_mutex_unlock(instance->guard);
     223                return EOK;
     224        }
     225
     226        usb_transfer_batch_t * const batch = ep->active_batch;
     227        endpoint_deactivate_locked(ep);
     228        instance->status_change_endpoint = NULL;
     229        fibril_mutex_unlock(instance->guard);
     230
     231        endpoint_del_ref(ep);
     232
    212233        if (batch) {
    213                 const usb_target_t target = {{
    214                         .address = batch->ep->address,
    215                         .endpoint = batch->ep->endpoint,
    216                 }};
    217                 batch->error = virthub_base_request(&instance->base, target,
    218                     usb_transfer_batch_direction(batch),
    219                     (void*)batch->setup_buffer,
    220                     batch->buffer, batch->buffer_size, &batch->transfered_size);
    221                 usb_transfer_batch_finish(batch, NULL);
    222                 usb_transfer_batch_destroy(batch);
     234                batch->error = virthub_base_request(&instance->base, batch->target,
     235                    batch->dir, &batch->setup.packet,
     236                    batch->dma_buffer.virt, batch->size, &batch->transferred_size);
     237                usb_transfer_batch_finish(batch);
    223238        }
    224239        return EOK;
     
    351366                }
    352367
    353         case USB_HUB_FEATURE_PORT_ENABLE:         /*1*/
     368        case USB2_HUB_FEATURE_PORT_ENABLE:         /*1*/
    354369                OHCI_WR(hub->registers->rh_port_status[port],
    355370                    RHPS_CLEAR_PORT_ENABLE);
    356371                return EOK;
    357372
    358         case USB_HUB_FEATURE_PORT_SUSPEND:        /*2*/
     373        case USB2_HUB_FEATURE_PORT_SUSPEND:        /*2*/
    359374                OHCI_WR(hub->registers->rh_port_status[port],
    360375                    RHPS_CLEAR_PORT_SUSPEND);
     
    362377
    363378        case USB_HUB_FEATURE_C_PORT_CONNECTION:   /*16*/
    364         case USB_HUB_FEATURE_C_PORT_ENABLE:       /*17*/
    365         case USB_HUB_FEATURE_C_PORT_SUSPEND:      /*18*/
     379        case USB2_HUB_FEATURE_C_PORT_ENABLE:       /*17*/
     380        case USB2_HUB_FEATURE_C_PORT_SUSPEND:      /*18*/
    366381        case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: /*19*/
    367382        case USB_HUB_FEATURE_C_PORT_RESET:        /*20*/
    368383                usb_log_debug2("Clearing port C_CONNECTION, C_ENABLE, "
    369                     "C_SUSPEND, C_OC or C_RESET on port %u.\n", port);
     384                    "C_SUSPEND, C_OC or C_RESET on port %u.", port);
    370385                /* Bit offsets correspond to the feature number */
    371386                OHCI_WR(hub->registers->rh_port_status[port],
     
    412427                /* Fall through, for per port power */
    413428                /* Fallthrough */
    414         case USB_HUB_FEATURE_PORT_ENABLE:  /*1*/
    415         case USB_HUB_FEATURE_PORT_SUSPEND: /*2*/
     429        case USB2_HUB_FEATURE_PORT_ENABLE:  /*1*/
     430        case USB2_HUB_FEATURE_PORT_SUSPEND: /*2*/
    416431        case USB_HUB_FEATURE_PORT_RESET:   /*4*/
    417432                usb_log_debug2("Setting port POWER, ENABLE, SUSPEND or RESET "
    418                     "on port %u.\n", port);
     433                    "on port %u.", port);
    419434                /* Bit offsets correspond to the feature number */
    420435                OHCI_WR(hub->registers->rh_port_status[port], 1 << feature);
     
    462477        }
    463478
    464         usb_log_debug2("OHCI root hub interrupt mask: %hx.\n", mask);
     479        usb_log_debug2("OHCI root hub interrupt mask: %hx.", mask);
    465480
    466481        if (mask == 0)
  • uspace/drv/bus/usb/ohci/ohci_rh.h

    rf5e5f73 rdf6ded8  
    6161                uint8_t rempow[STATUS_BYTES(OHCI_MAX_PORTS) * 2];
    6262        } __attribute__((packed)) hub_descriptor;
    63         /** interrupt transfer waiting for an actual interrupt to occur */
    64         usb_transfer_batch_t *unfinished_interrupt_transfer;
     63        /** A hacky way to emulate interrupts over polling. See ehci_rh. */
     64        endpoint_t *status_change_endpoint;
     65        fibril_mutex_t *guard;
    6566} ohci_rh_t;
    6667
    67 errno_t ohci_rh_init(ohci_rh_t *instance, ohci_regs_t *regs, const char *name);
     68errno_t ohci_rh_init(ohci_rh_t *, ohci_regs_t *, fibril_mutex_t *, const char *);
    6869errno_t ohci_rh_schedule(ohci_rh_t *instance, usb_transfer_batch_t *batch);
    6970errno_t ohci_rh_interrupt(ohci_rh_t *instance);
  • 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" : "" );
  • uspace/drv/bus/usb/usbflbk/main.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
     3 * Copyright (c) 2018 Petr Manek
    34 * All rights reserved.
    45 *
     
    4849static errno_t usbfallback_device_add(usb_device_t *dev)
    4950{
    50         usb_log_info("Pretending to control %s `%s'.\n",
     51        usb_log_info("Pretending to control %s `%s'.",
    5152            usb_device_get_iface_number(dev) < 0 ? "device" : "interface",
    5253            usb_device_get_name(dev));
     
    6263{
    6364        assert(dev);
     65        usb_log_info("Device '%s' gone.", usb_device_get_name(dev));
     66        return EOK;
     67}
     68
     69static errno_t usbfallback_device_remove(usb_device_t *dev)
     70{
     71        assert(dev);
     72        usb_log_info("Device '%s' removed.", usb_device_get_name(dev));
    6473        return EOK;
    6574}
     
    6877static const usb_driver_ops_t usbfallback_driver_ops = {
    6978        .device_add = usbfallback_device_add,
    70         .device_rem = usbfallback_device_gone,
     79        .device_remove = usbfallback_device_remove,
    7180        .device_gone = usbfallback_device_gone,
    7281};
  • uspace/drv/bus/usb/usbhub/main.c

    rf5e5f73 rdf6ded8  
    4848static const usb_driver_ops_t usb_hub_driver_ops = {
    4949        .device_add = usb_hub_device_add,
    50 //      .device_rem = usb_hub_device_remove,
     50        .device_remove = usb_hub_device_remove,
    5151        .device_gone = usb_hub_device_gone,
    5252};
    5353
    54 /** Hub endpoints, excluding control endpoint. */
    55 static const usb_endpoint_description_t *usb_hub_endpoints[] = {
    56         &hub_status_change_endpoint_description,
    57         NULL,
    58 };
    5954/** Static usb hub driver information. */
    6055static const usb_driver_t usb_hub_driver = {
  • uspace/drv/bus/usb/usbhub/port.c

    rf5e5f73 rdf6ded8  
    22 * Copyright (c) 2011 Vojtech Horky
    33 * Copyright (c) 2011 Jan Vesely
     4 * Copyright (c) 2018 Ondrej Hlavaty
    45 * All rights reserved.
    56 *
     
    4041#include <inttypes.h>
    4142#include <fibril_synch.h>
     43#include <usbhc_iface.h>
    4244
    4345#include <usb/debug.h>
     
    4749#include "status.h"
    4850
    49 /** Information for fibril for device discovery. */
    50 struct add_device_phase1 {
    51         usb_hub_dev_t *hub;
    52         usb_hub_port_t *port;
    53         usb_speed_t speed;
    54 };
    55 
    56 static errno_t usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub);
    57 static void usb_hub_port_reset_completed(usb_hub_port_t *port,
    58     usb_hub_dev_t *hub, usb_port_status_t status);
    59 static errno_t get_port_status(usb_hub_port_t *port, usb_port_status_t *status);
    60 static errno_t add_device_phase1_worker_fibril(void *arg);
    61 static errno_t create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
    62     usb_speed_t speed);
    63 
    64 errno_t usb_hub_port_fini(usb_hub_port_t *port, usb_hub_dev_t *hub)
     51#define port_log(lvl, port, fmt, ...) do { \
     52                usb_log_##lvl("(%p-%u): " fmt, \
     53                    (port->hub), (port->port_number), ##__VA_ARGS__); \
     54        } while (0)
     55
     56/** Initialize hub port information.
     57 *
     58 * @param port Port to be initialized.
     59 */
     60void usb_hub_port_init(usb_hub_port_t *port, usb_hub_dev_t *hub,
     61    unsigned int port_number)
    6562{
    6663        assert(port);
    67         if (port->device_attached)
    68                 return usb_hub_port_device_gone(port, hub);
     64        memset(port, 0, sizeof(*port));
     65        port->hub = hub;
     66        port->port_number = port_number;
     67        usb_port_init(&port->base);
     68}
     69
     70static inline usb_hub_port_t *get_hub_port(usb_port_t *port)
     71{
     72        assert(port);
     73        return (usb_hub_port_t *) port;
     74}
     75
     76/**
     77 * Inform the HC that the device on port is gone.
     78 */
     79static void remove_device(usb_port_t *port_base)
     80{
     81        usb_hub_port_t *port = get_hub_port(port_base);
     82
     83        async_exch_t *exch = usb_device_bus_exchange_begin(port->hub->usb_device);
     84        if (!exch) {
     85                port_log(error, port, "Cannot remove the device, "
     86                    "failed creating exchange.");
     87                return;
     88        }
     89       
     90        const errno_t err = usbhc_device_remove(exch, port->port_number);
     91        if (err)
     92                port_log(error, port, "Failed to remove device: %s",
     93                    str_error(err));
     94
     95        usb_device_bus_exchange_end(exch);
     96}
     97
     98
     99static usb_speed_t get_port_speed(usb_hub_port_t *port, uint32_t status)
     100{
     101        assert(port);
     102        assert(port->hub);
     103
     104        return usb_port_speed(port->hub->speed, status);
     105}
     106
     107/**
     108 * Routine for adding a new device in USB2.
     109 */
     110static errno_t enumerate_device_usb2(usb_hub_port_t *port, async_exch_t *exch)
     111{
     112        errno_t err;
     113
     114        port_log(debug, port, "Requesting default address.");
     115        err = usb_hub_reserve_default_address(port->hub, exch, &port->base);
     116        if (err != EOK) {
     117                port_log(error, port, "Failed to reserve default address: %s",
     118                    str_error(err));
     119                return err;
     120        }
     121
     122        /* Reservation of default address could have blocked */
     123        if (port->base.state != PORT_CONNECTING)
     124                goto out_address;
     125
     126        port_log(debug, port, "Resetting port.");
     127        if ((err = usb_hub_set_port_feature(port->hub, port->port_number,
     128                            USB_HUB_FEATURE_PORT_RESET))) {
     129                port_log(warning, port, "Port reset request failed: %s",
     130                    str_error(err));
     131                goto out_address;
     132        }
     133
     134        if ((err = usb_port_wait_for_enabled(&port->base))) {
     135                port_log(error, port, "Failed to reset port: %s",
     136                    str_error(err));
     137                goto out_address;
     138        }
     139
     140        port_log(debug, port, "Enumerating device.");
     141        if ((err = usbhc_device_enumerate(exch, port->port_number,
     142                            port->speed))) {
     143                port_log(error, port, "Failed to enumerate device: %s",
     144                    str_error(err));
     145                /* Disable the port */
     146                usb_hub_clear_port_feature(port->hub, port->port_number,
     147                    USB2_HUB_FEATURE_PORT_ENABLE);
     148                goto out_address;
     149        }
     150
     151        port_log(debug, port, "Device enumerated");
     152
     153out_address:
     154        usb_hub_release_default_address(port->hub, exch);
     155        return err;
     156}
     157
     158/**
     159 * Routine for adding a new device in USB 3.
     160 */
     161static errno_t enumerate_device_usb3(usb_hub_port_t *port, async_exch_t *exch)
     162{
     163        errno_t err;
     164
     165        port_log(debug, port, "Issuing a warm reset.");
     166        if ((err = usb_hub_set_port_feature(port->hub, port->port_number,
     167                            USB3_HUB_FEATURE_BH_PORT_RESET))) {
     168                port_log(warning, port, "Port reset request failed: %s",
     169                    str_error(err));
     170                return err;
     171        }
     172
     173        if ((err = usb_port_wait_for_enabled(&port->base))) {
     174                port_log(error, port, "Failed to reset port: %s",
     175                    str_error(err));
     176                return err;
     177        }
     178
     179        port_log(debug, port, "Enumerating device.");
     180        if ((err = usbhc_device_enumerate(exch, port->port_number,
     181                            port->speed))) {
     182                port_log(error, port, "Failed to enumerate device: %s",
     183                    str_error(err));
     184                return err;
     185        }
     186
     187        port_log(debug, port, "Device enumerated");
    69188        return EOK;
    70189}
    71190
    72 /**
    73  * Clear feature on hub port.
    74  *
    75  * @param port Port structure.
    76  * @param feature Feature selector.
    77  * @return Operation result
    78  */
    79 errno_t usb_hub_port_clear_feature(
    80     usb_hub_port_t *port, usb_hub_class_feature_t feature)
    81 {
    82         assert(port);
    83         const usb_device_request_setup_packet_t clear_request = {
    84                 .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
    85                 .request = USB_DEVREQ_CLEAR_FEATURE,
    86                 .value = feature,
    87                 .index = port->port_number,
    88                 .length = 0,
    89         };
    90         return usb_pipe_control_write(port->control_pipe, &clear_request,
    91             sizeof(clear_request), NULL, 0);
    92 }
    93 
    94 /**
    95  * Set feature on hub port.
    96  *
    97  * @param port Port structure.
    98  * @param feature Feature selector.
    99  * @return Operation result
    100  */
    101 errno_t usb_hub_port_set_feature(
    102     usb_hub_port_t *port, usb_hub_class_feature_t feature)
    103 {
    104         assert(port);
    105         const usb_device_request_setup_packet_t clear_request = {
    106                 .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE,
    107                 .request = USB_DEVREQ_SET_FEATURE,
    108                 .index = port->port_number,
    109                 .value = feature,
    110                 .length = 0,
    111         };
    112         return usb_pipe_control_write(port->control_pipe, &clear_request,
    113             sizeof(clear_request), NULL, 0);
    114 }
    115 
    116 /**
    117  * Mark reset process as failed due to external reasons
    118  *
    119  * @param port Port structure
    120  */
    121 void usb_hub_port_reset_fail(usb_hub_port_t *port)
    122 {
    123         assert(port);
    124         fibril_mutex_lock(&port->mutex);
    125         if (port->reset_status == IN_RESET)
    126                 port->reset_status = RESET_FAIL;
    127         fibril_condvar_broadcast(&port->reset_cv);
    128         fibril_mutex_unlock(&port->mutex);
     191static errno_t enumerate_device(usb_port_t *port_base)
     192{
     193        usb_hub_port_t *port = get_hub_port(port_base);
     194
     195        port_log(debug, port, "Setting up new device.");
     196        async_exch_t *exch = usb_device_bus_exchange_begin(port->hub->usb_device);
     197        if (!exch) {
     198                port_log(error, port, "Failed to create exchange.");
     199                return ENOMEM;
     200        }
     201
     202        const errno_t err = port->hub->speed == USB_SPEED_SUPER
     203                ? enumerate_device_usb3(port, exch)
     204                : enumerate_device_usb2(port, exch);
     205
     206        usb_device_bus_exchange_end(exch);
     207        return err;
     208}
     209
     210static void port_changed_connection(usb_hub_port_t *port, usb_port_status_t status)
     211{
     212        const bool connected = !!(status & USB_HUB_PORT_STATUS_CONNECTION);
     213        port_log(debug, port, "Connection change: device %s.", connected
     214            ? "attached" : "removed");
     215
     216        if (connected) {
     217                usb_port_connected(&port->base, &enumerate_device);
     218        } else {
     219                usb_port_disabled(&port->base, &remove_device);
     220        }
     221}
     222
     223static void port_changed_enabled(usb_hub_port_t *port, usb_port_status_t status)
     224{
     225        const bool enabled = !!(status & USB_HUB_PORT_STATUS_ENABLE);
     226        if (enabled) {
     227                port_log(warning, port, "Port unexpectedly changed to enabled.");
     228        } else {
     229                usb_port_disabled(&port->base, &remove_device);
     230        }
     231}
     232
     233static void port_changed_overcurrent(usb_hub_port_t *port,
     234    usb_port_status_t status)
     235{
     236        const bool overcurrent = !!(status & USB_HUB_PORT_STATUS_OC);
     237
     238        /* According to the USB specs:
     239         * 11.13.5 Over-current Reporting and Recovery
     240         * Hub device is responsible for putting port in power off
     241         * mode. USB system software is responsible for powering port
     242         * back on when the over-current condition is gone */
     243
     244        usb_port_disabled(&port->base, &remove_device);
     245
     246        if (!overcurrent) {
     247                const errno_t err = usb_hub_set_port_feature(port->hub,
     248                    port->port_number, USB_HUB_FEATURE_PORT_POWER);
     249                if (err)
     250                        port_log(error, port, "Failed to set port power "
     251                            "after OC: %s.", str_error(err));
     252        }
     253}
     254
     255static void port_changed_reset(usb_hub_port_t *port, usb_port_status_t status)
     256{
     257        const bool enabled = !!(status & USB_HUB_PORT_STATUS_ENABLE);
     258
     259        if (enabled) {
     260                port->speed = get_port_speed(port, status);
     261                usb_port_enabled(&port->base);
     262        } else
     263                usb_port_disabled(&port->base, &remove_device);
     264}
     265
     266typedef void (*change_handler_t)(usb_hub_port_t *, usb_port_status_t);
     267
     268static void check_port_change(usb_hub_port_t *port, usb_port_status_t *status,
     269    change_handler_t handler, usb_port_status_t mask,
     270    usb_hub_class_feature_t feature)
     271{
     272        if ((*status & mask) == 0)
     273                return;
     274
     275        /* Clear the change so it won't come again */
     276        usb_hub_clear_port_feature(port->hub, port->port_number, feature);
     277
     278        if (handler)
     279                handler(port, *status);
     280
     281        /* Mark the change as resolved */
     282        *status &= ~mask;
    129283}
    130284
     
    136290 * @param hub hub representation
    137291 */
    138 void usb_hub_port_process_interrupt(usb_hub_port_t *port, usb_hub_dev_t *hub)
     292void usb_hub_port_process_interrupt(usb_hub_port_t *port)
    139293{
    140294        assert(port);
    141         assert(hub);
    142         usb_log_debug2("(%p-%u): Interrupt.\n", hub, port->port_number);
     295        port_log(debug2, port, "Interrupt.");
    143296
    144297        usb_port_status_t status = 0;
    145         const errno_t opResult = get_port_status(port, &status);
    146         if (opResult != EOK) {
    147                 usb_log_error("(%p-%u): Failed to get port status: %s.\n", hub,
    148                     port->port_number, str_error(opResult));
     298        const errno_t err = usb_hub_get_port_status(port->hub,
     299            port->port_number, &status);
     300        if (err != EOK) {
     301                port_log(error, port, "Failed to get port status: %s.",
     302                    str_error(err));
    149303                return;
    150304        }
    151305
    152         /* Connection change */
    153         if (status & USB_HUB_PORT_C_STATUS_CONNECTION) {
    154                 const bool connected =
    155                     (status & USB_HUB_PORT_STATUS_CONNECTION) != 0;
    156                 usb_log_debug("(%p-%u): Connection change: device %s.\n", hub,
    157                     port->port_number, connected ? "attached" : "removed");
    158 
    159                 /* ACK the change */
    160                 const errno_t opResult = usb_hub_port_clear_feature(port,
    161                     USB_HUB_FEATURE_C_PORT_CONNECTION);
    162                 if (opResult != EOK) {
    163                         usb_log_warning("(%p-%u): Failed to clear "
    164                             "port-change-connection flag: %s.\n", hub,
    165                             port->port_number, str_error(opResult));
    166                 }
    167 
    168                 if (connected) {
    169                         const errno_t opResult = create_add_device_fibril(port, hub,
    170                             usb_port_speed(status));
    171                         if (opResult != EOK) {
    172                                 usb_log_error("(%p-%u): Cannot handle change on"
    173                                    " port: %s.\n", hub, port->port_number,
    174                                    str_error(opResult));
    175                         }
    176                 } else {
    177                         /* Handle the case we were in reset */
    178                         // FIXME: usb_hub_port_reset_fail(port);
    179                         /* If enabled change was reported leave the removal
    180                          * to that handler, it shall ACK the change too. */
    181                         if (!(status & USB_HUB_PORT_C_STATUS_ENABLED)) {
    182                                 usb_hub_port_device_gone(port, hub);
    183                         }
    184                 }
    185         }
    186 
    187         /* Enable change, ports are automatically disabled on errors. */
    188         if (status & USB_HUB_PORT_C_STATUS_ENABLED) {
    189                 // TODO: maybe HS reset failed?
    190                 usb_log_info("(%p-%u): Port disabled because of errors.\n", hub,
    191                    port->port_number);
    192                 usb_hub_port_device_gone(port, hub);
    193                 const errno_t rc = usb_hub_port_clear_feature(port,
    194                         USB_HUB_FEATURE_C_PORT_ENABLE);
    195                 if (rc != EOK) {
    196                         usb_log_error("(%p-%u): Failed to clear port enable "
    197                             "change feature: %s.", hub, port->port_number,
    198                             str_error(rc));
    199                 }
    200 
    201         }
    202 
    203         /* Suspend change */
    204         if (status & USB_HUB_PORT_C_STATUS_SUSPEND) {
    205                 usb_log_error("(%p-%u): Port went to suspend state, this should"
    206                     " NOT happen as we do not support suspend state!", hub,
    207                     port->port_number);
    208                 const errno_t rc = usb_hub_port_clear_feature(port,
    209                         USB_HUB_FEATURE_C_PORT_SUSPEND);
    210                 if (rc != EOK) {
    211                         usb_log_error("(%p-%u): Failed to clear port suspend "
    212                             "change feature: %s.", hub, port->port_number,
    213                             str_error(rc));
    214                 }
    215         }
    216 
    217         /* Over current */
    218         if (status & USB_HUB_PORT_C_STATUS_OC) {
    219                 usb_log_debug("(%p-%u): Port OC reported!.", hub,
    220                     port->port_number);
    221                 /* According to the USB specs:
    222                  * 11.13.5 Over-current Reporting and Recovery
    223                  * Hub device is responsible for putting port in power off
    224                  * mode. USB system software is responsible for powering port
    225                  * back on when the over-current condition is gone */
    226                 const errno_t rc = usb_hub_port_clear_feature(port,
    227                     USB_HUB_FEATURE_C_PORT_OVER_CURRENT);
    228                 if (rc != EOK) {
    229                         usb_log_error("(%p-%u): Failed to clear port OC change "
    230                             "feature: %s.\n", hub, port->port_number,
    231                             str_error(rc));
    232                 }
    233                 if (!(status & ~USB_HUB_PORT_STATUS_OC)) {
    234                         const errno_t rc = usb_hub_port_set_feature(
    235                             port, USB_HUB_FEATURE_PORT_POWER);
    236                         if (rc != EOK) {
    237                                 usb_log_error("(%p-%u): Failed to set port "
    238                                     "power after OC: %s.", hub,
    239                                     port->port_number, str_error(rc));
    240                         }
    241                 }
    242         }
    243 
    244         /* Port reset, set on port reset complete. */
    245         if (status & USB_HUB_PORT_C_STATUS_RESET) {
    246                 usb_hub_port_reset_completed(port, hub, status);
    247         }
    248 
    249         usb_log_debug2("(%p-%u): Port status %#08" PRIx32, hub,
    250             port->port_number, status);
    251 }
    252 
    253 /**
    254  * routine called when a device on port has been removed
    255  *
    256  * If the device on port had default address, it releases default address.
    257  * Otherwise does not do anything, because DDF does not allow to remove device
    258  * from it`s device tree.
    259  * @param port port structure
    260  * @param hub hub representation
    261  */
    262 errno_t usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub)
    263 {
    264         assert(port);
    265         assert(hub);
    266         async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device);
    267         if (!exch)
    268                 return ENOMEM;
    269         const errno_t rc = usb_device_remove(exch, port->port_number);
    270         usb_device_bus_exchange_end(exch);
    271         if (rc == EOK)
    272                 port->device_attached = false;
    273         return rc;
    274 
    275 }
    276 
    277 /**
    278  * Process port reset change
    279  *
    280  * After this change port should be enabled, unless some problem occurred.
    281  * This functions triggers second phase of enabling new device.
    282  * @param port Port structure
    283  * @param status Port status mask
    284  */
    285 void usb_hub_port_reset_completed(usb_hub_port_t *port, usb_hub_dev_t *hub,
    286     usb_port_status_t status)
    287 {
    288         assert(port);
    289         fibril_mutex_lock(&port->mutex);
    290         const bool enabled = (status & USB_HUB_PORT_STATUS_ENABLED) != 0;
    291         /* Finalize device adding. */
    292 
    293         if (enabled) {
    294                 port->reset_status = RESET_OK;
    295                 usb_log_debug("(%p-%u): Port reset complete.\n", hub,
    296                     port->port_number);
     306        check_port_change(port, &status, &port_changed_connection,
     307            USB_HUB_PORT_STATUS_C_CONNECTION,
     308            USB_HUB_FEATURE_C_PORT_CONNECTION);
     309
     310        check_port_change(port, &status, &port_changed_overcurrent,
     311            USB_HUB_PORT_STATUS_C_OC, USB_HUB_FEATURE_C_PORT_OVER_CURRENT);
     312
     313        check_port_change(port, &status, &port_changed_reset,
     314            USB_HUB_PORT_STATUS_C_RESET, USB_HUB_FEATURE_C_PORT_RESET);
     315
     316        if (port->hub->speed <= USB_SPEED_HIGH) {
     317                check_port_change(port, &status, &port_changed_enabled,
     318                    USB2_HUB_PORT_STATUS_C_ENABLE,
     319                    USB2_HUB_FEATURE_C_PORT_ENABLE);
    297320        } else {
    298                 port->reset_status = RESET_FAIL;
    299                 usb_log_warning("(%p-%u): Port reset complete but port not "
    300                     "enabled.", hub, port->port_number);
    301         }
    302         fibril_condvar_broadcast(&port->reset_cv);
    303         fibril_mutex_unlock(&port->mutex);
    304 
    305         /* Clear the port reset change. */
    306         errno_t rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET);
    307         if (rc != EOK) {
    308                 usb_log_error("(%p-%u): Failed to clear port reset change: %s.",
    309                     hub, port->port_number, str_error(rc));
    310         }
    311 }
    312 
    313 /** Retrieve port status.
    314  *
    315  * @param[in] port Port structure
    316  * @param[out] status Where to store the port status.
    317  * @return Error code.
    318  */
    319 static errno_t get_port_status(usb_hub_port_t *port, usb_port_status_t *status)
    320 {
    321         assert(port);
    322         /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6
    323          * Generic GET_STATUS request cannot be used because of the difference
    324          * in status data size (2B vs. 4B)*/
    325         const usb_device_request_setup_packet_t request = {
    326                 .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS,
    327                 .request = USB_HUB_REQUEST_GET_STATUS,
    328                 .value = 0,
    329                 .index = uint16_host2usb(port->port_number),
    330                 .length = sizeof(usb_port_status_t),
    331         };
    332         size_t recv_size;
    333         usb_port_status_t status_tmp;
    334 
    335         const errno_t rc = usb_pipe_control_read(port->control_pipe,
    336             &request, sizeof(usb_device_request_setup_packet_t),
    337             &status_tmp, sizeof(status_tmp), &recv_size);
    338         if (rc != EOK) {
    339                 return rc;
    340         }
    341 
    342         if (recv_size != sizeof (status_tmp)) {
    343                 return ELIMIT;
    344         }
    345 
    346         if (status != NULL) {
    347                 *status = status_tmp;
    348         }
    349 
    350         return EOK;
    351 }
    352 
    353 static errno_t port_enable(usb_hub_port_t *port, usb_hub_dev_t *hub, bool enable)
    354 {
    355         if (enable) {
    356                 errno_t rc =
    357                     usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET);
    358                 if (rc != EOK) {
    359                         usb_log_error("(%p-%u): Port reset request failed: %s.",
    360                             hub, port->port_number, str_error(rc));
    361                         return rc;
    362                 }
    363                 /* Wait until reset completes. */
    364                 fibril_mutex_lock(&port->mutex);
    365                 port->reset_status = IN_RESET;
    366                 while (port->reset_status == IN_RESET)
    367                         fibril_condvar_wait(&port->reset_cv, &port->mutex);
    368                 rc = port->reset_status == RESET_OK ? EOK : ESTALL;
    369                 fibril_mutex_unlock(&port->mutex);
    370                 return rc;
    371         } else {
    372                 return usb_hub_port_clear_feature(port,
    373                                 USB_HUB_FEATURE_PORT_ENABLE);
    374         }
    375 }
    376 
    377 /** Fibril for adding a new device.
    378  *
    379  * Separate fibril is needed because the port reset completion is announced
    380  * via interrupt pipe and thus we cannot block here.
    381  *
    382  * @param arg Pointer to struct add_device_phase1.
    383  * @return 0 Always.
    384  */
    385 errno_t add_device_phase1_worker_fibril(void *arg)
    386 {
    387         struct add_device_phase1 *params = arg;
    388         assert(params);
    389 
    390         errno_t ret = EOK;
    391         usb_hub_dev_t *hub = params->hub;
    392         usb_hub_port_t *port = params->port;
    393         const usb_speed_t speed = params->speed;
    394         free(arg);
    395 
    396         usb_log_debug("(%p-%u): New device sequence.", hub, port->port_number);
    397 
    398         async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device);
    399         if (!exch) {
    400                 usb_log_error("(%p-%u): Failed to begin bus exchange.", hub,
    401                     port->port_number);
    402                 ret = ENOMEM;
    403                 goto out;
    404         }
    405 
    406         /* Reserve default address */
    407         while ((ret = usb_reserve_default_address(exch, speed)) == ENOENT) {
    408                 async_usleep(1000000);
    409         }
    410         if (ret != EOK) {
    411                 usb_log_error("(%p-%u): Failed to reserve default address: %s",
    412                     hub, port->port_number, str_error(ret));
    413                 goto out;
    414         }
    415 
    416         usb_log_debug("(%p-%u): Got default address reseting port.", hub,
    417             port->port_number);
    418         /* Reset port */
    419         ret = port_enable(port, hub, true);
    420         if (ret != EOK) {
    421                 usb_log_error("(%p-%u): Failed to reset port.", hub,
    422                     port->port_number);
    423                 if (usb_release_default_address(exch) != EOK)
    424                         usb_log_warning("(%p-%u): Failed to release default "
    425                             "address.", hub, port->port_number);
    426                 ret = EIO;
    427                 goto out;
    428         }
    429         usb_log_debug("(%p-%u): Port reset, enumerating device", hub,
    430             port->port_number);
    431 
    432         ret = usb_device_enumerate(exch, port->port_number);
    433         if (ret != EOK) {
    434                 usb_log_error("(%p-%u): Failed to enumerate device: %s", hub,
    435                     port->port_number, str_error(ret));
    436                 const errno_t ret = port_enable(port, hub, false);
    437                 if (ret != EOK) {
    438                         usb_log_warning("(%p-%u)Failed to disable port (%s), "
    439                             "NOT releasing default address.", hub,
    440                             port->port_number, str_error(ret));
    441                 } else {
    442                         const errno_t ret = usb_release_default_address(exch);
    443                         if (ret != EOK)
    444                                 usb_log_warning("(%p-%u): Failed to release "
    445                                     "default address: %s", hub,
    446                                     port->port_number, str_error(ret));
    447                 }
    448         } else {
    449                 usb_log_debug("(%p-%u): Device enumerated", hub,
    450                     port->port_number);
    451                 port->device_attached = true;
    452                 if (usb_release_default_address(exch) != EOK)
    453                         usb_log_warning("(%p-%u): Failed to release default "
    454                             "address", hub, port->port_number);
    455         }
    456 out:
    457         usb_device_bus_exchange_end(exch);
    458 
    459         fibril_mutex_lock(&hub->pending_ops_mutex);
    460         assert(hub->pending_ops_count > 0);
    461         --hub->pending_ops_count;
    462         fibril_condvar_signal(&hub->pending_ops_cv);
    463         fibril_mutex_unlock(&hub->pending_ops_mutex);
    464 
    465         return ret;
    466 }
    467 
    468 /** Start device adding when connection change is detected.
    469  *
    470  * This fires a new fibril to complete the device addition.
    471  *
    472  * @param hub Hub where the change occured.
    473  * @param port Port index (starting at 1).
    474  * @param speed Speed of the device.
    475  * @return Error code.
    476  */
    477 static errno_t create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub,
    478     usb_speed_t speed)
    479 {
    480         assert(hub);
    481         assert(port);
    482         struct add_device_phase1 *data
    483             = malloc(sizeof(struct add_device_phase1));
    484         if (data == NULL) {
    485                 return ENOMEM;
    486         }
    487         data->hub = hub;
    488         data->port = port;
    489         data->speed = speed;
    490 
    491         fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data);
    492         if (fibril == 0) {
    493                 free(data);
    494                 return ENOMEM;
    495         }
    496         fibril_mutex_lock(&hub->pending_ops_mutex);
    497         ++hub->pending_ops_count;
    498         fibril_mutex_unlock(&hub->pending_ops_mutex);
    499         fibril_add_ready(fibril);
    500 
    501         return EOK;
    502 }
     321                check_port_change(port, &status, &port_changed_reset,
     322                    USB3_HUB_PORT_STATUS_C_BH_RESET,
     323                    USB3_HUB_FEATURE_C_BH_PORT_RESET);
     324
     325                check_port_change(port, &status, NULL,
     326                    USB3_HUB_PORT_STATUS_C_LINK_STATE,
     327                    USB3_HUB_FEATURE_C_PORT_LINK_STATE);
     328        }
     329
     330        /* Check for changes we ignored */
     331        if (status & 0xffff0000) {
     332                port_log(debug, port, "Port status change igored. "
     333                    "Status: %#08" PRIx32, status);
     334        }
     335}
     336
    503337
    504338/**
  • uspace/drv/bus/usb/usbhub/port.h

    rf5e5f73 rdf6ded8  
    22 * Copyright (c) 2011 Vojtech Horky
    33 * Copyright (c) 2011 Jan Vesely
     4 * Copyright (c) 2018 Ondrej Hlavaty
    45 * All rights reserved.
    56 *
     
    3233 */
    3334/** @file
    34  * Hub ports related functions.
     35 * Hub port handling.
    3536 */
    3637
     
    4041#include <usb/dev/driver.h>
    4142#include <usb/classes/hub.h>
    42 #include <usb_iface.h>
     43#include <usb/port.h>
    4344
    4445typedef struct usb_hub_dev usb_hub_dev_t;
     
    4647/** Information about single port on a hub. */
    4748typedef struct {
     49        usb_port_t base;
     50        /* Parenting hub */
     51        usb_hub_dev_t *hub;
    4852        /** Port number as reported in descriptors. */
    4953        unsigned int port_number;
    50         /** Device communication pipe. */
    51         usb_pipe_t *control_pipe;
    52         /** Mutex needed not only by CV for checking port reset. */
    53         fibril_mutex_t mutex;
    54         /** CV for waiting to port reset completion. */
    55         fibril_condvar_t reset_cv;
    56         /** Port reset status.
    57          * Guarded by @c reset_mutex.
    58          */
    59         enum {
    60                 NO_RESET,
    61                 IN_RESET,
    62                 RESET_OK,
    63                 RESET_FAIL,
    64         } reset_status;
    65         /** Device reported to USB bus driver */
    66         bool device_attached;
     54        /** Speed at the time of enabling the port */
     55        usb_speed_t speed;
    6756} usb_hub_port_t;
    6857
    69 /** Initialize hub port information.
    70  *
    71  * @param port Port to be initialized.
    72  */
    73 static inline void usb_hub_port_init(usb_hub_port_t *port,
    74     unsigned int port_number, usb_pipe_t *control_pipe)
    75 {
    76         assert(port);
    77         port->port_number = port_number;
    78         port->control_pipe = control_pipe;
    79         port->reset_status = NO_RESET;
    80         port->device_attached = false;
    81         fibril_mutex_initialize(&port->mutex);
    82         fibril_condvar_initialize(&port->reset_cv);
    83 }
     58void usb_hub_port_init(usb_hub_port_t *, usb_hub_dev_t *, unsigned int);
    8459
    85 errno_t usb_hub_port_fini(usb_hub_port_t *port, usb_hub_dev_t *hub);
    86 errno_t usb_hub_port_clear_feature(
    87     usb_hub_port_t *port, usb_hub_class_feature_t feature);
    88 errno_t usb_hub_port_set_feature(
    89     usb_hub_port_t *port, usb_hub_class_feature_t feature);
    90 void usb_hub_port_reset_fail(usb_hub_port_t *port);
    91 void usb_hub_port_process_interrupt(usb_hub_port_t *port, usb_hub_dev_t *hub);
     60void usb_hub_port_process_interrupt(usb_hub_port_t *port);
    9261
    9362#endif
  • uspace/drv/bus/usb/usbhub/status.h

    rf5e5f73 rdf6ded8  
    3838
    3939/**
    40  * structure holding port status and changes flags.
    41  * should not be accessed directly, use supplied getter/setter methods.
    42  *
    43  * For more information refer to tables 11-15 and 11-16 in
    44  * "Universal Serial Bus Specification Revision 1.1" pages 274 and 277
    45  * (290 and 293 in pdf)
    46  *
    47  */
    48 typedef uint32_t usb_port_status_t;
    49 #define USB_HUB_PORT_STATUS_CONNECTION \
    50     (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_CONNECTION)))
    51 #define USB_HUB_PORT_STATUS_ENABLED \
    52     (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_ENABLE)))
    53 #define USB_HUB_PORT_STATUS_SUSPEND \
    54     (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_SUSPEND)))
    55 #define USB_HUB_PORT_STATUS_OC \
    56     (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_OVER_CURRENT)))
    57 #define USB_HUB_PORT_STATUS_RESET \
    58     (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_RESET)))
    59 #define USB_HUB_PORT_STATUS_POWER \
    60     (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_POWER)))
    61 #define USB_HUB_PORT_STATUS_LOW_SPEED \
    62     (uint32_usb2host(1 << (USB_HUB_FEATURE_PORT_LOW_SPEED)))
    63 #define USB_HUB_PORT_STATUS_HIGH_SPEED \
    64     (uint32_usb2host(1 << 10))
    65 #define USB_HUB_PORT_STATUS_TEST_MODE \
    66     (uint32_usb2host(1 << 11))
    67 #define USB_HUB_PORT_INDICATOR_CONTROL \
    68     (uint32_usb2host(1 << 12))
    69 
    70 #define USB_HUB_PORT_C_STATUS_CONNECTION \
    71     (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_CONNECTION)))
    72 #define USB_HUB_PORT_C_STATUS_ENABLED \
    73     (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_ENABLE)))
    74 #define USB_HUB_PORT_C_STATUS_SUSPEND \
    75     (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_SUSPEND)))
    76 #define USB_HUB_PORT_C_STATUS_OC \
    77     (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_OVER_CURRENT)))
    78 #define USB_HUB_PORT_C_STATUS_RESET \
    79     (uint32_usb2host(1 << (USB_HUB_FEATURE_C_PORT_RESET)))
    80 
    81 /**
    8240 * structure holding hub status and changes flags.
    8341 *
     
    9755    (uint32_usb2host(1 << (16 + USB_HUB_FEATURE_C_HUB_LOCAL_POWER)))
    9856
    99 
    100 /**
    101  * speed getter for port status
    102  *
    103  * @param status
    104  * @return speed of usb device (for more see usb specification)
    105  */
    106 static inline usb_speed_t usb_port_speed(usb_port_status_t status)
     57static inline usb_speed_t usb_port_speed(usb_speed_t hub_speed, uint32_t status)
    10758{
    108         if ((status & USB_HUB_PORT_STATUS_LOW_SPEED) != 0)
     59        if (hub_speed == USB_SPEED_SUPER)
     60                return USB_SPEED_SUPER;
     61        if (hub_speed == USB_SPEED_HIGH
     62            && (status & USB2_HUB_PORT_STATUS_HIGH_SPEED))
     63                return USB_SPEED_HIGH;
     64        if ((status & USB2_HUB_PORT_STATUS_LOW_SPEED) != 0)
    10965                return USB_SPEED_LOW;
    110         if ((status & USB_HUB_PORT_STATUS_HIGH_SPEED) != 0)
    111                 return USB_SPEED_HIGH;
    11266        return USB_SPEED_FULL;
    11367}
  • uspace/drv/bus/usb/usbhub/usbhub.c

    rf5e5f73 rdf6ded8  
    22 * Copyright (c) 2010 Matus Dekanek
    33 * Copyright (c) 2011 Jan Vesely
     4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    45 * All rights reserved.
    56 *
     
    5152#include <usb/classes/hub.h>
    5253#include <usb/dev/poll.h>
    53 #include <usb_iface.h>
     54#include <usbhc_iface.h>
    5455
    5556#include "usbhub.h"
     
    5859#define HUB_FNC_NAME "hub"
    5960
    60 /** Hub status-change endpoint description.
    61  *
    62  * For more information see section 11.15.1 of USB 1.1 specification.
    63  */
    64 const usb_endpoint_description_t hub_status_change_endpoint_description =
    65 {
    66         .transfer_type = USB_TRANSFER_INTERRUPT,
    67         .direction = USB_DIRECTION_IN,
    68         .interface_class = USB_CLASS_HUB,
    69         .interface_subclass = 0,
    70         .interface_protocol = 0,
    71         .flags = 0
     61#define HUB_STATUS_CHANGE_EP(protocol) { \
     62        .transfer_type = USB_TRANSFER_INTERRUPT, \
     63        .direction = USB_DIRECTION_IN, \
     64        .interface_class = USB_CLASS_HUB, \
     65        .interface_subclass = 0, \
     66        .interface_protocol = (protocol), \
     67        .flags = 0 \
     68}
     69
     70/**
     71 * Hub status-change endpoint description.
     72 *
     73 * According to USB 2.0 specification, there are two possible arrangements of
     74 * endpoints, depending on whether the hub has a MTT or not.
     75 *
     76 * Under any circumstances, there shall be exactly one endpoint descriptor.
     77 * Though to be sure, let's map the protocol precisely. The possible
     78 * combinations are:
     79 *                            | bDeviceProtocol | bInterfaceProtocol
     80 *      Only single TT        |       0         |         0
     81 *      MTT in Single-TT mode |       2         |         1
     82 *      MTT in MTT mode       |       2         |         2     (iface alt. 1)
     83 */
     84static const usb_endpoint_description_t
     85        status_change_single_tt_only = HUB_STATUS_CHANGE_EP(0),
     86        status_change_mtt_available = HUB_STATUS_CHANGE_EP(1);
     87
     88const usb_endpoint_description_t *usb_hub_endpoints [] = {
     89        &status_change_single_tt_only,
     90        &status_change_mtt_available,
    7291};
    7392
     
    81100};
    82101
    83 static errno_t usb_set_first_configuration(usb_device_t *usb_device);
    84 static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev);
    85 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev,
    86     usb_hub_status_t status);
    87 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev);
    88 static void usb_hub_polling_terminated_callback(usb_device_t *device,
    89     bool was_error, void *data);
     102static errno_t usb_set_first_configuration(usb_device_t *);
     103static errno_t usb_hub_process_hub_specific_info(usb_hub_dev_t *);
     104static void usb_hub_over_current(const usb_hub_dev_t *, usb_hub_status_t);
     105static errno_t usb_hub_polling_init(usb_hub_dev_t *, usb_endpoint_mapping_t *);
     106static void usb_hub_global_interrupt(const usb_hub_dev_t *);
     107
     108static bool usb_hub_polling_error_callback(usb_device_t *dev,
     109        errno_t err_code, void *arg)
     110{
     111        assert(dev);
     112        assert(arg);
     113
     114        usb_log_error("Device %s polling error: %s",
     115                usb_device_get_name(dev), str_error(err_code));
     116
     117        return true;
     118}
    90119
    91120/**
     
    99128errno_t usb_hub_device_add(usb_device_t *usb_dev)
    100129{
     130        errno_t err;
    101131        assert(usb_dev);
     132
    102133        /* Create driver soft-state structure */
    103134        usb_hub_dev_t *hub_dev =
    104135            usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t));
    105136        if (hub_dev == NULL) {
    106                 usb_log_error("Failed to create hub driver structure.\n");
     137                usb_log_error("Failed to create hub driver structure.");
    107138                return ENOMEM;
    108139        }
    109140        hub_dev->usb_device = usb_dev;
    110         hub_dev->pending_ops_count = 0;
    111         hub_dev->running = false;
    112         fibril_mutex_initialize(&hub_dev->pending_ops_mutex);
    113         fibril_condvar_initialize(&hub_dev->pending_ops_cv);
     141        hub_dev->speed = usb_device_get_speed(usb_dev);
    114142
    115143        /* Set hub's first configuration. (There should be only one) */
    116         errno_t opResult = usb_set_first_configuration(usb_dev);
    117         if (opResult != EOK) {
    118                 usb_log_error("Could not set hub configuration: %s\n",
    119                     str_error(opResult));
    120                 return opResult;
     144        if ((err = usb_set_first_configuration(usb_dev))) {
     145                usb_log_error("Could not set hub configuration: %s", str_error(err));
     146                return err;
    121147        }
    122148
    123149        /* Get port count and create attached_devices. */
    124         opResult = usb_hub_process_hub_specific_info(hub_dev);
    125         if (opResult != EOK) {
    126                 usb_log_error("Could process hub specific info, %s\n",
    127                     str_error(opResult));
    128                 return opResult;
     150        if ((err = usb_hub_process_hub_specific_info(hub_dev))) {
     151                usb_log_error("Could process hub specific info, %s", str_error(err));
     152                return err;
     153        }
     154
     155        const usb_endpoint_description_t *status_change = hub_dev->mtt_available
     156            ? &status_change_mtt_available
     157            : &status_change_single_tt_only;
     158
     159        usb_endpoint_mapping_t *status_change_mapping
     160                = usb_device_get_mapped_ep_desc(hub_dev->usb_device, status_change);
     161        if (!status_change_mapping) {
     162                usb_log_error("Failed to map the Status Change Endpoint of a hub.");
     163                return EIO;
    129164        }
    130165
    131166        /* Create hub control function. */
    132         usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n");
     167        usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.");
    133168        hub_dev->hub_fun = usb_device_ddf_fun_create(hub_dev->usb_device,
    134169            fun_exposed, HUB_FNC_NAME);
    135170        if (hub_dev->hub_fun == NULL) {
    136                 usb_log_error("Failed to create hub function.\n");
     171                usb_log_error("Failed to create hub function.");
    137172                return ENOMEM;
    138173        }
    139174
    140175        /* Bind hub control function. */
    141         opResult = ddf_fun_bind(hub_dev->hub_fun);
    142         if (opResult != EOK) {
    143                 usb_log_error("Failed to bind hub function: %s.\n",
    144                    str_error(opResult));
    145                 ddf_fun_destroy(hub_dev->hub_fun);
    146                 return opResult;
     176        if ((err = ddf_fun_bind(hub_dev->hub_fun))) {
     177                usb_log_error("Failed to bind hub function: %s.", str_error(err));
     178                goto err_ddf_fun;
    147179        }
    148180
    149181        /* Start hub operation. */
    150         opResult = usb_device_auto_poll_desc(hub_dev->usb_device,
    151             &hub_status_change_endpoint_description,
    152             hub_port_changes_callback, ((hub_dev->port_count + 1 + 7) / 8),
    153             -1, usb_hub_polling_terminated_callback, hub_dev);
    154         if (opResult != EOK) {
    155                 /* Function is already bound */
    156                 ddf_fun_unbind(hub_dev->hub_fun);
    157                 ddf_fun_destroy(hub_dev->hub_fun);
    158                 usb_log_error("Failed to create polling fibril: %s.\n",
    159                     str_error(opResult));
    160                 return opResult;
    161         }
    162         hub_dev->running = true;
    163         usb_log_info("Controlling hub '%s' (%p: %zu ports).\n",
     182        if ((err = usb_hub_polling_init(hub_dev, status_change_mapping))) {
     183                usb_log_error("Failed to start polling: %s.", str_error(err));
     184                goto err_bound;
     185        }
     186
     187        usb_log_info("Controlling %s-speed hub '%s' (%p: %zu ports).",
     188            usb_str_speed(hub_dev->speed),
    164189            usb_device_get_name(hub_dev->usb_device), hub_dev,
    165190            hub_dev->port_count);
    166191
    167192        return EOK;
    168 }
    169 
    170 /**
    171  * Turn off power to all ports.
    172  *
    173  * @param usb_dev generic usb device information
    174  * @return error code
    175  */
    176 errno_t usb_hub_device_remove(usb_device_t *usb_dev)
    177 {
    178         return ENOTSUP;
    179 }
    180 
    181 /**
    182  * Remove all attached devices
    183  * @param usb_dev generic usb device information
    184  * @return error code
    185  */
    186 errno_t usb_hub_device_gone(usb_device_t *usb_dev)
    187 {
    188         assert(usb_dev);
    189         usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
    190         assert(hub);
    191         unsigned tries = 10;
    192         while (hub->running) {
    193                 async_usleep(100000);
    194                 if (!tries--) {
    195                         usb_log_error("(%p): Can't remove hub, still running.",
    196                             hub);
    197                         return EBUSY;
    198                 }
    199         }
    200 
    201         assert(!hub->running);
     193
     194err_bound:
     195        ddf_fun_unbind(hub_dev->hub_fun);
     196err_ddf_fun:
     197        ddf_fun_destroy(hub_dev->hub_fun);
     198        return err;
     199}
     200
     201static errno_t usb_hub_cleanup(usb_hub_dev_t *hub)
     202{
     203        free(hub->polling.buffer);
     204        usb_polling_fini(&hub->polling);
    202205
    203206        for (size_t port = 0; port < hub->port_count; ++port) {
    204                 const errno_t ret = usb_hub_port_fini(&hub->ports[port], hub);
    205                 if (ret != EOK)
    206                         return ret;
     207                usb_port_fini(&hub->ports[port].base);
    207208        }
    208209        free(hub->ports);
     
    217218
    218219        usb_log_info("(%p) USB hub driver stopped and cleaned.", hub);
     220
     221        /* Device data (usb_hub_dev_t) will be freed by usbdev. */
    219222        return EOK;
    220223}
    221224
    222 /** Callback for polling hub for changes.
     225/**
     226 * Turn off power to all ports.
     227 *
     228 * @param usb_dev generic usb device information
     229 * @return error code
     230 */
     231errno_t usb_hub_device_remove(usb_device_t *usb_dev)
     232{
     233        assert(usb_dev);
     234        usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
     235        assert(hub);
     236
     237        usb_log_info("(%p) USB hub removed, joining polling fibril.", hub);
     238
     239        /* Join polling fibril (ignoring error code). */
     240        usb_polling_join(&hub->polling);
     241        usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
     242
     243        /* Destroy hub. */
     244        return usb_hub_cleanup(hub);
     245}
     246
     247/**
     248 * Remove all attached devices
     249 * @param usb_dev generic usb device information
     250 * @return error code
     251 */
     252errno_t usb_hub_device_gone(usb_device_t *usb_dev)
     253{
     254        assert(usb_dev);
     255        usb_hub_dev_t *hub = usb_device_data_get(usb_dev);
     256        assert(hub);
     257
     258        usb_log_info("(%p) USB hub gone, joining polling fibril.", hub);
     259
     260        /* Join polling fibril (ignoring error code). */
     261        usb_polling_join(&hub->polling);
     262        usb_log_info("(%p) USB hub polling stopped, freeing memory.", hub);
     263
     264        /* Destroy hub. */
     265        return usb_hub_cleanup(hub);
     266}
     267
     268/**
     269 * Initialize and start the polling of the Status Change Endpoint.
     270 *
     271 * @param mapping The mapping of Status Change Endpoint
     272 */
     273static errno_t usb_hub_polling_init(usb_hub_dev_t *hub_dev,
     274        usb_endpoint_mapping_t *mapping)
     275{
     276        errno_t err;
     277        usb_polling_t *polling = &hub_dev->polling;
     278
     279        if ((err = usb_polling_init(polling)))
     280                return err;
     281
     282        polling->device = hub_dev->usb_device;
     283        polling->ep_mapping = mapping;
     284        polling->request_size = ((hub_dev->port_count + 1 + 7) / 8);
     285        polling->buffer = malloc(polling->request_size);
     286        polling->on_data = hub_port_changes_callback;
     287        polling->on_error = usb_hub_polling_error_callback;
     288        polling->arg = hub_dev;
     289
     290        if ((err = usb_polling_start(polling))) {
     291                /* Polling is already initialized. */
     292                free(polling->buffer);
     293                usb_polling_fini(polling);
     294                return err;
     295        }
     296
     297        return EOK;
     298}
     299
     300/**
     301 * Callback for polling hub for changes.
    223302 *
    224303 * @param dev Device where the change occured.
     
    245324        }
    246325
    247         /* N + 1 bit indicates change on port N */
     326        /* Nth bit indicates change on port N */
    248327        for (size_t port = 0; port < hub->port_count; ++port) {
    249328                const size_t bit = port + 1;
    250329                const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1;
    251330                if (change) {
    252                         usb_hub_port_process_interrupt(&hub->ports[port], hub);
     331                        usb_hub_port_process_interrupt(&hub->ports[port]);
    253332                }
    254333        }
    255334        return true;
     335}
     336
     337static void usb_hub_power_ports(usb_hub_dev_t *hub_dev)
     338{
     339        if (!hub_dev->power_switched) {
     340                usb_log_info("(%p): Power switching not supported, "
     341                    "ports always powered.", hub_dev);
     342                return;
     343        }
     344
     345        usb_log_info("(%p): Hub port power switching enabled (%s).", hub_dev,
     346            hub_dev->per_port_power ? "per port" : "ganged");
     347
     348        for (unsigned int port = 0; port < hub_dev->port_count; ++port) {
     349                usb_log_debug("(%p): Powering port %u.", hub_dev, port + 1);
     350                const errno_t ret = usb_hub_set_port_feature(hub_dev, port + 1,
     351                    USB_HUB_FEATURE_PORT_POWER);
     352
     353                if (ret != EOK) {
     354                        usb_log_error("(%p-%u): Cannot power on port: %s.",
     355                            hub_dev, hub_dev->ports[port].port_number,
     356                            str_error(ret));
     357                        /* Continue to try at least other ports */
     358                }
     359        }
    256360}
    257361
     
    270374        assert(hub_dev);
    271375
     376        usb_log_debug("(%p): Retrieving descriptor.", hub_dev);
     377        usb_pipe_t *control_pipe = usb_device_get_default_pipe(hub_dev->usb_device);
     378
     379        usb_descriptor_type_t desc_type = hub_dev->speed >= USB_SPEED_SUPER
     380                ? USB_DESCTYPE_SSPEED_HUB : USB_DESCTYPE_HUB;
     381
    272382        /* Get hub descriptor. */
    273         usb_log_debug("(%p): Retrieving descriptor.", hub_dev);
    274         usb_pipe_t *control_pipe =
    275             usb_device_get_default_pipe(hub_dev->usb_device);
    276 
    277383        usb_hub_descriptor_header_t descriptor;
    278384        size_t received_size;
    279385        errno_t opResult = usb_request_get_descriptor(control_pipe,
    280386            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    281             USB_DESCTYPE_HUB, 0, 0, &descriptor,
     387            desc_type, 0, 0, &descriptor,
    282388            sizeof(usb_hub_descriptor_header_t), &received_size);
    283389        if (opResult != EOK) {
    284                 usb_log_error("(%p): Failed to receive hub descriptor: %s.\n",
     390                usb_log_error("(%p): Failed to receive hub descriptor: %s.",
    285391                    hub_dev, str_error(opResult));
    286392                return opResult;
    287393        }
    288394
    289         usb_log_debug("(%p): Setting port count to %d.\n", hub_dev,
     395        usb_log_debug("(%p): Setting port count to %d.", hub_dev,
    290396            descriptor.port_count);
    291397        hub_dev->port_count = descriptor.port_count;
     398        hub_dev->control_pipe = control_pipe;
     399
     400        usb_log_debug("(%p): Setting hub depth to %u.", hub_dev,
     401            usb_device_get_depth(hub_dev->usb_device));
     402        if ((opResult = usb_hub_set_depth(hub_dev))) {
     403                usb_log_error("(%p): Failed to set hub depth: %s.",
     404                    hub_dev, str_error(opResult));
     405                return opResult;
     406        }
    292407
    293408        hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t));
     
    297412
    298413        for (size_t port = 0; port < hub_dev->port_count; ++port) {
    299                 usb_hub_port_init(
    300                     &hub_dev->ports[port], port + 1, control_pipe);
     414                usb_hub_port_init(&hub_dev->ports[port], hub_dev, port + 1);
    301415        }
    302416
     
    306420            descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG;
    307421
    308         if (!hub_dev->power_switched) {
    309                 usb_log_info("(%p): Power switching not supported, "
    310                     "ports always powered.", hub_dev);
    311                 return EOK;
    312         }
    313 
    314         usb_log_info("(%p): Hub port power switching enabled (%s).\n", hub_dev,
    315             hub_dev->per_port_power ? "per port" : "ganged");
    316 
    317         for (unsigned int port = 0; port < hub_dev->port_count; ++port) {
    318                 usb_log_debug("(%p): Powering port %u.", hub_dev, port);
    319                 const errno_t ret = usb_hub_port_set_feature(
    320                     &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
    321 
    322                 if (ret != EOK) {
    323                         usb_log_error("(%p-%u): Cannot power on port: %s.\n",
    324                             hub_dev, hub_dev->ports[port].port_number,
    325                             str_error(ret));
    326                 } else {
    327                         if (!hub_dev->per_port_power) {
    328                                 usb_log_debug("(%p) Ganged power switching, "
    329                                     "one port is enough.", hub_dev);
    330                                 break;
    331                         }
    332                 }
    333         }
     422        const uint8_t protocol = usb_device_descriptors(hub_dev->usb_device)
     423                ->device.device_protocol;
     424        hub_dev->mtt_available = (protocol == 2);
     425
     426        usb_hub_power_ports(hub_dev);
     427
    334428        return EOK;
    335429}
     
    349443        const size_t configuration_count =
    350444            usb_device_descriptors(usb_device)->device.configuration_count;
    351         usb_log_debug("Hub has %zu configurations.\n", configuration_count);
     445        usb_log_debug("Hub has %zu configurations.", configuration_count);
    352446
    353447        if (configuration_count < 1) {
    354                 usb_log_error("There are no configurations available\n");
     448                usb_log_error("There are no configurations available");
    355449                return EINVAL;
    356450        }
     
    369463        /* Set configuration. Use the configuration that was in
    370464         * usb_device->descriptors.configuration i.e. The first one. */
    371         const errno_t opResult = usb_request_set_configuration(
     465        errno_t opResult = usb_request_set_configuration(
    372466            usb_device_get_default_pipe(usb_device),
    373467            config_descriptor->configuration_number);
    374468        if (opResult != EOK) {
    375                 usb_log_error("Failed to set hub configuration: %s.\n",
     469                usb_log_error("Failed to set hub configuration: %s.",
    376470                    str_error(opResult));
    377471        } else {
    378                 usb_log_debug("\tUsed configuration %d\n",
     472                usb_log_debug("\tUsed configuration %d",
    379473                    config_descriptor->configuration_number);
    380474        }
     475
    381476        return opResult;
    382477}
     
    406501        /* Over-current condition is gone, it is safe to turn the ports on. */
    407502        for (size_t port = 0; port < hub_dev->port_count; ++port) {
    408                 const errno_t ret = usb_hub_port_set_feature(
    409                     &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER);
     503                const errno_t ret = usb_hub_set_port_feature(hub_dev, port,
     504                    USB_HUB_FEATURE_PORT_POWER);
    410505                if (ret != EOK) {
    411506                        usb_log_warning("(%p-%u): HUB OVER-CURRENT GONE: Cannot"
     
    417512                }
    418513        }
    419 
     514}
     515
     516/**
     517 * Set feature on the real hub port.
     518 *
     519 * @param port Port structure.
     520 * @param feature Feature selector.
     521 */
     522errno_t usb_hub_set_depth(const usb_hub_dev_t *hub)
     523{
     524        assert(hub);
     525
     526        /* Slower hubs do not care about depth */
     527        if (hub->speed < USB_SPEED_SUPER)
     528                return EOK;
     529
     530        const usb_device_request_setup_packet_t set_request = {
     531                .request_type = USB_HUB_REQ_TYPE_SET_HUB_DEPTH,
     532                .request = USB_HUB_REQUEST_SET_HUB_DEPTH,
     533                .value = uint16_host2usb(usb_device_get_depth(hub->usb_device) - 1),
     534                .index = 0,
     535                .length = 0,
     536        };
     537        return usb_pipe_control_write(hub->control_pipe, &set_request,
     538            sizeof(set_request), NULL, 0);
     539}
     540
     541/**
     542 * Set feature on the real hub port.
     543 *
     544 * @param port Port structure.
     545 * @param feature Feature selector.
     546 */
     547errno_t usb_hub_set_port_feature(const usb_hub_dev_t *hub, size_t port_number,
     548    usb_hub_class_feature_t feature)
     549{
     550        assert(hub);
     551        const usb_device_request_setup_packet_t clear_request = {
     552                .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE,
     553                .request = USB_DEVREQ_SET_FEATURE,
     554                .index = uint16_host2usb(port_number),
     555                .value = feature,
     556                .length = 0,
     557        };
     558        return usb_pipe_control_write(hub->control_pipe, &clear_request,
     559            sizeof(clear_request), NULL, 0);
     560}
     561
     562/**
     563 * Clear feature on the real hub port.
     564 *
     565 * @param port Port structure.
     566 * @param feature Feature selector.
     567 */
     568errno_t usb_hub_clear_port_feature(const usb_hub_dev_t *hub, size_t port_number,
     569    usb_hub_class_feature_t feature)
     570{
     571        assert(hub);
     572        const usb_device_request_setup_packet_t clear_request = {
     573                .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE,
     574                .request = USB_DEVREQ_CLEAR_FEATURE,
     575                .value = feature,
     576                .index = uint16_host2usb(port_number),
     577                .length = 0,
     578        };
     579        return usb_pipe_control_write(hub->control_pipe,
     580            &clear_request, sizeof(clear_request), NULL, 0);
     581}
     582
     583/**
     584 * Retrieve port status.
     585 *
     586 * @param[in] port Port structure
     587 * @param[out] status Where to store the port status.
     588 * @return Error code.
     589 */
     590errno_t usb_hub_get_port_status(const usb_hub_dev_t *hub, size_t port_number,
     591    usb_port_status_t *status)
     592{
     593        assert(hub);
     594        assert(status);
     595
     596        /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6
     597         * Generic GET_STATUS request cannot be used because of the difference
     598         * in status data size (2B vs. 4B)*/
     599        const usb_device_request_setup_packet_t request = {
     600                .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS,
     601                .request = USB_HUB_REQUEST_GET_STATUS,
     602                .value = 0,
     603                .index = uint16_host2usb(port_number),
     604                .length = sizeof(usb_port_status_t),
     605        };
     606        size_t recv_size;
     607
     608        uint32_t buffer;
     609        const errno_t rc = usb_pipe_control_read(hub->control_pipe,
     610            &request, sizeof(usb_device_request_setup_packet_t),
     611            &buffer, sizeof(buffer), &recv_size);
     612        if (rc != EOK)
     613                return rc;
     614
     615        if (recv_size != sizeof(*status))
     616                return ELIMIT;
     617
     618        *status = uint32_usb2host(buffer);
     619        return EOK;
    420620}
    421621
     
    492692
    493693/**
    494  * callback called from hub polling fibril when the fibril terminates
    495  *
    496  * Does not perform cleanup, just marks the hub as not running.
    497  * @param device usb device afected
    498  * @param was_error indicates that the fibril is stoped due to an error
    499  * @param data pointer to usb_hub_dev_t structure
    500  */
    501 static void usb_hub_polling_terminated_callback(usb_device_t *device,
    502     bool was_error, void *data)
    503 {
    504         usb_hub_dev_t *hub = data;
     694 * Instead of just sleeping, we may as well sleep on a condition variable.
     695 * This has the advantage that we may instantly wait other hub from the polling
     696 * sleep, mitigating the delay of polling while still being synchronized with
     697 * other devices in need of the default address (there shall not be any).
     698 */
     699static FIBRIL_CONDVAR_INITIALIZE(global_hub_default_address_cv);
     700static FIBRIL_MUTEX_INITIALIZE(global_hub_default_address_guard);
     701
     702/**
     703 * Reserve a default address for a port across all other devices connected to
     704 * the bus. We aggregate requests for ports to minimize delays between
     705 * connecting multiple devices from one hub - which happens e.g. when the hub
     706 * is connected with already attached devices.
     707 */
     708errno_t usb_hub_reserve_default_address(usb_hub_dev_t *hub, async_exch_t *exch,
     709    usb_port_t *port)
     710{
    505711        assert(hub);
    506 
    507         fibril_mutex_lock(&hub->pending_ops_mutex);
    508 
    509         /* The device is dead. However there might be some pending operations
    510          * that we need to wait for.
    511          * One of them is device adding in progress.
    512          * The respective fibril is probably waiting for status change
    513          * in port reset (port enable) callback.
    514          * Such change would never come (otherwise we would not be here).
    515          * Thus, we would flush all pending port resets.
     712        assert(exch);
     713        assert(port);
     714        assert(fibril_mutex_is_locked(&port->guard));
     715
     716        errno_t err = usbhc_reserve_default_address(exch);
     717        /*
     718         * EINVAL signalls that its our hub (hopefully different port) that has
     719         * this address reserved
    516720         */
    517         if (hub->pending_ops_count > 0) {
    518                 for (size_t port = 0; port < hub->port_count; ++port) {
    519                         usb_hub_port_reset_fail(&hub->ports[port]);
    520                 }
    521         }
    522         /* And now wait for them. */
    523         while (hub->pending_ops_count > 0) {
    524                 fibril_condvar_wait(&hub->pending_ops_cv,
    525                     &hub->pending_ops_mutex);
    526         }
    527         fibril_mutex_unlock(&hub->pending_ops_mutex);
    528         hub->running = false;
    529 }
     721        while (err == EAGAIN || err == EINVAL) {
     722                /* Drop the port guard, we're going to wait */
     723                fibril_mutex_unlock(&port->guard);
     724
     725                /* This sleeping might be disturbed by other hub */
     726                fibril_mutex_lock(&global_hub_default_address_guard);
     727                fibril_condvar_wait_timeout(&global_hub_default_address_cv,
     728                    &global_hub_default_address_guard, 2000000);
     729                fibril_mutex_unlock(&global_hub_default_address_guard);
     730
     731                fibril_mutex_lock(&port->guard);
     732                err = usbhc_reserve_default_address(exch);
     733        }
     734
     735        if (err)
     736                return err;
     737
     738        /*
     739         * As we dropped the port guard, we need to check whether the device is
     740         * still connected. If the release fails, we still hold the default
     741         * address -- but then there is probably a bigger problem with the HC
     742         * anyway.
     743         */
     744        if (port->state != PORT_CONNECTING) {
     745                err = usb_hub_release_default_address(hub, exch);
     746                return err ? err : EINTR;
     747        }
     748
     749        return EOK;
     750}
     751
     752/**
     753 * Release the default address from a port.
     754 */
     755errno_t usb_hub_release_default_address(usb_hub_dev_t *hub, async_exch_t *exch)
     756{
     757        const errno_t ret = usbhc_release_default_address(exch);
     758
     759        /*
     760         * This is an optimistic optimization - it may wake
     761         * one hub from polling sleep instantly.
     762         */
     763        fibril_condvar_signal(&global_hub_default_address_cv);
     764
     765        return ret;
     766}
     767
    530768/**
    531769 * @}
  • uspace/drv/bus/usb/usbhub/usbhub.h

    rf5e5f73 rdf6ded8  
    22 * Copyright (c) 2010 Vojtech Horky
    33 * Copyright (c) 2011 Vojtech Horky
     4 * Copyright (c) 2018 Ondrej Hlavaty, Petr Manek
    45 * All rights reserved.
    56 *
     
    3940
    4041#include <ddf/driver.h>
     42#include <fibril_synch.h>
    4143
    4244#include <usb/classes/hub.h>
     
    4446#include <usb/dev/pipes.h>
    4547#include <usb/dev/driver.h>
    46 
    47 #include <fibril_synch.h>
     48#include <usb/dev/poll.h>
    4849
    4950#define NAME "usbhub"
    5051
    5152#include "port.h"
     53#include "status.h"
    5254
    5355/** Information about attached hub. */
     
    5759        /** Port structures, one for each port */
    5860        usb_hub_port_t *ports;
     61        /** Speed of the hub */
     62        usb_speed_t speed;
    5963        /** Generic usb device data*/
    6064        usb_device_t *usb_device;
    61 
    62         /** Number of pending operations on the mutex to prevent shooting
    63          * ourselves in the foot.
    64          * When the hub is disconnected but we are in the middle of some
    65          * operation, we cannot destroy this structure right away because
    66          * the pending operation might use it.
    67          */
    68         size_t pending_ops_count;
    69         /** Guard for pending_ops_count. */
    70         fibril_mutex_t pending_ops_mutex;
    71         /** Condition variable for pending_ops_count. */
    72         fibril_condvar_t pending_ops_cv;
     65        /** Data polling handle. */
     66        usb_polling_t polling;
    7367        /** Pointer to usbhub function. */
    7468        ddf_fun_t *hub_fun;
    75         /** Status indicator */
    76         bool running;
     69        /** Device communication pipe. */
     70        usb_pipe_t *control_pipe;
    7771        /** Hub supports port power switching. */
    7872        bool power_switched;
    7973        /** Each port is switched individually. */
    8074        bool per_port_power;
     75        /** Whether MTT is available */
     76        bool mtt_available;
    8177};
    8278
    83 extern const usb_endpoint_description_t hub_status_change_endpoint_description;
     79extern const usb_endpoint_description_t *usb_hub_endpoints [];
    8480
    85 extern errno_t usb_hub_device_add(usb_device_t *);
    86 extern errno_t usb_hub_device_remove(usb_device_t *);
    87 extern errno_t usb_hub_device_gone(usb_device_t *);
     81errno_t usb_hub_device_add(usb_device_t *);
     82errno_t usb_hub_device_remove(usb_device_t *);
     83errno_t usb_hub_device_gone(usb_device_t *);
    8884
    89 extern bool hub_port_changes_callback(usb_device_t *, uint8_t *, size_t,
    90     void *);
     85errno_t usb_hub_set_depth(const usb_hub_dev_t *);
     86errno_t usb_hub_get_port_status(const usb_hub_dev_t *, size_t,
     87    usb_port_status_t *);
     88errno_t usb_hub_set_port_feature(const usb_hub_dev_t *, size_t,
     89    usb_hub_class_feature_t);
     90errno_t usb_hub_clear_port_feature(const usb_hub_dev_t *, size_t,
     91    usb_hub_class_feature_t);
     92
     93bool hub_port_changes_callback(usb_device_t *, uint8_t *, size_t, void *);
     94
     95errno_t usb_hub_reserve_default_address(usb_hub_dev_t *, async_exch_t *,
     96    usb_port_t *);
     97errno_t usb_hub_release_default_address(usb_hub_dev_t *, async_exch_t *);
    9198
    9299#endif
  • uspace/drv/bus/usb/usbmid/dump.c

    rf5e5f73 rdf6ded8  
    5454        const int type = data[1];
    5555        if (type == USB_DESCTYPE_INTERFACE) {
    56                 usb_standard_interface_descriptor_t *descriptor
    57                     = (usb_standard_interface_descriptor_t *) data;
    58                 usb_log_info("Found interface: %s (0x%02x/0x%02x/0x%02x).\n",
     56                usb_standard_interface_descriptor_t *descriptor =
     57                    (usb_standard_interface_descriptor_t *) data;
     58                usb_log_info("Found interface: %s (0x%02x/0x%02x/0x%02x).",
    5959                    usb_str_class(descriptor->interface_class),
    6060                    (int) descriptor->interface_class,
  • uspace/drv/bus/usb/usbmid/explore.c

    rf5e5f73 rdf6ded8  
    106106
    107107
    108                 usb_log_info("Creating child for interface %d (%s).\n",
     108                usb_log_info("Creating child for interface %d (%s).",
    109109                    interface->interface_number,
    110110                    usb_str_class(interface->interface_class));
     
    144144                    dev_class, usb_str_class(dev_class),
    145145                    USB_CLASS_USE_INTERFACE);
    146                 usb_log_error("Not a multi-interface device, refusing.\n");
     146                usb_log_error("Not a multi-interface device, refusing.");
    147147                return ENOTSUP;
    148148        }
     
    160160            config_descriptor->configuration_number);
    161161        if (rc != EOK) {
    162                 usb_log_error("Failed to set device configuration: %s.\n",
     162                usb_log_error("Failed to set device configuration: %s.",
    163163                    str_error(rc));
    164164                return rc;
     
    168168        usb_mid_t *usb_mid = usb_device_data_alloc(dev, sizeof(usb_mid_t));
    169169        if (!usb_mid) {
    170                 usb_log_error("Failed to create USB MID structure.\n");
     170                usb_log_error("Failed to create USB MID structure.");
    171171                return ENOMEM;
    172172        }
     
    175175        usb_mid->ctl_fun = usb_device_ddf_fun_create(dev, fun_exposed, "ctl");
    176176        if (usb_mid->ctl_fun == NULL) {
    177                 usb_log_error("Failed to create control function.\n");
     177                usb_log_error("Failed to create control function.");
    178178                return ENOMEM;
    179179        }
     
    182182        rc = ddf_fun_bind(usb_mid->ctl_fun);
    183183        if (rc != EOK) {
    184                 usb_log_error("Failed to bind control function: %s.\n",
     184                usb_log_error("Failed to bind control function: %s.",
    185185                    str_error(rc));
    186186                ddf_fun_destroy(usb_mid->ctl_fun);
  • uspace/drv/bus/usb/usbmid/main.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
     3 * Copyright (c) 2018 Petr Manek, Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    5152static errno_t usbmid_device_add(usb_device_t *dev)
    5253{
    53         usb_log_info("Taking care of new MID `%s'.\n", usb_device_get_name(dev));
     54        usb_log_info("Taking care of new MID `%s'.", usb_device_get_name(dev));
    5455
    5556        return usbmid_explore_device(dev);
     57}
     58
     59static errno_t destroy_interfaces(usb_mid_t *usb_mid)
     60{
     61        errno_t ret = EOK;
     62
     63        while (!list_empty(&usb_mid->interface_list)) {
     64                link_t *item = list_first(&usb_mid->interface_list);
     65                list_remove(item);
     66
     67                usbmid_interface_t *iface = usbmid_interface_from_link(item);
     68
     69                const errno_t pret = usbmid_interface_destroy(iface);
     70                if (pret != EOK) {
     71                        usb_log_error("Failed to remove child `%s': %s",
     72                            ddf_fun_get_name(iface->fun), str_error(pret));
     73                        ret = pret;
     74                }
     75        }
     76
     77        return ret;
    5678}
    5779
     
    7092        errno_t ret = ddf_fun_unbind(usb_mid->ctl_fun);
    7193        if (ret != EOK) {
    72                 usb_log_error("Failed to unbind USB MID ctl function: %s.\n",
     94                usb_log_error("Failed to unbind USB MID ctl function: %s.",
    7395                    str_error(ret));
    7496                return ret;
     
    7799
    78100        /* Remove all children */
    79         while (!list_empty(&usb_mid->interface_list)) {
    80                 link_t *item = list_first(&usb_mid->interface_list);
    81                 list_remove(item);
    82 
    83                 usbmid_interface_t *iface = usbmid_interface_from_link(item);
    84 
    85                 usb_log_info("Removing child `%s'.\n",
     101        list_foreach(usb_mid->interface_list, link, usbmid_interface_t, iface) {
     102                usb_log_info("Removing child `%s'.",
    86103                    ddf_fun_get_name(iface->fun));
    87104
    88                 /* Tell the child to go off-line. */
     105                /* Tell the child to go offline. */
    89106                errno_t pret = ddf_fun_offline(iface->fun);
    90107                if (pret != EOK) {
    91                         usb_log_warning("Failed to turn off child `%s': %s\n",
     108                        usb_log_warning("Failed to turn off child `%s': %s",
    92109                            ddf_fun_get_name(iface->fun), str_error(pret));
    93                         ret = pret;
    94                 }
    95 
    96                 /* Now remove the child. */
    97                 pret = usbmid_interface_destroy(iface);
    98                 if (pret != EOK) {
    99                         usb_log_error("Failed to destroy child `%s': %s\n",
    100                             ddf_fun_get_name(iface->fun), str_error(pret));
    101                         ret = pret;
    102110                }
    103111        }
    104         return ret;
     112
     113        return destroy_interfaces(usb_mid);
    105114}
    106115
     
    116125        assert(usb_mid);
    117126
    118         usb_log_info("USB MID gone: `%s'.\n", usb_device_get_name(dev));
     127        usb_log_info("USB MID gone: `%s'.", usb_device_get_name(dev));
    119128
    120129        /* Remove ctl function */
    121130        errno_t ret = ddf_fun_unbind(usb_mid->ctl_fun);
    122131        if (ret != EOK) {
    123                 usb_log_error("Failed to unbind USB MID ctl function: %s.\n",
     132                usb_log_error("Failed to unbind USB MID ctl function: %s.",
    124133                    str_error(ret));
    125134                return ret;
     
    127136        ddf_fun_destroy(usb_mid->ctl_fun);
    128137
    129         /* Now remove all other functions */
    130         while (!list_empty(&usb_mid->interface_list)) {
    131                 link_t *item = list_first(&usb_mid->interface_list);
    132                 list_remove(item);
     138        /* Destroy children and tell their drivers they are gone. */
     139        return destroy_interfaces(usb_mid);
     140}
    133141
    134                 usbmid_interface_t *iface = usbmid_interface_from_link(item);
     142static errno_t usbmid_function_online(ddf_fun_t *fun)
     143{
     144        usb_device_t *usb_dev = ddf_dev_data_get(ddf_fun_get_dev(fun));
     145        usb_mid_t *usb_mid = usb_device_data_get(usb_dev);
     146        if (fun == usb_mid->ctl_fun)
     147                return ENOTSUP;
    135148
    136                 usb_log_info("Child `%s' is gone.\n",
    137                     ddf_fun_get_name(iface->fun));
     149        return ddf_fun_online(fun);
     150}
    138151
    139                 const errno_t pret = usbmid_interface_destroy(iface);
    140                 if (pret != EOK) {
    141                         usb_log_error("Failed to remove child `%s': %s\n",
    142                             ddf_fun_get_name(iface->fun), str_error(pret));
    143                         ret = pret;
    144                 }
    145         }
    146         return ret;
     152static errno_t usbmid_function_offline(ddf_fun_t *fun)
     153{
     154        usb_device_t *usb_dev = ddf_dev_data_get(ddf_fun_get_dev(fun));
     155        usb_mid_t *usb_mid = usb_device_data_get(usb_dev);
     156        if (fun == usb_mid->ctl_fun)
     157                return ENOTSUP;
     158
     159        return ddf_fun_offline(fun);
    147160}
    148161
     
    150163static const usb_driver_ops_t mid_driver_ops = {
    151164        .device_add = usbmid_device_add,
    152         .device_rem = usbmid_device_remove,
     165        .device_remove = usbmid_device_remove,
    153166        .device_gone = usbmid_device_gone,
     167        .function_online = usbmid_function_online,
     168        .function_offline = usbmid_function_offline
    154169};
    155170
  • uspace/drv/bus/usb/usbmid/usbmid.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4546#include "usbmid.h"
    4647
    47 /** Get USB device handle by calling the parent usb_device_t.
     48/**
     49 * Get USB device description by calling HC and altering the interface field.
    4850 *
    4951 * @param[in] fun Device function the operation is running on.
    50  * @param[out] handle Device handle.
     52 * @param[out] desc Device descriptor.
    5153 * @return Error code.
    5254 */
    53 static errno_t usb_iface_device_handle(ddf_fun_t *fun, devman_handle_t *handle)
    54 {
    55         assert(fun);
    56         assert(handle);
    57         usb_device_t *usb_dev = usb_device_get(ddf_fun_get_dev(fun));
    58         *handle = usb_device_get_devman_handle(usb_dev);
    59         return EOK;
    60 }
    61 
    62 /** Callback for DDF USB get interface. */
    63 static errno_t usb_iface_iface_no(ddf_fun_t *fun, int *iface_no)
     55static errno_t usb_iface_description(ddf_fun_t *fun, usb_device_desc_t *desc)
    6456{
    6557        usbmid_interface_t *iface = ddf_fun_data_get(fun);
    6658        assert(iface);
     59        usb_device_t *usb_dev = ddf_dev_data_get(ddf_fun_get_dev(fun));
     60        assert(usb_dev);
    6761
    68         if (iface_no)
    69                 *iface_no = iface->interface_no;
     62        async_exch_t *exch = usb_device_bus_exchange_begin(usb_dev);
     63        if (!exch)
     64                return EPARTY;
     65
     66        usb_device_desc_t tmp_desc;
     67        const errno_t ret = usb_get_my_description(exch, &tmp_desc);
     68
     69        if (ret == EOK && desc) {
     70                *desc = tmp_desc;
     71                desc->iface = iface->interface_no;
     72        }
     73
     74        usb_device_bus_exchange_end(exch);
    7075
    7176        return EOK;
     
    7479/** DDF interface of the child - USB functions. */
    7580static usb_iface_t child_usb_iface = {
    76         .get_my_device_handle = usb_iface_device_handle,
    77         .get_my_interface = usb_iface_iface_no,
     81        .get_my_description = usb_iface_description,
    7882};
    7983
     
    117121         * class name something humanly understandable.
    118122         */
    119         int ret = asprintf(&child_name, "%s%hhu",
     123        errno_t ret = asprintf(&child_name, "%s%hhu",
    120124            usb_str_class(interface_descriptor->interface_class),
    121125            interface_descriptor->interface_number);
  • uspace/drv/bus/usb/vhc/conndev.c

    rf5e5f73 rdf6ded8  
    113113                receive_device_name(callback);
    114114               
    115                 usb_log_info("New virtual device `%s' (id: %" PRIxn ").\n",
     115                usb_log_info("New virtual device `%s' (id: %" PRIxn ").",
    116116                    plugged_device_name, plugged_device_handle);
    117117        } else
     
    130130
    131131        if (plugged_device_handle != 0) {
    132                 usb_log_info("Virtual device `%s' disconnected (id: %" PRIxn ").\n",
     132                usb_log_info("Virtual device `%s' disconnected (id: %" PRIxn ").",
    133133                    plugged_device_name, plugged_device_handle);
    134134                vhc_virtdev_unplug(vhc, plugged_device_handle);
  • uspace/drv/bus/usb/vhc/hub/hub.c

    rf5e5f73 rdf6ded8  
    6868
    6969/** Convert hub port state to a char. */
    70 char hub_port_state_to_char(hub_port_state_t state) {
     70char hub_port_state_to_char(hub_port_state_t state)
     71{
    7172        switch (state) {
    72                 case HUB_PORT_STATE_NOT_CONFIGURED:
    73                         return '-';
    74                 case HUB_PORT_STATE_POWERED_OFF:
    75                         return 'O';
    76                 case HUB_PORT_STATE_DISCONNECTED:
    77                         return 'X';
    78                 case HUB_PORT_STATE_DISABLED:
    79                         return 'D';
    80                 case HUB_PORT_STATE_RESETTING:
    81                         return 'R';
    82                 case HUB_PORT_STATE_ENABLED:
    83                         return 'E';
    84                 case HUB_PORT_STATE_SUSPENDED:
    85                         return 'S';
    86                 case HUB_PORT_STATE_RESUMING:
    87                         return 'F';
    88                 default:
    89                         return '?';
     73        case HUB_PORT_STATE_NOT_CONFIGURED:
     74                return '-';
     75        case HUB_PORT_STATE_POWERED_OFF:
     76                return 'O';
     77        case HUB_PORT_STATE_DISCONNECTED:
     78                return 'X';
     79        case HUB_PORT_STATE_DISABLED:
     80                return 'D';
     81        case HUB_PORT_STATE_RESETTING:
     82                return 'R';
     83        case HUB_PORT_STATE_ENABLED:
     84                return 'E';
     85        case HUB_PORT_STATE_SUSPENDED:
     86                return 'S';
     87        case HUB_PORT_STATE_RESUMING:
     88                return 'F';
     89        default:
     90                return '?';
    9091        }
    9192}
     
    231232        }
    232233
    233         usb_log_debug("Setting port %zu to state %d.\n", port_index, state);
     234        usb_log_debug("Setting port %zu to state %d.", port_index, state);
    234235
    235236        switch (state) {
    236                 case HUB_PORT_STATE_POWERED_OFF:
    237                         clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
    238                         clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
    239                         clear_port_status_change(port, HUB_STATUS_C_PORT_RESET);
    240                         break;
    241                 case HUB_PORT_STATE_RESUMING:
    242                         port->state = state;
    243                         set_port_state_delayed(hub, port_index,
    244                             10, state, HUB_PORT_STATE_ENABLED);
    245                         break;
    246                 case HUB_PORT_STATE_RESETTING:
    247                         port->state = state;
    248                         set_port_state_delayed(hub, port_index,
    249                             10, state, HUB_PORT_STATE_ENABLED);
    250                         break;
    251                 case HUB_PORT_STATE_ENABLED:
    252                         if (port->state == HUB_PORT_STATE_RESETTING) {
    253                                 set_port_status_change(port, HUB_STATUS_C_PORT_RESET);
    254                         }
    255                         break;
    256                 default:
    257                         break;
     237        case HUB_PORT_STATE_POWERED_OFF:
     238                clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
     239                clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
     240                clear_port_status_change(port, HUB_STATUS_C_PORT_RESET);
     241                break;
     242        case HUB_PORT_STATE_RESUMING:
     243                port->state = state;
     244                set_port_state_delayed(hub, port_index,
     245                    10, state, HUB_PORT_STATE_ENABLED);
     246                break;
     247        case HUB_PORT_STATE_RESETTING:
     248                port->state = state;
     249                set_port_state_delayed(hub, port_index,
     250                    10, state, HUB_PORT_STATE_ENABLED);
     251                break;
     252        case HUB_PORT_STATE_ENABLED:
     253                if (port->state == HUB_PORT_STATE_RESETTING) {
     254                        set_port_status_change(port, HUB_STATUS_C_PORT_RESET);
     255                }
     256                break;
     257        default:
     258                break;
    258259        }
    259260
     
    336337        }
    337338
    338         uint32_t status;
    339         status = MAKE_BYTE(
     339        uint32_t status = MAKE_BYTE(
    340340            /* Current connect status. */
    341341            port->connected_device == NULL ? 0 : 1,
     
    344344            /* Suspend. */
    345345            (port->state == HUB_PORT_STATE_SUSPENDED)
    346                 || (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,
     346            || (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,
    347347            /* Over-current. */
    348348            0,
     
    350350            port->state == HUB_PORT_STATE_RESETTING ? 1 : 0,
    351351            /* Reserved. */
    352             0, 0, 0)
    353 
    354             | (MAKE_BYTE(
     352            0, 0, 0);
     353
     354        status |= MAKE_BYTE(
    355355            /* Port power. */
    356356            port->state == HUB_PORT_STATE_POWERED_OFF ? 0 : 1,
     
    359359            /* Reserved. */
    360360            0, 0, 0, 0, 0, 0
    361             )) << 8;
     361            ) << 8;
    362362
    363363        status |= (port->status_change << 16);
     
    423423        uint16_t old_value = port->status_change;
    424424        port->status_change |= change;
    425         usb_log_debug("Changing status change on %zu: %04x => %04x\n",
     425        usb_log_debug("Changing status change on %zu: %04x => %04x",
    426426            port->index,
    427427            (unsigned int) old_value, (unsigned int) port->status_change);
     
    463463static errno_t set_port_state_delayed_fibril(void *arg)
    464464{
    465         struct delay_port_state_change *change
    466             = (struct delay_port_state_change *) arg;
     465        struct delay_port_state_change *change =
     466            (struct delay_port_state_change *) arg;
    467467
    468468        async_usleep(change->delay);
     
    500500    hub_port_state_t old_state, hub_port_state_t new_state)
    501501{
    502         struct delay_port_state_change *change
    503             = malloc(sizeof(struct delay_port_state_change));
     502        struct delay_port_state_change *change =
     503            malloc(sizeof(struct delay_port_state_change));
    504504
    505505        change->hub = hub;
     
    510510        fid_t fibril = fibril_create(set_port_state_delayed_fibril, change);
    511511        if (fibril == 0) {
    512                 printf("Failed to create fibril\n");
     512                usb_log_error("Failed to create fibril.");
    513513                free(change);
    514514                return;
  • uspace/drv/bus/usb/vhc/hub/virthubops.c

    rf5e5f73 rdf6ded8  
    137137
    138138        switch (feature) {
    139                 case USB_HUB_FEATURE_PORT_ENABLE:
     139                case USB2_HUB_FEATURE_PORT_ENABLE:
    140140                        if ((port_state != HUB_PORT_STATE_NOT_CONFIGURED)
    141141                            && (port_state != HUB_PORT_STATE_POWERED_OFF)) {
     
    145145                        break;
    146146
    147                 case USB_HUB_FEATURE_PORT_SUSPEND:
     147                case USB2_HUB_FEATURE_PORT_SUSPEND:
    148148                        if (port_state != HUB_PORT_STATE_SUSPENDED) {
    149149                                rc = EOK;
     
    166166                        break;
    167167
    168                 case USB_HUB_FEATURE_C_PORT_ENABLE:
     168                case USB2_HUB_FEATURE_C_PORT_ENABLE:
    169169                        hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_ENABLE);
    170170                        rc = EOK;
    171171                        break;
    172172
    173                 case USB_HUB_FEATURE_C_PORT_SUSPEND:
     173                case USB2_HUB_FEATURE_C_PORT_SUSPEND:
    174174                        hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_SUSPEND);
    175175                        rc = EOK;
     
    317317                        break;
    318318
    319                 case USB_HUB_FEATURE_PORT_SUSPEND:
     319                case USB2_HUB_FEATURE_PORT_SUSPEND:
    320320                        if (port_state == HUB_PORT_STATE_ENABLED) {
    321321                                hub_set_port_state(hub, port, HUB_PORT_STATE_SUSPENDED);
  • uspace/drv/bus/usb/vhc/main.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    4041
    4142#include <usb/host/ddf_helpers.h>
     43#include <usb/host/utility.h>
    4244
    4345#include <usb/debug.h>
     
    6971                return ret;
    7072        }
    71         vhc_init(vhc);
    7273        return EOK;
    7374}
    7475
    75 hcd_ops_t vhc_hc_ops = {
    76         .schedule = vhc_schedule,
    77 };
    78 
    7976static errno_t vhc_dev_add(ddf_dev_t *dev)
    8077{
     78        /* Initialize generic structures */
     79        errno_t ret = hcd_ddf_setup_hc(dev, sizeof(vhc_data_t));
     80        if (ret != EOK) {
     81                usb_log_error("Failed to init HCD structures: %s.",
     82                   str_error(ret));
     83                return ret;
     84        }
     85        vhc_data_t *vhc = ddf_dev_data_get(dev);
     86        vhc_init(vhc);
     87
     88        hc_device_setup(&vhc->base, (bus_t *) &vhc->bus);
     89
    8190        /* Initialize virtual structure */
    8291        ddf_fun_t *ctl_fun = NULL;
    83         errno_t ret = vhc_control_node(dev, &ctl_fun);
     92        ret = vhc_control_node(dev, &ctl_fun);
    8493        if (ret != EOK) {
    85                 usb_log_error("Failed to setup control node.\n");
    86                 return ret;
    87         }
    88         vhc_data_t *data = ddf_fun_data_get(ctl_fun);
    89 
    90         /* Initialize generic structures */
    91         ret = hcd_ddf_setup_hc(dev, USB_SPEED_FULL,
    92             BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
    93         if (ret != EOK) {
    94                 usb_log_error("Failed to init HCD structures: %s.\n",
    95                    str_error(ret));
    96                 ddf_fun_destroy(ctl_fun);
     94                usb_log_error("Failed to setup control node.");
    9795                return ret;
    9896        }
    9997
    100         hcd_set_implementation(dev_to_hcd(dev), data, &vhc_hc_ops);
    101 
    10298        /* Add virtual hub device */
    103         ret = vhc_virtdev_plug_hub(data, &data->hub, NULL, 0);
     99        ret = vhc_virtdev_plug_hub(vhc, &vhc->hub, NULL, 0);
    104100        if (ret != EOK) {
    105                 usb_log_error("Failed to plug root hub: %s.\n", str_error(ret));
     101                usb_log_error("Failed to plug root hub: %s.", str_error(ret));
    106102                ddf_fun_destroy(ctl_fun);
    107103                return ret;
     
    112108         * needs to be ready at this time.
    113109         */
    114         ret = hcd_ddf_setup_root_hub(dev);
     110        ret = hc_setup_virtual_root_hub(&vhc->base, USB_SPEED_HIGH);
    115111        if (ret != EOK) {
    116                 usb_log_error("Failed to init VHC root hub: %s\n",
     112                usb_log_error("Failed to init VHC root hub: %s",
    117113                        str_error(ret));
    118114                // TODO do something here...
  • uspace/drv/bus/usb/vhc/transfer.c

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    3132#include <usb/debug.h>
    3233#include <usbvirt/device.h>
     34#include <usb/host/bandwidth.h>
     35#include <usb/host/endpoint.h>
     36#include <usb/host/usb_transfer_batch.h>
    3337#include <usbvirt/ipc.h>
    3438#include "vhcd.h"
     
    3741static bool is_set_address_transfer(vhc_transfer_t *transfer)
    3842{
    39         if (transfer->batch->ep->endpoint != 0) {
    40                 return false;
    41         }
    42         if (transfer->batch->ep->transfer_type != USB_TRANSFER_CONTROL) {
    43                 return false;
    44         }
    45         if (usb_transfer_batch_direction(transfer->batch) != USB_DIRECTION_OUT) {
     43        if (transfer->batch.target.endpoint != 0) {
     44                return false;
     45        }
     46        if (transfer->batch.ep->transfer_type != USB_TRANSFER_CONTROL) {
     47                return false;
     48        }
     49        if (transfer->batch.dir != USB_DIRECTION_OUT) {
    4650                return false;
    4751        }
    4852        const usb_device_request_setup_packet_t *setup =
    49             (void*)transfer->batch->setup_buffer;
     53            &transfer->batch.setup.packet;
    5054        if (setup->request_type != 0) {
    5155                return false;
     
    6266{
    6367        errno_t rc;
    64        
    65         const usb_direction_t dir = usb_transfer_batch_direction(batch);
     68
     69        const usb_direction_t dir = batch->dir;
    6670
    6771        if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
    6872                if (dir == USB_DIRECTION_IN) {
    6973                        rc = usbvirt_control_read(dev,
    70                             batch->setup_buffer, batch->setup_size,
    71                             batch->buffer, batch->buffer_size,
     74                            batch->setup.buffer, USB_SETUP_PACKET_SIZE,
     75                            batch->dma_buffer.virt, batch->size,
    7276                            actual_data_size);
    7377                } else {
    7478                        assert(dir == USB_DIRECTION_OUT);
    7579                        rc = usbvirt_control_write(dev,
    76                             batch->setup_buffer, batch->setup_size,
    77                             batch->buffer, batch->buffer_size);
     80                            batch->setup.buffer, USB_SETUP_PACKET_SIZE,
     81                            batch->dma_buffer.virt, batch->size);
    7882                }
    7983        } else {
     
    8185                        rc = usbvirt_data_in(dev, batch->ep->transfer_type,
    8286                            batch->ep->endpoint,
    83                             batch->buffer, batch->buffer_size,
     87                            batch->dma_buffer.virt, batch->size,
    8488                            actual_data_size);
    8589                } else {
     
    8791                        rc = usbvirt_data_out(dev, batch->ep->transfer_type,
    8892                            batch->ep->endpoint,
    89                             batch->buffer, batch->buffer_size);
     93                            batch->dma_buffer.virt, batch->size);
    9094                }
    9195        }
     
    99103        errno_t rc;
    100104
    101         const usb_direction_t dir = usb_transfer_batch_direction(batch);
     105        const usb_direction_t dir = batch->dir;
    102106
    103107        if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
    104108                if (dir == USB_DIRECTION_IN) {
    105109                        rc = usbvirt_ipc_send_control_read(sess,
    106                             batch->setup_buffer, batch->setup_size,
    107                             batch->buffer, batch->buffer_size,
     110                            batch->setup.buffer, USB_SETUP_PACKET_SIZE,
     111                            batch->dma_buffer.virt, batch->size,
    108112                            actual_data_size);
    109113                } else {
    110114                        assert(dir == USB_DIRECTION_OUT);
    111115                        rc = usbvirt_ipc_send_control_write(sess,
    112                             batch->setup_buffer, batch->setup_size,
    113                             batch->buffer, batch->buffer_size);
     116                            batch->setup.buffer, USB_SETUP_PACKET_SIZE,
     117                            batch->dma_buffer.virt, batch->size);
    114118                }
    115119        } else {
     
    117121                        rc = usbvirt_ipc_send_data_in(sess, batch->ep->endpoint,
    118122                            batch->ep->transfer_type,
    119                             batch->buffer, batch->buffer_size,
     123                            batch->dma_buffer.virt, batch->size,
    120124                            actual_data_size);
    121125                } else {
     
    123127                        rc = usbvirt_ipc_send_data_out(sess, batch->ep->endpoint,
    124128                            batch->ep->transfer_type,
    125                             batch->buffer, batch->buffer_size);
     129                            batch->dma_buffer.virt, batch->size);
    126130                }
    127131        }
     
    135139        assert(!list_empty(&dev->transfer_queue));
    136140
    137         vhc_transfer_t *transfer = list_get_instance(
    138             list_first(&dev->transfer_queue), vhc_transfer_t, link);
     141        vhc_transfer_t *transfer =
     142            list_get_instance(list_first(&dev->transfer_queue),
     143            vhc_transfer_t, link);
    139144        list_remove(&transfer->link);
    140145
     
    147152        assert(outcome != ENAK);
    148153        assert(transfer);
    149         assert(transfer->batch);
    150         usb_transfer_batch_finish_error(transfer->batch, NULL,
    151             data_transfer_size, outcome);
    152         usb_transfer_batch_destroy(transfer->batch);
    153         free(transfer);
    154 }
     154        transfer->batch.error = outcome;
     155        transfer->batch.transferred_size = data_transfer_size;
     156        usb_transfer_batch_finish(&transfer->batch);
     157}
     158
     159static usb_transfer_batch_t *batch_create(endpoint_t *ep)
     160{
     161        vhc_transfer_t *transfer = calloc(1, sizeof(vhc_transfer_t));
     162        usb_transfer_batch_init(&transfer->batch, ep);
     163        link_initialize(&transfer->link);
     164        return &transfer->batch;
     165}
     166
     167static int device_enumerate(device_t *device)
     168{
     169        vhc_data_t *vhc = bus_to_vhc(device->bus);
     170        return usb2_bus_device_enumerate(&vhc->bus_helper, device);
     171}
     172
     173static int endpoint_register(endpoint_t *endpoint)
     174{
     175        vhc_data_t *vhc = bus_to_vhc(endpoint->device->bus);
     176        return usb2_bus_endpoint_register(&vhc->bus_helper, endpoint);
     177}
     178
     179static void endpoint_unregister(endpoint_t *endpoint)
     180{
     181        vhc_data_t *vhc = bus_to_vhc(endpoint->device->bus);
     182        usb2_bus_endpoint_unregister(&vhc->bus_helper, endpoint);
     183
     184        // TODO: abort transfer?
     185}
     186
     187static const bus_ops_t vhc_bus_ops = {
     188        .batch_create = batch_create,
     189        .batch_schedule = vhc_schedule,
     190
     191        .device_enumerate = device_enumerate,
     192        .endpoint_register = endpoint_register,
     193        .endpoint_unregister = endpoint_unregister,
     194};
    155195
    156196errno_t vhc_init(vhc_data_t *instance)
     
    159199        list_initialize(&instance->devices);
    160200        fibril_mutex_initialize(&instance->guard);
    161         instance->magic = 0xDEADBEEF;
     201        bus_init(&instance->bus, sizeof(device_t));
     202        usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11);
     203        instance->bus.ops = &vhc_bus_ops;
    162204        return virthub_init(&instance->hub, "root hub");
    163205}
    164206
    165 errno_t vhc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    166 {
    167         assert(hcd);
     207errno_t vhc_schedule(usb_transfer_batch_t *batch)
     208{
    168209        assert(batch);
    169         vhc_data_t *vhc = hcd_get_driver_data(hcd);
     210        vhc_transfer_t *transfer = (vhc_transfer_t *) batch;
     211        vhc_data_t *vhc = bus_to_vhc(endpoint_get_bus(batch->ep));
    170212        assert(vhc);
    171 
    172         vhc_transfer_t *transfer = malloc(sizeof(vhc_transfer_t));
    173         if (!transfer)
    174                 return ENOMEM;
    175         link_initialize(&transfer->link);
    176         transfer->batch = batch;
    177213
    178214        fibril_mutex_lock(&vhc->guard);
     
    182218        list_foreach(vhc->devices, link, vhc_virtdev_t, dev) {
    183219                fibril_mutex_lock(&dev->guard);
    184                 if (dev->address == transfer->batch->ep->address) {
     220                if (dev->address == transfer->batch.target.address) {
    185221                        if (!targets) {
    186222                                list_append(&transfer->link, &dev->transfer_queue);
     
    194230       
    195231        if (targets > 1)
    196                 usb_log_warning("Transfer would be accepted by more devices!\n");
     232                usb_log_warning("Transfer would be accepted by more devices!");
    197233
    198234        return targets ? EOK : ENOENT;
     
    217253                size_t data_transfer_size = 0;
    218254                if (dev->dev_sess) {
    219                         rc = process_transfer_remote(transfer->batch,
     255                        rc = process_transfer_remote(&transfer->batch,
    220256                            dev->dev_sess, &data_transfer_size);
    221257                } else if (dev->dev_local != NULL) {
    222                         rc = process_transfer_local(transfer->batch,
     258                        rc = process_transfer_local(&transfer->batch,
    223259                            dev->dev_local, &data_transfer_size);
    224260                } else {
    225                         usb_log_warning("Device has no remote phone nor local node.\n");
     261                        usb_log_warning("Device has no remote phone "
     262                            "nor local node.");
    226263                        rc = ESTALL;
    227264                }
    228265
    229                 usb_log_debug2("Transfer %p processed: %s.\n",
     266                usb_log_debug2("Transfer %p processed: %s.",
    230267                    transfer, str_error(rc));
    231268
     
    234271                        if (is_set_address_transfer(transfer)) {
    235272                                usb_device_request_setup_packet_t *setup =
    236                                     (void*) transfer->batch->setup_buffer;
     273                                    (void *) transfer->batch.setup.buffer;
    237274                                dev->address = setup->value;
    238                                 usb_log_debug2("Address changed to %d\n",
     275                                usb_log_debug2("Address changed to %d",
    239276                                    dev->address);
    240277                        }
  • uspace/drv/bus/usb/vhc/vhcd.h

    rf5e5f73 rdf6ded8  
    11/*
    22 * Copyright (c) 2010 Vojtech Horky
     3 * Copyright (c) 2018 Ondrej Hlavaty
    34 * All rights reserved.
    45 *
     
    3839
    3940#include <usbvirt/device.h>
    40 #include <usbhc_iface.h>
    4141#include <async.h>
     42#include <macros.h>
    4243
    4344#include <usb/host/hcd.h>
     45#include <usb/host/usb2_bus.h>
     46#include <usb/host/usb_transfer_batch.h>
    4447
    4548#define NAME "vhc"
     
    5659
    5760typedef struct {
    58         uint32_t magic;
     61        hc_device_t base;
     62
     63        bus_t bus;
     64        usb2_bus_helper_t bus_helper;
     65
     66        ddf_fun_t *virtual_fun;
    5967        list_t devices;
    6068        fibril_mutex_t guard;
     
    6371
    6472typedef struct {
     73        usb_transfer_batch_t batch;
    6574        link_t link;
    66         usb_transfer_batch_t *batch;
    6775} vhc_transfer_t;
     76
     77static inline vhc_data_t *hcd_to_vhc(hc_device_t *hcd)
     78{
     79        assert(hcd);
     80        return (vhc_data_t *) hcd;
     81}
     82
     83static inline vhc_data_t *bus_to_vhc(bus_t *bus)
     84{
     85        assert(bus);
     86        return member_to_inst(bus, vhc_data_t, bus);
     87}
    6888
    6989void on_client_close(ddf_fun_t *fun);
     
    7393errno_t vhc_virtdev_plug(vhc_data_t *, async_sess_t *, uintptr_t *);
    7494errno_t vhc_virtdev_plug_local(vhc_data_t *, usbvirt_device_t *, uintptr_t *);
    75 errno_t vhc_virtdev_plug_hub(vhc_data_t *, usbvirt_device_t *, uintptr_t *, usb_address_t address);
     95errno_t vhc_virtdev_plug_hub(vhc_data_t *, usbvirt_device_t *, uintptr_t *,
     96    usb_address_t address);
    7697void vhc_virtdev_unplug(vhc_data_t *, uintptr_t);
    7798
    78 errno_t vhc_init(vhc_data_t *instance);
    79 errno_t vhc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
     99errno_t vhc_init(vhc_data_t *);
     100errno_t vhc_schedule(usb_transfer_batch_t *);
    80101errno_t vhc_transfer_queue_processor(void *arg);
    81102
Note: See TracChangeset for help on using the changeset viewer.