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


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

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

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

Notable additions and features:

  • new host controller driver has been implemented to control various xHC models (among others, NEC Renesas uPD720200)
  • isochronous data transfer mode
  • support for explicit USB device removal
  • USB tablet driver
Location:
uspace/drv/bus/usb/ehci
Files:
1 added
1 deleted
18 edited
1 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
Note: See TracChangeset for help on using the changeset viewer.