Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/ehci/ehci_batch.c

    r090eea68 r5fd9c30  
    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;
     61void ehci_transfer_batch_destroy(ehci_transfer_batch_t *ehci_batch)
     62{
     63        assert(ehci_batch);
    6564        if (ehci_batch->tds) {
    6665                for (size_t i = 0; i < ehci_batch->td_count; ++i) {
     
    6968                free(ehci_batch->tds);
    7069        }
    71         usb_transfer_batch_destroy(ehci_batch->usb_batch);
    7270        free32(ehci_batch->device_buffer);
    7371        free(ehci_batch);
     
    7573}
    7674
    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);
    88 }
    89 
    9075/** Allocate memory and initialize internal data structure.
    9176 *
     
    9479 * NULL otherwise.
    9580 *
     81 */
     82ehci_transfer_batch_t * ehci_transfer_batch_create(endpoint_t *ep)
     83{
     84        assert(ep);
     85
     86        ehci_transfer_batch_t *ehci_batch = calloc(1, sizeof(ehci_transfer_batch_t));
     87        if (!ehci_batch) {
     88                usb_log_error("Failed to allocate EHCI batch data.");
     89                return NULL;
     90        }
     91
     92        usb_transfer_batch_init(&ehci_batch->base, ep);
     93        link_initialize(&ehci_batch->link);
     94
     95        return ehci_batch;
     96}
     97
     98/** Prepares a batch to be sent.
     99 *
    96100 * Determines the number of needed transfer descriptors (TDs).
    97101 * Prepares a transport buffer (that is accessible by the hardware).
    98102 * Initializes parameters needed for the transfer and callback.
    99103 */
    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;
     104int ehci_transfer_batch_prepare(ehci_transfer_batch_t *ehci_batch)
     105{
     106        assert(ehci_batch);
     107
     108        const size_t setup_size = (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
     109                ? USB_SETUP_PACKET_SIZE
     110                : 0;
     111
     112        const size_t size = ehci_batch->base.buffer_size;
     113
     114        /* Mix setup stage and data together, we have enough space */
     115        if (size + setup_size > 0) {
     116                /* Use one buffer for setup and data stage */
     117                ehci_batch->device_buffer = malloc32(size + setup_size);
     118                if (!ehci_batch->device_buffer) {
     119                        usb_log_error("Batch %p: Failed to allocate device "
     120                            "buffer", ehci_batch);
     121                        return ENOMEM;
     122                }
     123                /* Copy setup data */
     124                memcpy(ehci_batch->device_buffer, ehci_batch->base.setup.buffer,
     125                    setup_size);
     126                /* Copy generic data */
     127                if (ehci_batch->base.dir != USB_DIRECTION_IN)
     128                        memcpy(ehci_batch->device_buffer + setup_size,
     129                            ehci_batch->base.buffer, ehci_batch->base.buffer_size);
     130        }
     131
     132        /* Add TD left over by the previous transfer */
     133        ehci_batch->qh = ehci_endpoint_get(ehci_batch->base.ep)->qh;
     134
     135        /* Determine number of TDs needed */
     136        ehci_batch->td_count = (size + EHCI_TD_MAX_TRANSFER - 1)
     137                / EHCI_TD_MAX_TRANSFER;
    115138
    116139        /* Control transfer need Setup and Status stage */
    117         if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
     140        if (ehci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL) {
    118141                ehci_batch->td_count += 2;
    119142        }
     
    122145        if (!ehci_batch->tds) {
    123146                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;
     147                    "descriptors.", ehci_batch);
     148                return ENOMEM;
     149        }
    130150
    131151        for (unsigned i = 0; i < ehci_batch->td_count; ++i) {
     
    133153                if (!ehci_batch->tds[i]) {
    134154                        usb_log_error("Batch %p: Failed to allocate TD %d.",
    135                             usb_batch, i);
    136                         goto dispose;
     155                            ehci_batch, i);
     156                        return ENOMEM;
    137157                }
    138158                memset(ehci_batch->tds[i], 0, sizeof(td_t));
    139159        }
    140160
    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);
     161        assert(batch_setup[ehci_batch->base.ep->transfer_type]);
     162        batch_setup[ehci_batch->base.ep->transfer_type](ehci_batch);
    166163
    167164        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;
     165            ehci_batch, usb_str_direction(ehci_batch->base.dir),
     166            USB_TRANSFER_BATCH_ARGS(ehci_batch->base));
     167
     168        return EOK;
    175169}
    176170
     
    184178 * completes with the last TD.
    185179 */
    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);
     180bool ehci_transfer_batch_check_completed(ehci_transfer_batch_t *ehci_batch)
     181{
     182        assert(ehci_batch);
    190183
    191184        usb_log_debug("Batch %p: checking %zu td(s) for completion.\n",
    192             ehci_batch->usb_batch, ehci_batch->td_count);
     185            ehci_batch, ehci_batch->td_count);
    193186
    194187        usb_log_debug2("Batch %p: QH: %08x:%08x:%08x:%08x:%08x:%08x.\n",
    195             ehci_batch->usb_batch,
     188            ehci_batch,
    196189            ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
    197190            ehci_batch->qh->status, ehci_batch->qh->current,
     
    206199
    207200        /* Assume all data got through */
    208         ehci_batch->usb_batch->transfered_size =
    209             ehci_batch->usb_batch->buffer_size;
     201        ehci_batch->base.transfered_size = ehci_batch->base.buffer_size;
    210202
    211203        /* Check all TDs */
     
    213205                assert(ehci_batch->tds[i] != NULL);
    214206                usb_log_debug("Batch %p: TD %zu: %08x:%08x:%08x.",
    215                     ehci_batch->usb_batch, i,
     207                    ehci_batch, i,
    216208                    ehci_batch->tds[i]->status, ehci_batch->tds[i]->next,
    217209                    ehci_batch->tds[i]->alternate);
    218210
    219                 ehci_batch->usb_batch->error = td_error(ehci_batch->tds[i]);
    220                 if (ehci_batch->usb_batch->error == EOK) {
     211                ehci_batch->base.error = td_error(ehci_batch->tds[i]);
     212                if (ehci_batch->base.error == EOK) {
    221213                        /* If the TD got all its data through, it will report
    222214                         * 0 bytes remain, the sole exception is INPUT with
     
    231223                         * we leave the very last(unused) TD behind.
    232224                         */
    233                         ehci_batch->usb_batch->transfered_size
     225                        ehci_batch->base.transfered_size
    234226                            -= td_remain_size(ehci_batch->tds[i]);
    235227                } else {
    236228                        usb_log_debug("Batch %p found error TD(%zu):%08x (%d).",
    237                             ehci_batch->usb_batch, i,
     229                            ehci_batch, i,
    238230                            ehci_batch->tds[i]->status,
    239                             ehci_batch->usb_batch->error);
     231                            ehci_batch->base.error);
    240232                        /* Clear possible ED HALT */
    241233                        qh_clear_halt(ehci_batch->qh);
     
    244236        }
    245237
    246         assert(ehci_batch->usb_batch->transfered_size <=
    247             ehci_batch->usb_batch->buffer_size);
     238        assert(ehci_batch->base.transfered_size <= ehci_batch->base.buffer_size);
     239
     240        if (ehci_batch->base.dir == USB_DIRECTION_IN)
     241                memcpy(ehci_batch->base.buffer, ehci_batch->device_buffer, ehci_batch->base.transfered_size);
     242
    248243        /* Clear TD pointers */
    249244        ehci_batch->qh->next = LINK_POINTER_TERM;
    250245        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));
     246        usb_log_debug("Batch %p complete: %s", ehci_batch,
     247            str_error(ehci_batch->base.error));
    253248
    254249        return true;
     
    268263 *
    269264 * @param[in] ehci_batch Batch structure to use.
    270  * @param[in] dir Communication direction
    271265 *
    272266 * 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);
     267 * Data stage with alternating toggle and direction
     268 * Status stage with toggle 1 and direction
     269 */
     270static void batch_control(ehci_transfer_batch_t *ehci_batch)
     271{
     272        assert(ehci_batch);
     273
     274        usb_direction_t dir = ehci_batch->base.dir;
    280275        assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
    281276
    282277        usb_log_debug2("Batch %p: Control QH(%"PRIxn"): "
    283             "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch->usb_batch,
     278            "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch,
    284279            addr_to_phys(ehci_batch->qh),
    285280            ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
     
    298293        /* Setup stage */
    299294        td_init(ehci_batch->tds[0], ehci_batch->tds[1], USB_DIRECTION_BOTH,
    300             buffer, ehci_batch->usb_batch->setup_size, toggle, false);
     295            buffer, USB_SETUP_PACKET_SIZE, toggle, false);
    301296        usb_log_debug2("Batch %p: Created CONTROL SETUP TD(%"PRIxn"): "
    302             "%08x:%08x:%08x", ehci_batch->usb_batch,
     297            "%08x:%08x:%08x", ehci_batch,
    303298            addr_to_phys(ehci_batch->tds[0]),
    304299            ehci_batch->tds[0]->status, ehci_batch->tds[0]->next,
    305300            ehci_batch->tds[0]->alternate);
    306         buffer += ehci_batch->usb_batch->setup_size;
     301        buffer += USB_SETUP_PACKET_SIZE;
    307302
    308303        /* Data stage */
    309304        size_t td_current = 1;
    310         size_t remain_size = ehci_batch->usb_batch->buffer_size;
     305        size_t remain_size = ehci_batch->base.buffer_size;
    311306        while (remain_size > 0) {
    312307                const size_t transfer_size =
     
    318313                    transfer_size, toggle, false);
    319314                usb_log_debug2("Batch %p: Created CONTROL DATA TD(%"PRIxn"): "
    320                     "%08x:%08x:%08x", ehci_batch->usb_batch,
     315                    "%08x:%08x:%08x", ehci_batch,
    321316                    addr_to_phys(ehci_batch->tds[td_current]),
    322317                    ehci_batch->tds[td_current]->status,
     
    334329        td_init(ehci_batch->tds[td_current], NULL, status_dir, NULL, 0, 1, true);
    335330        usb_log_debug2("Batch %p: Created CONTROL STATUS TD(%"PRIxn"): "
    336             "%08x:%08x:%08x", ehci_batch->usb_batch,
     331            "%08x:%08x:%08x", ehci_batch,
    337332            addr_to_phys(ehci_batch->tds[td_current]),
    338333            ehci_batch->tds[td_current]->status,
     
    349344 * EHCI hw in ED.
    350345 */
    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);
     346static void batch_data(ehci_transfer_batch_t *ehci_batch)
     347{
     348        assert(ehci_batch);
    356349
    357350        usb_log_debug2("Batch %p: Data QH(%"PRIxn"): "
    358             "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch->usb_batch,
     351            "%08x:%08x:%08x:%08x:%08x:%08x", ehci_batch,
    359352            addr_to_phys(ehci_batch->qh),
    360353            ehci_batch->qh->ep_char, ehci_batch->qh->ep_cap,
     
    363356
    364357        size_t td_current = 0;
    365         size_t remain_size = ehci_batch->usb_batch->buffer_size;
     358        size_t remain_size = ehci_batch->base.buffer_size;
    366359        char *buffer = ehci_batch->device_buffer;
    367360        while (remain_size > 0) {
     
    373366                    ehci_batch->tds[td_current],
    374367                    last ? NULL : ehci_batch->tds[td_current + 1],
    375                     dir, buffer, transfer_size, -1, last);
     368                    ehci_batch->base.dir, buffer, transfer_size, -1, last);
    376369
    377370                usb_log_debug2("Batch %p: DATA TD(%"PRIxn": %08x:%08x:%08x",
    378                     ehci_batch->usb_batch,
     371                    ehci_batch,
    379372                    addr_to_phys(ehci_batch->tds[td_current]),
    380373                    ehci_batch->tds[td_current]->status,
     
    390383
    391384/** Transfer setup table. */
    392 static void (*const batch_setup[])(ehci_transfer_batch_t*, usb_direction_t) =
     385static void (*const batch_setup[])(ehci_transfer_batch_t*) =
    393386{
    394387        [USB_TRANSFER_CONTROL] = batch_control,
Note: See TracChangeset for help on using the changeset viewer.