Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 5fd9c30 in mainline


Ignore:
Timestamp:
2017-10-21T20:52:56Z (4 years ago)
Author:
Ondřej Hlavatý <aearsis@…>
Branches:
lfn, master
Children:
766043c
Parents:
74b852b
Message:

usbhost refactoring: let transfer_batch be initialized by bus

Currently makes older HCs fail, work in progress.

Location:
uspace
Files:
28 edited

Legend:

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

    r74b852b r5fd9c30  
    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,
  • uspace/drv/bus/usb/ehci/ehci_batch.h

    r74b852b r5fd9c30  
    4545/** EHCI specific data required for USB transfer */
    4646typedef struct ehci_transfer_batch {
     47        usb_transfer_batch_t base;
    4748        /** Link */
    4849        link_t link;
     
    5960} ehci_transfer_batch_t;
    6061
    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);
     62ehci_transfer_batch_t * ehci_transfer_batch_create(endpoint_t *ep);
     63int ehci_transfer_batch_prepare(ehci_transfer_batch_t *batch);
    6364void ehci_transfer_batch_commit(const ehci_transfer_batch_t *batch);
    64 void ehci_transfer_batch_finish_dispose(ehci_transfer_batch_t *batch);
     65bool ehci_transfer_batch_check_completed(ehci_transfer_batch_t *batch);
     66void ehci_transfer_batch_destroy(ehci_transfer_batch_t *batch);
    6567
    6668static inline ehci_transfer_batch_t *ehci_transfer_batch_from_link(link_t *l)
     
    6971        return list_get_instance(l, ehci_transfer_batch_t, link);
    7072}
     73
     74static inline ehci_transfer_batch_t * ehci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
     75{
     76        assert(usb_batch);
     77
     78        return (ehci_transfer_batch_t *) usb_batch;
     79}
     80
    7181#endif
    7282/**
  • uspace/drv/bus/usb/ehci/ehci_bus.c

    r74b852b r5fd9c30  
    4141
    4242#include "ehci_bus.h"
     43#include "ehci_batch.h"
    4344#include "hc.h"
    4445
     
    140141        hc_dequeue_endpoint(bus->hc, ep);
    141142        return EOK;
     143}
    142144
     145static usb_transfer_batch_t *ehci_bus_create_batch(bus_t *bus, endpoint_t *ep)
     146{
     147        ehci_transfer_batch_t *batch = ehci_transfer_batch_create(ep);
     148        return &batch->base;
     149}
     150
     151static void ehci_bus_destroy_batch(usb_transfer_batch_t *batch)
     152{
     153        ehci_transfer_batch_destroy(ehci_transfer_batch_get(batch));
    143154}
    144155
     
    161172        ops->release_endpoint = ehci_release_ep;
    162173
     174        ops->create_batch = ehci_bus_create_batch;
     175        ops->destroy_batch = ehci_bus_destroy_batch;
     176
    163177        bus->hc = hc;
    164178
  • uspace/drv/bus/usb/ehci/ehci_rh.c

    r74b852b r5fd9c30  
    146146        const usb_target_t target = batch->ep->target;
    147147        batch->error = virthub_base_request(&instance->base, target,
    148             usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,
     148            batch->dir, (void*) batch->setup.buffer,
    149149            batch->buffer, batch->buffer_size, &batch->transfered_size);
    150150        if (batch->error == ENAK) {
     
    157157                instance->unfinished_interrupt_transfer = batch;
    158158        } else {
    159                 usb_transfer_batch_finish(batch, NULL);
    160                 usb_transfer_batch_destroy(batch);
    161159                usb_log_debug("RH(%p): BATCH(%p) virtual request complete: %s",
    162160                    instance, batch, str_error(batch->error));
     161                usb_transfer_batch_finish(batch);
    163162        }
    164163        return EOK;
     
    182181                const usb_target_t target = batch->ep->target;
    183182                batch->error = virthub_base_request(&instance->base, target,
    184                     usb_transfer_batch_direction(batch),
    185                     (void*)batch->setup_buffer,
     183                    batch->dir, (void*) batch->setup.buffer,
    186184                    batch->buffer, batch->buffer_size, &batch->transfered_size);
    187                 usb_transfer_batch_finish(batch, NULL);
    188                 usb_transfer_batch_destroy(batch);
     185                usb_transfer_batch_finish(batch);
    189186        }
    190187        return EOK;
  • uspace/drv/bus/usb/ehci/hc.c

    r74b852b r5fd9c30  
    296296                return ehci_rh_schedule(&instance->rh, batch);
    297297        }
     298
    298299        ehci_transfer_batch_t *ehci_batch = ehci_transfer_batch_get(batch);
    299         if (!ehci_batch)
    300                 return ENOMEM;
     300
     301        const int err = ehci_transfer_batch_prepare(ehci_batch);
     302        if (err)
     303                return err;
    301304
    302305        fibril_mutex_lock(&instance->guard);
     
    343346                            ehci_transfer_batch_from_link(current);
    344347
    345                         if (ehci_transfer_batch_is_complete(batch)) {
     348                        if (ehci_transfer_batch_check_completed(batch)) {
    346349                                list_remove(current);
    347                                 ehci_transfer_batch_finish_dispose(batch);
     350                                usb_transfer_batch_finish(&batch->base);
    348351                        }
    349352                }
  • uspace/drv/bus/usb/ohci/hc.c

    r74b852b r5fd9c30  
    295295                return ENOMEM;
    296296
     297        const int err = ohci_transfer_batch_prepare(ohci_batch);
     298        if (err)
     299                return err;
     300
    297301        fibril_mutex_lock(&instance->guard);
    298302        list_append(&ohci_batch->link, &instance->pending_batches);
     
    346350                            ohci_transfer_batch_from_link(current);
    347351
    348                         if (ohci_transfer_batch_is_complete(batch)) {
     352                        if (ohci_transfer_batch_check_completed(batch)) {
    349353                                list_remove(current);
    350                                 ohci_transfer_batch_finish_dispose(batch);
     354                                usb_transfer_batch_finish(&batch->base);
    351355                        }
    352356
  • uspace/drv/bus/usb/ohci/ohci_batch.c

    r74b852b r5fd9c30  
    4747#include "ohci_bus.h"
    4848
    49 static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t);
     49static void (*const batch_setup[])(ohci_transfer_batch_t*);
    5050
    5151/** Safely destructs ohci_transfer_batch_t structure
     
    5353 * @param[in] ohci_batch Instance to destroy.
    5454 */
    55 static void ohci_transfer_batch_dispose(ohci_transfer_batch_t *ohci_batch)
    56 {
    57         if (!ohci_batch)
    58                 return;
     55void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch)
     56{
     57        assert(ohci_batch);
    5958        if (ohci_batch->tds) {
    6059                const ohci_endpoint_t *ohci_ep =
     
    6766                free(ohci_batch->tds);
    6867        }
    69         usb_transfer_batch_destroy(ohci_batch->usb_batch);
    7068        free32(ohci_batch->device_buffer);
    7169        free(ohci_batch);
    72 }
    73 
    74 /** Finishes usb_transfer_batch and destroys the structure.
    75  *
    76  * @param[in] uhci_batch Instance to finish and destroy.
    77  */
    78 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *ohci_batch)
    79 {
    80         assert(ohci_batch);
    81         assert(ohci_batch->usb_batch);
    82         usb_transfer_batch_finish(ohci_batch->usb_batch,
    83             ohci_batch->device_buffer + ohci_batch->usb_batch->setup_size);
    84         ohci_transfer_batch_dispose(ohci_batch);
    8570}
    8671
     
    9075 * @return Valid pointer if all structures were successfully created,
    9176 * NULL otherwise.
    92  *
    93  * Determines the number of needed transfer descriptors (TDs).
    94  * Prepares a transport buffer (that is accessible by the hardware).
    95  * Initializes parameters needed for the transfer and callback.
    96  */
    97 ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
    98 {
    99         assert(usb_batch);
     77 */
     78ohci_transfer_batch_t * ohci_transfer_batch_create(endpoint_t *ep)
     79{
     80        assert(ep);
    10081
    10182        ohci_transfer_batch_t *ohci_batch =
     
    10384        if (!ohci_batch) {
    10485                usb_log_error("Failed to allocate OHCI batch data.");
    105                 goto dispose;
    106         }
     86                return NULL;
     87        }
     88
     89        usb_transfer_batch_init(&ohci_batch->base, ep);
    10790        link_initialize(&ohci_batch->link);
    108         ohci_batch->td_count =
    109             (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1)
     91
     92        return ohci_batch;
     93}
     94
     95/** Prepares a batch to be sent.
     96 *
     97 * Determines the number of needed transfer descriptors (TDs).
     98 * Prepares a transport buffer (that is accessible by the hardware).
     99 * Initializes parameters needed for the transfer and callback.
     100 */
     101int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch)
     102{
     103        assert(ohci_batch);
     104
     105        const size_t setup_size = (ohci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
     106                ? USB_SETUP_PACKET_SIZE
     107                : 0;
     108
     109        usb_transfer_batch_t *usb_batch = &ohci_batch->base;
     110
     111        ohci_batch->td_count = (usb_batch->buffer_size + OHCI_TD_MAX_TRANSFER - 1)
    110112            / OHCI_TD_MAX_TRANSFER;
    111113        /* Control transfer need Setup and Status stage */
     
    118120        if (!ohci_batch->tds) {
    119121                usb_log_error("Failed to allocate OHCI transfer descriptors.");
    120                 goto dispose;
     122                return ENOMEM;
    121123        }
    122124
     
    129131                if (!ohci_batch->tds[i]) {
    130132                        usb_log_error("Failed to allocate TD %d.", i);
    131                         goto dispose;
     133                        return ENOMEM;
    132134                }
    133135        }
    134 
    135136
    136137        /* NOTE: OHCI is capable of handling buffer that crosses page boundaries
     
    138139         * than two pages (the first page is computed using start pointer, the
    139140         * other using the end pointer) */
    140         if (usb_batch->setup_size + usb_batch->buffer_size > 0) {
     141        if (setup_size + usb_batch->buffer_size > 0) {
    141142                /* Use one buffer for setup and data stage */
    142143                ohci_batch->device_buffer =
    143                     malloc32(usb_batch->setup_size + usb_batch->buffer_size);
     144                    malloc32(setup_size + usb_batch->buffer_size);
    144145                if (!ohci_batch->device_buffer) {
    145146                        usb_log_error("Failed to allocate device buffer");
    146                         goto dispose;
     147                        return ENOMEM;
    147148                }
    148149                /* Copy setup data */
    149                 memcpy(ohci_batch->device_buffer, usb_batch->setup_buffer,
    150                     usb_batch->setup_size);
     150                memcpy(ohci_batch->device_buffer, usb_batch->setup.buffer, setup_size);
    151151                /* Copy generic data */
    152152                if (usb_batch->ep->direction != USB_DIRECTION_IN)
    153153                        memcpy(
    154                             ohci_batch->device_buffer + usb_batch->setup_size,
     154                            ohci_batch->device_buffer + setup_size,
    155155                            usb_batch->buffer, usb_batch->buffer_size);
    156156        }
    157         ohci_batch->usb_batch = usb_batch;
    158 
    159         const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);
     157
    160158        assert(batch_setup[usb_batch->ep->transfer_type]);
    161         batch_setup[usb_batch->ep->transfer_type](ohci_batch, dir);
    162 
    163         return ohci_batch;
    164 dispose:
    165         ohci_transfer_batch_dispose(ohci_batch);
    166         return NULL;
     159        batch_setup[usb_batch->ep->transfer_type](ohci_batch);
     160
     161        return EOK;
    167162}
    168163
     
    176171 * completes with the last TD.
    177172 */
    178 bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *ohci_batch)
    179 {
    180         assert(ohci_batch);
    181         assert(ohci_batch->usb_batch);
     173bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *ohci_batch)
     174{
     175        assert(ohci_batch);
    182176
    183177        usb_log_debug("Batch %p checking %zu td(s) for completion.\n",
     
    194188
    195189        /* Assume all data got through */
    196         ohci_batch->usb_batch->transfered_size =
    197             ohci_batch->usb_batch->buffer_size;
     190        ohci_batch->base.transfered_size = ohci_batch->base.buffer_size;
    198191
    199192        /* Assume we will leave the last(unused) TD behind */
     
    207200                    ohci_batch->tds[i]->next, ohci_batch->tds[i]->be);
    208201
    209                 ohci_batch->usb_batch->error = td_error(ohci_batch->tds[i]);
    210                 if (ohci_batch->usb_batch->error == EOK) {
     202                ohci_batch->base.error = td_error(ohci_batch->tds[i]);
     203                if (ohci_batch->base.error == EOK) {
    211204                        /* If the TD got all its data through, it will report
    212205                         * 0 bytes remain, the sole exception is INPUT with
     
    221214                         * we leave the very last(unused) TD behind.
    222215                         */
    223                         ohci_batch->usb_batch->transfered_size
     216                        ohci_batch->base.transfered_size
    224217                            -= td_remain_size(ohci_batch->tds[i]);
    225218                } else {
     
    252245                }
    253246        }
    254         assert(ohci_batch->usb_batch->transfered_size <=
    255             ohci_batch->usb_batch->buffer_size);
     247        assert(ohci_batch->base.transfered_size <=
     248            ohci_batch->base.buffer_size);
     249
     250        if (ohci_batch->base.dir == USB_DIRECTION_IN)
     251                memcpy(ohci_batch->base.buffer, ohci_batch->device_buffer, ohci_batch->base.transfered_size);
    256252
    257253        /* Store the remaining TD */
    258         ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->usb_batch->ep);
     254        ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ohci_batch->base.ep);
    259255        assert(ohci_ep);
    260256        ohci_ep->td = ohci_batch->tds[leave_td];
     
    286282 * Status stage with toggle 1 and direction supplied by parameter.
    287283 */
    288 static void batch_control(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir)
    289 {
    290         assert(ohci_batch);
    291         assert(ohci_batch->usb_batch);
     284static void batch_control(ohci_transfer_batch_t *ohci_batch)
     285{
     286        assert(ohci_batch);
     287
     288        usb_direction_t dir = ohci_batch->base.dir;
    292289        assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
     290
    293291        usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
    294292            ohci_batch->ed->status, ohci_batch->ed->td_tail,
     
    307305        td_init(
    308306            ohci_batch->tds[0], ohci_batch->tds[1], USB_DIRECTION_BOTH,
    309             buffer, ohci_batch->usb_batch->setup_size, toggle);
     307            buffer, USB_SETUP_PACKET_SIZE, toggle);
    310308        usb_log_debug("Created CONTROL SETUP TD: %08x:%08x:%08x:%08x.\n",
    311309            ohci_batch->tds[0]->status, ohci_batch->tds[0]->cbp,
    312310            ohci_batch->tds[0]->next, ohci_batch->tds[0]->be);
    313         buffer += ohci_batch->usb_batch->setup_size;
     311        buffer += USB_SETUP_PACKET_SIZE;
    314312
    315313        /* Data stage */
     
    361359 * OHCI hw in ED.
    362360 */
    363 static void batch_data(ohci_transfer_batch_t *ohci_batch, usb_direction_t dir)
    364 {
    365         assert(ohci_batch);
    366         assert(ohci_batch->usb_batch);
     361static void batch_data(ohci_transfer_batch_t *ohci_batch)
     362{
     363        assert(ohci_batch);
     364
     365        usb_direction_t dir = ohci_batch->base.dir;
    367366        assert(dir == USB_DIRECTION_IN || dir == USB_DIRECTION_OUT);
    368367        usb_log_debug("Using ED(%p): %08x:%08x:%08x:%08x.\n", ohci_batch->ed,
     
    401400
    402401/** Transfer setup table. */
    403 static void (*const batch_setup[])(ohci_transfer_batch_t*, usb_direction_t) =
     402static void (*const batch_setup[])(ohci_transfer_batch_t*) =
    404403{
    405404        [USB_TRANSFER_CONTROL] = batch_control,
  • uspace/drv/bus/usb/ohci/ohci_batch.h

    r74b852b r5fd9c30  
    4545/** OHCI specific data required for USB transfer */
    4646typedef struct ohci_transfer_batch {
     47        usb_transfer_batch_t base;
     48
    4749        /** Link */
    4850        link_t link;
     
    5961} ohci_transfer_batch_t;
    6062
    61 ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *batch);
    62 bool ohci_transfer_batch_is_complete(const ohci_transfer_batch_t *batch);
     63ohci_transfer_batch_t * ohci_transfer_batch_create(endpoint_t *batch);
     64int ohci_transfer_batch_prepare(ohci_transfer_batch_t *ohci_batch);
    6365void ohci_transfer_batch_commit(const ohci_transfer_batch_t *batch);
    64 void ohci_transfer_batch_finish_dispose(ohci_transfer_batch_t *batch);
     66bool ohci_transfer_batch_check_completed(ohci_transfer_batch_t *batch);
     67void ohci_transfer_batch_destroy(ohci_transfer_batch_t *ohci_batch);
    6568
    6669static inline ohci_transfer_batch_t *ohci_transfer_batch_from_link(link_t *l)
     
    6972        return list_get_instance(l, ohci_transfer_batch_t, link);
    7073}
     74
     75static inline ohci_transfer_batch_t * ohci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
     76{
     77        assert(usb_batch);
     78
     79        return (ohci_transfer_batch_t *) usb_batch;
     80}
     81
    7182#endif
    7283/**
  • uspace/drv/bus/usb/ohci/ohci_bus.c

    r74b852b r5fd9c30  
    4040
    4141#include "ohci_bus.h"
     42#include "ohci_batch.h"
    4243#include "hc.h"
    4344
     
    141142        hc_dequeue_endpoint(bus->hc, ep);
    142143        return EOK;
     144}
    143145
     146static usb_transfer_batch_t *ohci_bus_create_batch(bus_t *bus, endpoint_t *ep)
     147{
     148        ohci_transfer_batch_t *batch = ohci_transfer_batch_create(ep);
     149        return &batch->base;
     150}
     151
     152static void ohci_bus_destroy_batch(usb_transfer_batch_t *batch)
     153{
     154        ohci_transfer_batch_destroy(ohci_transfer_batch_get(batch));
    144155}
    145156
     
    161172        ops->release_endpoint = ohci_release_ep;
    162173
     174        ops->create_batch = ohci_bus_create_batch;
     175        ops->destroy_batch = ohci_bus_destroy_batch;
     176
    163177        bus->hc = hc;
    164178
  • uspace/drv/bus/usb/ohci/ohci_rh.c

    r74b852b r5fd9c30  
    180180        const usb_target_t target = batch->ep->target;
    181181        batch->error = virthub_base_request(&instance->base, target,
    182             usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,
     182            batch->dir, &batch->setup.packet,
    183183            batch->buffer, batch->buffer_size, &batch->transfered_size);
    184184        if (batch->error == ENAK) {
     
    189189                instance->unfinished_interrupt_transfer = batch;
    190190        } else {
    191                 usb_transfer_batch_finish(batch, NULL);
    192                 usb_transfer_batch_destroy(batch);
     191                usb_transfer_batch_finish(batch);
    193192        }
    194193        return EOK;
     
    210209                const usb_target_t target = batch->ep->target;
    211210                batch->error = virthub_base_request(&instance->base, target,
    212                     usb_transfer_batch_direction(batch),
    213                     (void*)batch->setup_buffer,
     211                    batch->dir, &batch->setup.packet,
    214212                    batch->buffer, batch->buffer_size, &batch->transfered_size);
    215                 usb_transfer_batch_finish(batch, NULL);
    216                 usb_transfer_batch_destroy(batch);
     213                usb_transfer_batch_finish(batch);
    217214        }
    218215        return EOK;
  • uspace/drv/bus/usb/uhci/hc.c

    r74b852b r5fd9c30  
    177177                        uhci_transfer_batch_t *batch =
    178178                            uhci_transfer_batch_from_link(current);
    179                         uhci_transfer_batch_finish_dispose(batch);
     179                        usb_transfer_batch_finish(&batch->base);
    180180                }
    181181        }
     
    309309}
    310310
     311static usb_transfer_batch_t *create_transfer_batch(bus_t *bus, endpoint_t *ep)
     312{
     313        uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep);
     314        return &batch->base;
     315}
     316
     317static void destroy_transfer_batch(usb_transfer_batch_t *batch)
     318{
     319        uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch));
     320}
     321
    311322/** Initialize UHCI hc memory structures.
    312323 *
     
    326337        if ((err = usb2_bus_init(&instance->bus, BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11)))
    327338                return err;
     339
     340        instance->bus.base.ops.create_batch = create_transfer_batch;
     341        instance->bus.base.ops.destroy_batch = destroy_transfer_batch;
    328342
    329343        /* Init USB frame list page */
     
    450464                return uhci_rh_schedule(&instance->rh, batch);
    451465
    452         uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
     466        uhci_transfer_batch_t *uhci_batch = (uhci_transfer_batch_t *) batch;
    453467        if (!uhci_batch) {
    454468                usb_log_error("Failed to create UHCI transfer structures.\n");
    455469                return ENOMEM;
    456470        }
     471
     472        const int err = uhci_transfer_batch_prepare(uhci_batch);
     473        if (err)
     474                return err;
    457475
    458476        transfer_list_t *list =
  • uspace/drv/bus/usb/uhci/transfer_list.c

    r74b852b r5fd9c30  
    167167                    uhci_transfer_batch_from_link(current);
    168168
    169                 if (uhci_transfer_batch_is_complete(batch)) {
     169                if (uhci_transfer_batch_check_completed(batch)) {
    170170                        /* Save for processing */
    171171                        transfer_list_remove_batch(instance, batch);
  • uspace/drv/bus/usb/uhci/uhci_batch.c

    r74b852b r5fd9c30  
    5050#define DEFAULT_ERROR_COUNT 3
    5151
    52 /** Safely destructs uhci_transfer_batch_t structure.
     52/** Transfer batch setup table. */
     53static void (*const batch_setup[])(uhci_transfer_batch_t*);
     54
     55/** Destroys uhci_transfer_batch_t structure.
    5356 *
    5457 * @param[in] uhci_batch Instance to destroy.
    5558 */
    56 static void uhci_transfer_batch_dispose(uhci_transfer_batch_t *uhci_batch)
    57 {
    58         if (uhci_batch) {
    59                 usb_transfer_batch_destroy(uhci_batch->usb_batch);
    60                 free32(uhci_batch->device_buffer);
    61                 free(uhci_batch);
    62         }
    63 }
    64 
    65 /** Finishes usb_transfer_batch and destroys the structure.
    66  *
    67  * @param[in] uhci_batch Instance to finish and destroy.
    68  */
    69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch)
     59void uhci_transfer_batch_destroy(uhci_transfer_batch_t *uhci_batch)
    7060{
    7161        assert(uhci_batch);
    72         assert(uhci_batch->usb_batch);
    73         assert(!link_in_use(&uhci_batch->link));
    74         usb_transfer_batch_finish(uhci_batch->usb_batch,
    75             uhci_transfer_batch_data_buffer(uhci_batch));
    76         uhci_transfer_batch_dispose(uhci_batch);
    77 }
    78 
    79 /** Transfer batch setup table. */
    80 static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t);
     62        free32(uhci_batch->device_buffer);
     63        free(uhci_batch);
     64}
    8165
    8266/** Allocate memory and initialize internal data structure.
     
    8569 * @return Valid pointer if all structures were successfully created,
    8670 * NULL otherwise.
     71 */
     72uhci_transfer_batch_t * uhci_transfer_batch_create(endpoint_t *ep)
     73{
     74        uhci_transfer_batch_t *uhci_batch =
     75            calloc(1, sizeof(uhci_transfer_batch_t));
     76        if (!uhci_batch) {
     77                usb_log_error("Failed to allocate UHCI batch.\n");
     78                return NULL;
     79        }
     80
     81        usb_transfer_batch_init(&uhci_batch->base, ep);
     82
     83        link_initialize(&uhci_batch->link);
     84        return uhci_batch;
     85}
     86
     87/* Prepares batch for commiting.
    8788 *
    8889 * Determines the number of needed transfer descriptors (TDs).
     
    9091 * Initializes parameters needed for the transfer and callback.
    9192 */
    92 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *usb_batch)
     93int uhci_transfer_batch_prepare(uhci_transfer_batch_t *uhci_batch)
    9394{
    9495        static_assert((sizeof(td_t) % 16) == 0);
    95 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
    96         if (ptr == NULL) { \
    97                 usb_log_error(message); \
    98                 uhci_transfer_batch_dispose(uhci_batch); \
    99                 return NULL; \
    100         } else (void)0
    101 
    102         uhci_transfer_batch_t *uhci_batch =
    103             calloc(1, sizeof(uhci_transfer_batch_t));
    104         CHECK_NULL_DISPOSE_RETURN(uhci_batch,
    105             "Failed to allocate UHCI batch.\n");
    106         link_initialize(&uhci_batch->link);
    107         uhci_batch->td_count =
    108             (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1)
    109             / usb_batch->ep->max_packet_size;
     96
     97        usb_transfer_batch_t *usb_batch = &uhci_batch->base;
     98
     99        uhci_batch->td_count = (usb_batch->buffer_size + usb_batch->ep->max_packet_size - 1)
     100                / usb_batch->ep->max_packet_size;
     101
    110102        if (usb_batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
    111103                uhci_batch->td_count += 2;
    112104        }
    113105
     106        const size_t setup_size = (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
     107                ? USB_SETUP_PACKET_SIZE
     108                : 0;
     109
    114110        const size_t total_size = (sizeof(td_t) * uhci_batch->td_count)
    115             + sizeof(qh_t) + usb_batch->setup_size + usb_batch->buffer_size;
     111            + sizeof(qh_t) + setup_size + usb_batch->buffer_size;
    116112        uhci_batch->device_buffer = malloc32(total_size);
    117         CHECK_NULL_DISPOSE_RETURN(uhci_batch->device_buffer,
    118             "Failed to allocate UHCI buffer.\n");
     113        if (!uhci_batch->device_buffer) {
     114                usb_log_error("Failed to allocate UHCI buffer.\n");
     115                return ENOMEM;
     116        }
    119117        memset(uhci_batch->device_buffer, 0, total_size);
    120118
     
    130128            + sizeof(qh_t);
    131129        /* Copy SETUP packet data to the device buffer */
    132         memcpy(dest, usb_batch->setup_buffer, usb_batch->setup_size);
    133         dest += usb_batch->setup_size;
     130        memcpy(dest, usb_batch->setup.buffer, setup_size);
     131        dest += setup_size;
    134132        /* Copy generic data unless they are provided by the device */
    135133        if (usb_batch->ep->direction != USB_DIRECTION_IN) {
    136134                memcpy(dest, usb_batch->buffer, usb_batch->buffer_size);
    137135        }
    138         uhci_batch->usb_batch = usb_batch;
    139136        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
    140137            " memory structures ready.\n", usb_batch,
    141138            USB_TRANSFER_BATCH_ARGS(*usb_batch));
    142139
    143         const usb_direction_t dir = usb_transfer_batch_direction(usb_batch);
    144 
    145140        assert(batch_setup[usb_batch->ep->transfer_type]);
    146         batch_setup[usb_batch->ep->transfer_type](uhci_batch, dir);
    147 
    148         return uhci_batch;
     141        batch_setup[usb_batch->ep->transfer_type](uhci_batch);
     142
     143        return EOK;
    149144}
    150145
     
    158153 * is reached.
    159154 */
    160 bool uhci_transfer_batch_is_complete(const uhci_transfer_batch_t *uhci_batch)
     155bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *uhci_batch)
    161156{
    162157        assert(uhci_batch);
    163         assert(uhci_batch->usb_batch);
    164158
    165159        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT
     
    168162            USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch),
    169163            uhci_batch->td_count);
    170         uhci_batch->usb_batch->transfered_size = 0;
     164        uhci_batch->base.transfered_size = 0;
    171165
    172166        for (size_t i = 0;i < uhci_batch->td_count; ++i) {
     
    175169                }
    176170
    177                 uhci_batch->usb_batch->error = td_status(&uhci_batch->tds[i]);
    178                 if (uhci_batch->usb_batch->error != EOK) {
    179                         assert(uhci_batch->usb_batch->ep != NULL);
     171                uhci_batch->base.error = td_status(&uhci_batch->tds[i]);
     172                if (uhci_batch->base.error != EOK) {
     173                        assert(uhci_batch->base.ep != NULL);
    180174
    181175                        usb_log_debug("Batch %p found error TD(%zu->%p):%"
     
    184178                        td_print_status(&uhci_batch->tds[i]);
    185179
    186                         endpoint_toggle_set(uhci_batch->usb_batch->ep,
     180                        endpoint_toggle_set(uhci_batch->base.ep,
    187181                            td_toggle(&uhci_batch->tds[i]));
    188182                        if (i > 0)
     
    191185                }
    192186
    193                 uhci_batch->usb_batch->transfered_size
     187                uhci_batch->base.transfered_size
    194188                    += td_act_size(&uhci_batch->tds[i]);
    195189                if (td_is_short(&uhci_batch->tds[i]))
     
    197191        }
    198192substract_ret:
    199         uhci_batch->usb_batch->transfered_size
    200             -= uhci_batch->usb_batch->setup_size;
     193        if (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL)
     194                uhci_batch->base.transfered_size -= USB_SETUP_PACKET_SIZE;
    201195        return true;
    202196}
     
    216210 * The last transfer is marked with IOC flag.
    217211 */
    218 static void batch_data(uhci_transfer_batch_t *uhci_batch, usb_direction_t dir)
     212static void batch_data(uhci_transfer_batch_t *uhci_batch)
    219213{
    220214        assert(uhci_batch);
    221         assert(uhci_batch->usb_batch);
    222         assert(uhci_batch->usb_batch->ep);
     215
     216        usb_direction_t dir = uhci_batch->base.dir;
    223217        assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN);
    224218
     
    226220        const usb_packet_id pid = direction_pids[dir];
    227221        const bool low_speed =
    228             uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW;
    229         const size_t mps = uhci_batch->usb_batch->ep->max_packet_size;
    230         const usb_target_t target = uhci_batch->usb_batch->ep->target;
    231 
    232         int toggle = endpoint_toggle_get(uhci_batch->usb_batch->ep);
     222            uhci_batch->base.ep->speed == USB_SPEED_LOW;
     223        const size_t mps = uhci_batch->base.ep->max_packet_size;
     224        const usb_target_t target = uhci_batch->base.ep->target;
     225
     226        int toggle = endpoint_toggle_get(uhci_batch->base.ep);
    233227        assert(toggle == 0 || toggle == 1);
    234228
    235229        size_t td = 0;
    236         size_t remain_size = uhci_batch->usb_batch->buffer_size;
     230        size_t remain_size = uhci_batch->base.buffer_size;
    237231        char *buffer = uhci_transfer_batch_data_buffer(uhci_batch);
    238232
     
    254248        }
    255249        td_set_ioc(&uhci_batch->tds[td - 1]);
    256         endpoint_toggle_set(uhci_batch->usb_batch->ep, toggle);
     250        endpoint_toggle_set(uhci_batch->base.ep, toggle);
    257251        usb_log_debug2(
    258252            "Batch %p %s %s " USB_TRANSFER_BATCH_FMT " initialized.\n", \
    259253            uhci_batch->usb_batch,
    260             usb_str_transfer_type(uhci_batch->usb_batch->ep->transfer_type),
    261             usb_str_direction(uhci_batch->usb_batch->ep->direction),
     254            usb_str_transfer_type(uhci_batch->base.ep->transfer_type),
     255            usb_str_direction(uhci_batch->base.ep->direction),
    262256            USB_TRANSFER_BATCH_ARGS(*uhci_batch->usb_batch));
    263257}
     
    274268 * The last transfer is marked with IOC.
    275269 */
    276 static void batch_control(uhci_transfer_batch_t *uhci_batch, usb_direction_t dir)
     270static void batch_control(uhci_transfer_batch_t *uhci_batch)
    277271{
    278272        assert(uhci_batch);
    279         assert(uhci_batch->usb_batch);
    280         assert(uhci_batch->usb_batch->ep);
     273
     274        usb_direction_t dir = uhci_batch->base.dir;
    281275        assert(dir == USB_DIRECTION_OUT || dir == USB_DIRECTION_IN);
    282276        assert(uhci_batch->td_count >= 2);
     
    289283        const usb_packet_id status_stage_pid = status_stage_pids[dir];
    290284        const bool low_speed =
    291             uhci_batch->usb_batch->ep->speed == USB_SPEED_LOW;
    292         const size_t mps = uhci_batch->usb_batch->ep->max_packet_size;
    293         const usb_target_t target = uhci_batch->usb_batch->ep->target;
     285            uhci_batch->base.ep->speed == USB_SPEED_LOW;
     286        const size_t mps = uhci_batch->base.ep->max_packet_size;
     287        const usb_target_t target = uhci_batch->base.ep->target;
    294288
    295289        /* setup stage */
    296290        td_init(
    297291            &uhci_batch->tds[0], DEFAULT_ERROR_COUNT,
    298             uhci_batch->usb_batch->setup_size, 0, false,
     292            USB_SETUP_PACKET_SIZE, 0, false,
    299293            low_speed, target, USB_PID_SETUP,
    300294            uhci_transfer_batch_setup_buffer(uhci_batch), &uhci_batch->tds[1]);
     
    303297        size_t td = 1;
    304298        unsigned toggle = 1;
    305         size_t remain_size = uhci_batch->usb_batch->buffer_size;
     299        size_t remain_size = uhci_batch->base.buffer_size;
    306300        char *buffer = uhci_transfer_batch_data_buffer(uhci_batch);
    307301
     
    333327}
    334328
    335 static void (*const batch_setup[])(uhci_transfer_batch_t*, usb_direction_t) =
     329static void (*const batch_setup[])(uhci_transfer_batch_t*) =
    336330{
    337331        [USB_TRANSFER_CONTROL] = batch_control,
  • uspace/drv/bus/usb/uhci/uhci_batch.h

    r74b852b r5fd9c30  
    4343#include <stddef.h>
    4444#include <usb/host/usb_transfer_batch.h>
     45#include <usb/host/endpoint.h>
    4546
    4647#include "hw_struct/queue_head.h"
     
    4950/** UHCI specific data required for USB transfer */
    5051typedef struct uhci_transfer_batch {
     52        usb_transfer_batch_t base;
     53
    5154        /** Queue head
    5255         * This QH is used to maintain UHCI schedule structure and the element
     
    6669} uhci_transfer_batch_t;
    6770
    68 uhci_transfer_batch_t * uhci_transfer_batch_get(usb_transfer_batch_t *batch);
    69 void uhci_transfer_batch_finish_dispose(uhci_transfer_batch_t *uhci_batch);
    70 bool uhci_transfer_batch_is_complete(const uhci_transfer_batch_t *uhci_batch);
     71uhci_transfer_batch_t * uhci_transfer_batch_create(endpoint_t *ep);
     72int uhci_transfer_batch_prepare(uhci_transfer_batch_t *uhci_batch);
     73bool uhci_transfer_batch_check_completed(uhci_transfer_batch_t *uhci_batch);
     74void uhci_transfer_batch_destroy(uhci_transfer_batch_t *uhci_batch);
    7175
    7276/** Get offset to setup buffer accessible to the HC hw.
     
    9397        assert(uhci_batch->usb_batch);
    9498        return uhci_transfer_batch_setup_buffer(uhci_batch) +
    95             uhci_batch->usb_batch->setup_size;
     99            (uhci_batch->base.ep->transfer_type == USB_TRANSFER_CONTROL ? USB_SETUP_PACKET_SIZE : 0);
    96100}
    97101
     
    107111        uhci_batch->usb_batch->error = EINTR;
    108112        uhci_batch->usb_batch->transfered_size = 0;
    109         uhci_transfer_batch_finish_dispose(uhci_batch);
     113        usb_transfer_batch_finish(&uhci_batch->base);
    110114}
    111115
     
    120124}
    121125
     126static inline uhci_transfer_batch_t *uhci_transfer_batch_get(usb_transfer_batch_t *b)
     127{
     128        assert(b);
     129        return (uhci_transfer_batch_t *) b;
     130}
     131
    122132#endif
    123133
  • uspace/drv/bus/usb/uhci/uhci_rh.c

    r74b852b r5fd9c30  
    3939#include <usb/classes/hub.h>
    4040#include <usb/request.h>
     41#include <usb/host/endpoint.h>
    4142#include <usb/usb.h>
    4243
     
    106107        do {
    107108                batch->error = virthub_base_request(&instance->base, target,
    108                     usb_transfer_batch_direction(batch), (void*)batch->setup_buffer,
     109                    batch->dir, (void*) batch->setup.buffer,
    109110                    batch->buffer, batch->buffer_size, &batch->transfered_size);
    110111                if (batch->error == ENAK)
     
    113114                //ENAK is technically an error condition
    114115        } while (batch->error == ENAK);
    115         usb_transfer_batch_finish(batch, NULL);
    116         usb_transfer_batch_destroy(batch);
     116        usb_transfer_batch_finish(batch);
    117117        return EOK;
    118118}
  • uspace/drv/bus/usb/vhc/transfer.c

    r74b852b r5fd9c30  
    4444                return false;
    4545        }
    46         if (usb_transfer_batch_direction(transfer->batch) != USB_DIRECTION_OUT) {
    47                 return false;
    48         }
    49         const usb_device_request_setup_packet_t *setup =
    50             (void*)transfer->batch->setup_buffer;
     46        if (transfer->batch->dir != USB_DIRECTION_OUT) {
     47                return false;
     48        }
     49        const usb_device_request_setup_packet_t *setup
     50                = &transfer->batch->setup.packet;
    5151        if (setup->request_type != 0) {
    5252                return false;
     
    6363{
    6464        int rc;
    65        
    66         const usb_direction_t dir = usb_transfer_batch_direction(batch);
     65
     66        const usb_direction_t dir = batch->dir;
    6767
    6868        if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
    6969                if (dir == USB_DIRECTION_IN) {
    7070                        rc = usbvirt_control_read(dev,
    71                             batch->setup_buffer, batch->setup_size,
     71                            batch->setup.buffer, USB_SETUP_PACKET_SIZE,
    7272                            batch->buffer, batch->buffer_size,
    7373                            actual_data_size);
     
    7575                        assert(dir == USB_DIRECTION_OUT);
    7676                        rc = usbvirt_control_write(dev,
    77                             batch->setup_buffer, batch->setup_size,
     77                            batch->setup.buffer, USB_SETUP_PACKET_SIZE,
    7878                            batch->buffer, batch->buffer_size);
    7979                }
     
    100100        int rc;
    101101
    102         const usb_direction_t dir = usb_transfer_batch_direction(batch);
     102        const usb_direction_t dir = batch->dir;
    103103
    104104        if (batch->ep->transfer_type == USB_TRANSFER_CONTROL) {
    105105                if (dir == USB_DIRECTION_IN) {
    106106                        rc = usbvirt_ipc_send_control_read(sess,
    107                             batch->setup_buffer, batch->setup_size,
     107                            batch->setup.buffer, USB_SETUP_PACKET_SIZE,
    108108                            batch->buffer, batch->buffer_size,
    109109                            actual_data_size);
     
    111111                        assert(dir == USB_DIRECTION_OUT);
    112112                        rc = usbvirt_ipc_send_control_write(sess,
    113                             batch->setup_buffer, batch->setup_size,
     113                            batch->setup.buffer, USB_SETUP_PACKET_SIZE,
    114114                            batch->buffer, batch->buffer_size);
    115115                }
     
    149149        assert(transfer);
    150150        assert(transfer->batch);
    151         usb_transfer_batch_finish_error(transfer->batch, NULL,
    152             data_transfer_size, outcome);
    153         usb_transfer_batch_destroy(transfer->batch);
     151        transfer->batch->error = outcome;
     152        transfer->batch->transfered_size = data_transfer_size;
     153        usb_transfer_batch_finish(transfer->batch);
    154154        free(transfer);
    155155}
     
    236236                        if (is_set_address_transfer(transfer)) {
    237237                                usb_device_request_setup_packet_t *setup =
    238                                     (void*) transfer->batch->setup_buffer;
     238                                    (void*) transfer->batch->setup.buffer;
    239239                                dev->address = setup->value;
    240240                                usb_log_debug2("Address changed to %d\n",
  • uspace/drv/bus/usb/xhci/bus.c

    r74b852b r5fd9c30  
    4848#include "bus.h"
    4949#include "endpoint.h"
     50#include "transfers.h"
    5051
    5152/** Element of the hash table. */
     
    310311}
    311312
     313static usb_transfer_batch_t *create_batch(bus_t *bus, endpoint_t *ep)
     314{
     315        xhci_transfer_t *transfer = xhci_transfer_create(ep);
     316        return &transfer->batch;
     317}
     318
     319static void destroy_batch(usb_transfer_batch_t *batch)
     320{
     321        xhci_transfer_destroy(xhci_transfer_from_batch(batch));
     322}
     323
    312324static const bus_ops_t xhci_bus_ops = {
    313325        .enumerate_device = enumerate_device,
     
    329341        .endpoint_get_toggle = endpoint_get_toggle,
    330342        .endpoint_set_toggle = endpoint_set_toggle,
     343
     344        .create_batch = create_batch,
     345        .destroy_batch = destroy_batch,
    331346};
    332347
  • uspace/drv/bus/usb/xhci/hc.c

    r74b852b r5fd9c30  
    3737#include <str_error.h>
    3838#include <usb/debug.h>
     39#include <usb/host/endpoint.h>
    3940#include <usb/host/utils/malloc32.h>
    4041#include "debug.h"
     
    472473        }
    473474
    474         switch (batch->ep->transfer_type) {
    475         case USB_TRANSFER_CONTROL:
    476                 return xhci_schedule_control_transfer(hc, batch);
    477         case USB_TRANSFER_ISOCHRONOUS:
    478                 return xhci_schedule_isochronous_transfer(hc, batch);
    479         case USB_TRANSFER_BULK:
    480                 return xhci_schedule_bulk_transfer(hc, batch);
    481         case USB_TRANSFER_INTERRUPT:
    482                 return xhci_schedule_interrupt_transfer(hc, batch);
    483         }
    484 
    485         return EOK;
     475        return xhci_transfer_schedule(hc, batch);
    486476}
    487477
  • uspace/drv/bus/usb/xhci/main.c

    r74b852b r5fd9c30  
    186186{
    187187        log_init(NAME);
    188         logctl_set_log_level(NAME, LVL_DEBUG);
     188        logctl_set_log_level(NAME, LVL_DEBUG2);
    189189        return ddf_driver_main(&xhci_driver);
    190190}
  • uspace/drv/bus/usb/xhci/transfers.c

    r74b852b r5fd9c30  
    108108}
    109109
    110 xhci_transfer_t* xhci_transfer_alloc(usb_transfer_batch_t* batch) {
    111         xhci_transfer_t* transfer = malloc(sizeof(xhci_transfer_t));
     110xhci_transfer_t* xhci_transfer_create(endpoint_t* ep) {
     111        xhci_transfer_t* transfer = calloc(1, sizeof(xhci_transfer_t));
    112112        if (!transfer)
    113113                return NULL;
    114114
    115         memset(transfer, 0, sizeof(xhci_transfer_t));
    116         transfer->batch = batch;
     115        usb_transfer_batch_init(&transfer->batch, ep);
     116
    117117        link_initialize(&transfer->link);
    118         transfer->hc_buffer = batch->buffer_size > 0 ? malloc32(batch->buffer_size) : NULL;
    119118
    120119        return transfer;
    121120}
    122121
    123 void xhci_transfer_fini(xhci_transfer_t* transfer) {
    124         if (transfer) {
    125                 if (transfer->batch->buffer_size > 0)
    126                         free32(transfer->hc_buffer);
    127 
    128                 usb_transfer_batch_destroy(transfer->batch);
    129 
    130                 free(transfer);
    131         }
    132 }
    133 
    134 int xhci_schedule_control_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch)
    135 {
    136         if (!batch->setup_size) {
    137                 usb_log_error("Missing setup packet for the control transfer.");
    138                 return EINVAL;
    139         }
    140         if (batch->ep->transfer_type != USB_TRANSFER_CONTROL) {
    141                 /* This method only works for control transfers. */
    142                 usb_log_error("Attempted to schedule a control transfer to non control endpoint.");
    143                 return EINVAL;
    144         }
    145 
    146         usb_device_request_setup_packet_t* setup =
    147                 (usb_device_request_setup_packet_t*) batch->setup_buffer;
    148 
    149         /* For the TRB formats, see xHCI specification 6.4.1.2 */
    150         xhci_transfer_t *transfer = xhci_transfer_alloc(batch);
    151 
    152         if (!transfer->direction) {
    153                 // Sending stuff from host to device, we need to copy the actual data.
    154                 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size);
    155         }
    156 
    157         xhci_trb_t trbs[3];
    158         int trbs_used = 0;
     122void xhci_transfer_destroy(xhci_transfer_t* transfer)
     123{
     124        assert(transfer);
     125
     126        if (transfer->hc_buffer)
     127                free32(transfer->hc_buffer);
     128
     129        free(transfer);
     130}
     131
     132static xhci_trb_ring_t *get_ring(xhci_hc_t *hc, xhci_transfer_t *transfer)
     133{
     134        xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep);
     135        uint8_t slot_id = xhci_ep->device->slot_id;
     136
     137        xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[transfer->batch.ep->target.endpoint];
     138        assert(ring);
     139        return ring;
     140}
     141
     142static int schedule_control(xhci_hc_t* hc, xhci_transfer_t* transfer)
     143{
     144        usb_transfer_batch_t *batch = &transfer->batch;
     145        xhci_trb_ring_t *ring = get_ring(hc, transfer);
     146        xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep);
     147
     148        usb_device_request_setup_packet_t* setup = &batch->setup.packet;
     149
     150        xhci_trb_t trbs[3];
     151        int trbs_used = 0;
    159152
    160153        xhci_trb_t *trb_setup = trbs + trbs_used++;
     
    178171        xhci_trb_t *trb_data = NULL;
    179172        if (setup->length > 0) {
    180                 trb_data = trbs + trbs_used++;
    181                 xhci_trb_clean(trb_data);
     173                trb_data = trbs + trbs_used++;
     174                xhci_trb_clean(trb_data);
    182175
    183176                trb_data->parameter = addr_to_phys(transfer->hc_buffer);
     
    191184                TRB_CTRL_SET_TRB_TYPE(*trb_data, XHCI_TRB_TYPE_DATA_STAGE);
    192185
    193                 transfer->direction = REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type)
     186                int stage_dir = REQUEST_TYPE_IS_DEVICE_TO_HOST(setup->request_type)
    194187                                        ? STAGE_IN : STAGE_OUT;
    195                 TRB_CTRL_SET_DIR(*trb_data, transfer->direction);
     188                TRB_CTRL_SET_DIR(*trb_data, stage_dir);
    196189        }
    197190
     
    207200        TRB_CTRL_SET_DIR(*trb_status, get_status_direction_flag(trb_setup, setup->request_type, setup->length));
    208201
    209         xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep);
    210         uint8_t slot_id = xhci_ep->device->slot_id;
    211         xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint];
    212 
    213         int err = xhci_trb_ring_enqueue_multiple(ring, trbs, trbs_used, &transfer->interrupt_trb_phys);
    214         if (err != EOK)
    215                 return err;
    216 
    217         list_append(&transfer->link, &hc->transfers);
    218 
    219202        // Issue a Configure Endpoint command, if needed.
    220203        if (configure_endpoint_needed(setup)) {
    221                 // TODO: figure out the best time to issue this command
    222                 // FIXME: on fail, we need to "cancel" in-flight TRBs and remove transfer from the list
    223                 err = xhci_device_configure(xhci_ep->device, hc);
    224                 if (err != EOK)
    225                         return err;
    226         }
    227 
    228         const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbels start at 1 */
    229         return hc_ring_doorbell(hc, slot_id, target);
    230 }
    231 
    232 int xhci_schedule_bulk_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch)
    233 {
    234         if (batch->setup_size) {
    235                 usb_log_warning("Setup packet present for a bulk transfer. Ignored.");
    236         }
    237         if (batch->ep->transfer_type != USB_TRANSFER_BULK) {
    238                 /* This method only works for bulk transfers. */
    239                 usb_log_error("Attempted to schedule a bulk transfer to non bulk endpoint.");
    240                 return EINVAL;
    241         }
    242 
    243         xhci_transfer_t *transfer = xhci_transfer_alloc(batch);
    244         if (!transfer->direction) {
    245                 // Sending stuff from host to device, we need to copy the actual data.
    246                 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size);
    247         }
    248 
     204                const int err = xhci_device_configure(xhci_ep->device, hc);
     205                if (err)
     206                        return err;
     207        }
     208
     209        return xhci_trb_ring_enqueue_multiple(ring, trbs, trbs_used, &transfer->interrupt_trb_phys);
     210}
     211
     212static int schedule_bulk(xhci_hc_t* hc, xhci_transfer_t *transfer)
     213{
    249214        xhci_trb_t trb;
    250215        xhci_trb_clean(&trb);
     
    252217
    253218        // data size (sent for OUT, or buffer size)
    254         TRB_CTRL_SET_XFER_LEN(trb, batch->buffer_size);
     219        TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size);
    255220        // FIXME: TD size 4.11.2.4
    256221        TRB_CTRL_SET_TD_SIZE(trb, 1);
     
    261226        TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
    262227
    263         xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep);
     228        xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep);
    264229        uint8_t slot_id = xhci_ep->device->slot_id;
    265         xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint];
    266 
    267         xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
    268         list_append(&transfer->link, &hc->transfers);
    269 
    270         // TODO: target = endpoint | stream_id << 16
    271         const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */
    272         return hc_ring_doorbell(hc, slot_id, target);
    273 }
    274 
    275 int xhci_schedule_interrupt_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch)
    276 {
    277         if (batch->setup_size) {
    278                 usb_log_warning("Setup packet present for a interrupt transfer. Ignored.");
    279         }
    280         if (batch->ep->transfer_type != USB_TRANSFER_INTERRUPT) {
    281                 /* This method only works for interrupt transfers. */
    282                 usb_log_error("Attempted to schedule a interrupt transfer to non interrupt endpoint.");
    283                 return EINVAL;
    284         }
    285 
    286         xhci_transfer_t *transfer = xhci_transfer_alloc(batch);
    287         if (!transfer->direction) {
    288                 // Sending stuff from host to device, we need to copy the actual data.
    289                 memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size);
    290         }
    291 
     230        xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[transfer->batch.ep->target.endpoint];
     231
     232        return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     233}
     234
     235static int schedule_interrupt(xhci_hc_t* hc, xhci_transfer_t* transfer)
     236{
    292237        xhci_trb_t trb;
    293238        xhci_trb_clean(&trb);
     
    295240
    296241        // data size (sent for OUT, or buffer size)
    297         TRB_CTRL_SET_XFER_LEN(trb, batch->buffer_size);
     242        TRB_CTRL_SET_XFER_LEN(trb, transfer->batch.buffer_size);
    298243        // FIXME: TD size 4.11.2.4
    299244        TRB_CTRL_SET_TD_SIZE(trb, 1);
     
    304249        TRB_CTRL_SET_TRB_TYPE(trb, XHCI_TRB_TYPE_NORMAL);
    305250
    306         xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep);
     251        xhci_endpoint_t *xhci_ep = xhci_endpoint_get(transfer->batch.ep);
    307252        uint8_t slot_id = xhci_ep->device->slot_id;
    308         xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[batch->ep->target.endpoint];
    309 
    310         xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
    311         list_append(&transfer->link, &hc->transfers);
    312 
    313         const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */
    314         return hc_ring_doorbell(hc, slot_id, target);
    315 }
    316 
    317 int xhci_schedule_isochronous_transfer(xhci_hc_t* hc, usb_transfer_batch_t* batch)
    318 {
    319         if (batch->setup_size) {
    320                 usb_log_warning("Setup packet present for a isochronous transfer. Ignored.");
    321         }
    322         if (batch->ep->transfer_type != USB_TRANSFER_ISOCHRONOUS) {
    323                 /* This method only works for isochronous transfers. */
    324                 usb_log_error("Attempted to schedule a isochronous transfer to non isochronous endpoint.");
    325                 return EINVAL;
    326         }
    327 
    328         /* TODO: Implement me. */
    329         usb_log_error("Isochronous transfers are not yet implemented!");
    330         return ENOTSUP;
     253        xhci_trb_ring_t* ring = hc->dcbaa_virt[slot_id].trs[transfer->batch.ep->target.endpoint];
     254
     255        return xhci_trb_ring_enqueue(ring, &trb, &transfer->interrupt_trb_phys);
     256}
     257
     258static int schedule_isochronous(xhci_hc_t* hc, xhci_transfer_t* transfer)
     259{
     260        /* TODO: Implement me. */
     261        usb_log_error("Isochronous transfers are not yet implemented!");
     262        return ENOTSUP;
    331263}
    332264
     
    352284
    353285        list_remove(transfer_link);
    354         usb_transfer_batch_t *batch = transfer->batch;
    355 
    356         const int err = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK;
    357         const size_t size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb);
    358         usb_transfer_batch_finish_error(batch, transfer->hc_buffer, size, err);
    359         xhci_transfer_fini(transfer);
     286        usb_transfer_batch_t *batch = &transfer->batch;
     287
     288        batch->error = (TRB_COMPLETION_CODE(*trb) == XHCI_TRBC_SUCCESS) ? EOK : ENAK;
     289        batch->transfered_size = batch->buffer_size - TRB_TRANSFER_LENGTH(*trb);
     290
     291        if (batch->dir == USB_DIRECTION_IN) {
     292                assert(batch->buffer);
     293                assert(batch->transfered_size <= batch->buffer_size);
     294                memcpy(batch->buffer, transfer->hc_buffer, batch->transfered_size);
     295        }
     296
     297        usb_transfer_batch_finish(batch);
    360298        return EOK;
    361299}
     300
     301typedef int (*transfer_handler)(xhci_hc_t *, xhci_transfer_t *);
     302
     303static const transfer_handler transfer_handlers[] = {
     304        [USB_TRANSFER_CONTROL] = schedule_control,
     305        [USB_TRANSFER_ISOCHRONOUS] = schedule_isochronous,
     306        [USB_TRANSFER_BULK] = schedule_bulk,
     307        [USB_TRANSFER_INTERRUPT] = schedule_interrupt,
     308};
     309
     310int xhci_transfer_schedule(xhci_hc_t *hc, usb_transfer_batch_t *batch)
     311{
     312        assert(hc);
     313
     314        xhci_transfer_t *transfer = xhci_transfer_from_batch(batch);
     315        xhci_endpoint_t *xhci_ep = xhci_endpoint_get(batch->ep);
     316        uint8_t slot_id = xhci_ep->device->slot_id;
     317
     318        assert(xhci_ep);
     319        assert(slot_id);
     320
     321        const usb_transfer_type_t type = batch->ep->transfer_type;
     322        assert(type >= 0 && type < ARRAY_SIZE(transfer_handlers));
     323        assert(transfer_handlers[type]);
     324
     325        if (batch->buffer_size > 0) {
     326                transfer->hc_buffer = malloc32(batch->buffer_size);
     327        }
     328
     329        if (batch->dir != USB_DIRECTION_IN) {
     330                // Sending stuff from host to device, we need to copy the actual data.
     331                memcpy(transfer->hc_buffer, batch->buffer, batch->buffer_size);
     332        }
     333
     334        const int err = transfer_handlers[batch->ep->transfer_type](hc, transfer);
     335        if (err)
     336                return err;
     337
     338        list_append(&transfer->link, &hc->transfers);
     339
     340        const uint8_t target = xhci_endpoint_index(xhci_ep) + 1; /* EP Doorbells start at 1 */
     341        return hc_ring_doorbell(hc, slot_id, target);
     342}
  • uspace/drv/bus/usb/xhci/transfers.h

    r74b852b r5fd9c30  
    3434 */
    3535
     36#ifndef XHCI_TRANSFERS_H
     37#define XHCI_TRANSFERS_H
     38
     39#include <usb/host/usb_transfer_batch.h>
     40
    3641#include "hc.h"
    3742#include "trb_ring.h"
    3843
    3944typedef struct {
     45        usb_transfer_batch_t batch;
    4046        link_t link;
    4147
    42         uintptr_t interrupt_trb_phys;
    4348        uint8_t direction;
    4449
    45         usb_transfer_batch_t* batch;
     50        void* hc_buffer;                    /* Virtual address of the buffer start. */
     51        uintptr_t hc_buffer_phys;
    4652
    47         void* hc_buffer;                    /* Virtual address of the buffer start. */
     53        uintptr_t interrupt_trb_phys;
    4854} xhci_transfer_t;
    4955
     
    5157void xhci_fini_transfers(xhci_hc_t*);
    5258
    53 xhci_transfer_t* xhci_transfer_alloc(usb_transfer_batch_t*);
    54 void xhci_transfer_fini(xhci_transfer_t*);
     59xhci_transfer_t* xhci_transfer_create(endpoint_t *);
     60int xhci_transfer_schedule(xhci_hc_t*, usb_transfer_batch_t *);
     61int xhci_handle_transfer_event(xhci_hc_t*, xhci_trb_t*);
     62void xhci_transfer_destroy(xhci_transfer_t*);
    5563
    56 int xhci_handle_transfer_event(xhci_hc_t*, xhci_trb_t*);
     64static inline xhci_transfer_t *xhci_transfer_from_batch(usb_transfer_batch_t *batch)
     65{
     66        assert(batch);
     67        return (xhci_transfer_t *) batch;
     68}
    5769
    58 int xhci_schedule_control_transfer(xhci_hc_t*, usb_transfer_batch_t*);
    59 int xhci_schedule_bulk_transfer(xhci_hc_t*, usb_transfer_batch_t*);
    60 int xhci_schedule_interrupt_transfer(xhci_hc_t*, usb_transfer_batch_t*);
    61 int xhci_schedule_isochronous_transfer(xhci_hc_t* , usb_transfer_batch_t* );
     70/**
     71 * @}
     72 */
     73#endif
  • uspace/lib/usb/include/usb/request.h

    r74b852b r5fd9c30  
    109109int assert[(sizeof(usb_device_request_setup_packet_t) == 8) ? 1: -1];
    110110
    111 int usb_request_needs_toggle_reset(
     111/** How much toggles needs to be reset */
     112typedef enum {
     113        RESET_NONE,
     114        RESET_EP,
     115        RESET_ALL
     116} toggle_reset_mode_t;
     117
     118toggle_reset_mode_t usb_request_get_toggle_reset_mode(
    112119    const usb_device_request_setup_packet_t *request);
    113120
  • uspace/lib/usb/src/usb.c

    r74b852b r5fd9c30  
    128128 *
    129129 */
    130 int usb_request_needs_toggle_reset(
     130toggle_reset_mode_t usb_request_get_toggle_reset_mode(
    131131    const usb_device_request_setup_packet_t *request)
    132132{
     
    139139                if ((request->request_type == 0x2) &&
    140140                    (request->value == USB_FEATURE_ENDPOINT_HALT))
    141                         return uint16_usb2host(request->index);
     141                        return RESET_EP;
    142142                break;
    143143        case USB_DEVREQ_SET_CONFIGURATION:
     
    149149                 * interface of an already setup device. */
    150150                if (!(request->request_type & SETUP_REQUEST_TYPE_DEVICE_TO_HOST))
    151                         return 0;
     151                        return RESET_ALL;
    152152                break;
    153153        default:
    154154                break;
    155155        }
    156         return -1;
     156
     157        return RESET_NONE;
    157158}
    158159
  • uspace/lib/usbhost/include/usb/host/bus.h

    r74b852b r5fd9c30  
    3333 *
    3434 * The purpose of this structure is to keep information about connected devices
    35  * and enpoints, manage available bandwidth and the toggle bit flipping.
     35 * and endpoints, manage available bandwidth and the toggle bit flipping.
    3636 *
    3737 * The generic implementation is provided for USB 1 and 2 in usb2_bus.c. Some
     
    5353typedef struct bus bus_t;
    5454typedef struct ddf_fun ddf_fun_t;
     55typedef struct usb_transfer_batch usb_transfer_batch_t;
    5556
    5657typedef struct device {
     
    8586        int (*release_endpoint)(bus_t *, endpoint_t *);
    8687        endpoint_t *(*find_endpoint)(bus_t *, usb_target_t, usb_direction_t);
     88        void (*destroy_endpoint)(endpoint_t *);                 /**< Optional */
     89        bool (*endpoint_get_toggle)(endpoint_t *);              /**< Optional */
     90        void (*endpoint_set_toggle)(endpoint_t *, bool);        /**< Optional */
    8791
    8892        int (*request_address)(bus_t *, usb_address_t*, bool, usb_speed_t);
     
    9397        size_t (*count_bw) (endpoint_t *, size_t);
    9498
    95         /* Endpoint ops, optional (have generic fallback) */
    96         void (*destroy_endpoint)(endpoint_t *);
    97         bool (*endpoint_get_toggle)(endpoint_t *);
    98         void (*endpoint_set_toggle)(endpoint_t *, bool);
     99        usb_transfer_batch_t *(*create_batch)(bus_t *, endpoint_t *); /**< Optional */
     100        void (*destroy_batch)(usb_transfer_batch_t *);  /**< Optional */
    99101} bus_ops_t;
    100102
     
    135137int bus_release_address(bus_t *, usb_address_t);
    136138
     139
    137140static inline int bus_reserve_default_address(bus_t *bus, usb_speed_t speed) {
    138141        usb_address_t addr = USB_ADDRESS_DEFAULT;
  • uspace/lib/usbhost/include/usb/host/endpoint.h

    r74b852b r5fd9c30  
    4848typedef struct bus bus_t;
    4949typedef struct device device_t;
     50typedef struct usb_transfer_batch usb_transfer_batch_t;
    5051
    5152/** Host controller side endpoint structure. */
  • uspace/lib/usbhost/include/usb/host/usb_transfer_batch.h

    r74b852b r5fd9c30  
    3737#define LIBUSBHOST_HOST_USB_TRANSFER_BATCH_H
    3838
    39 #include <usb/host/endpoint.h>
    4039#include <usb/usb.h>
     40#include <usb/request.h>
    4141
    42 #include <assert.h>
    4342#include <stddef.h>
    4443#include <stdint.h>
     
    4746#define USB_SETUP_PACKET_SIZE 8
    4847
     48typedef struct endpoint endpoint_t;
     49typedef struct bus bus_t;
     50typedef struct usb_transfer_batch usb_transfer_batch_t;
     51
     52/** Callback to be called on transfer. */
     53typedef int (*usb_transfer_batch_callback_t)(usb_transfer_batch_t *);
     54
    4955/** Structure stores additional data needed for communication with EP */
    5056typedef struct usb_transfer_batch {
    5157        /** Endpoint used for communication */
    5258        endpoint_t *ep;
    53         /** Function called on completion (IN version) */
    54         usbhc_iface_transfer_in_callback_t callback_in;
    55         /** Function called on completion (OUT version) */
    56         usbhc_iface_transfer_out_callback_t callback_out;
    57         /** Argument to pass to the completion function */
    58         void *arg;
     59        /** Size reported to be sent */
     60        size_t expected_size;
     61
     62        /** Direction of the transfer */
     63        usb_direction_t dir;
     64
     65        /** Function called on completion */
     66        usb_transfer_batch_callback_t on_complete;
     67        /** Arbitrary data for the handler */
     68        void *on_complete_data;
     69
     70        /** Place to store SETUP data needed by control transfers */
     71        union {
     72                char buffer [USB_SETUP_PACKET_SIZE];
     73                usb_device_request_setup_packet_t packet;
     74                uint64_t packed;
     75        } setup;
     76
     77        /** Resetting the Toggle */
     78        toggle_reset_mode_t toggle_reset_mode;
     79
    5980        /** Place for data to send/receive */
    6081        char *buffer;
    6182        /** Size of memory pointed to by buffer member */
    6283        size_t buffer_size;
    63         /** Place to store SETUP data needed by control transfers */
    64         char setup_buffer[USB_SETUP_PACKET_SIZE];
    65         /** Used portion of setup_buffer member
    66          *
    67          * SETUP buffer must be 8 bytes for control transfers and is left
    68          * unused for all other transfers. Thus, this field is either 0 or 8.
    69          */
    70         size_t setup_size;
    7184
    72         /** Actually used portion of the buffer
    73          * This member is never accessed by functions provided in this header,
    74          * with the exception of usb_transfer_batch_finish. For external use.
    75          */
     85        /** Actually used portion of the buffer */
    7686        size_t transfered_size;
    77         /** Indicates success/failure of the communication
    78          * This member is never accessed by functions provided in this header,
    79          * with the exception of usb_transfer_batch_finish. For external use.
    80          */
     87        /** Indicates success/failure of the communication */
    8188        int error;
    8289} usb_transfer_batch_t;
     
    95102        (batch).buffer_size, (batch).ep->max_packet_size
    96103
     104void usb_transfer_batch_init(usb_transfer_batch_t *, endpoint_t *);
     105void usb_transfer_batch_finish(usb_transfer_batch_t *);
    97106
    98 usb_transfer_batch_t * usb_transfer_batch_create(
    99     endpoint_t *ep,
    100     char *buffer,
    101     size_t buffer_size,
    102     uint64_t setup_buffer,
    103     usbhc_iface_transfer_in_callback_t func_in,
    104     usbhc_iface_transfer_out_callback_t func_out,
    105     void *arg
    106 );
    107 void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance);
     107usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *);
     108void usb_transfer_batch_destroy(usb_transfer_batch_t *);
    108109
    109 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance,
    110     const void* data, size_t size, int error);
    111 
    112 /** Finish batch using stored error value and transferred size.
    113  *
    114  * @param[in] instance Batch structure to use.
    115  * @param[in] data Data to copy to the output buffer.
     110/** Provided to ease the transition. Wraps old-style handlers into a new one.
    116111 */
    117 static inline void usb_transfer_batch_finish(
    118     const usb_transfer_batch_t *instance, const void* data)
    119 {
    120         assert(instance);
    121         usb_transfer_batch_finish_error(
    122             instance, data, instance->transfered_size, instance->error);
    123 }
    124 
    125 /** Determine batch direction based on the callbacks present
    126  * @param[in] instance Batch structure to use, non-null.
    127  * @return USB_DIRECTION_IN, or USB_DIRECTION_OUT.
    128  */
    129 static inline usb_direction_t usb_transfer_batch_direction(
    130     const usb_transfer_batch_t *instance)
    131 {
    132         assert(instance);
    133         if (instance->callback_in) {
    134                 assert(instance->callback_out == NULL);
    135                 assert(instance->ep == NULL
    136                     || instance->ep->transfer_type == USB_TRANSFER_CONTROL
    137                     || instance->ep->direction == USB_DIRECTION_IN);
    138                 return USB_DIRECTION_IN;
    139         }
    140         if (instance->callback_out) {
    141                 assert(instance->callback_in == NULL);
    142                 assert(instance->ep == NULL
    143                     || instance->ep->transfer_type == USB_TRANSFER_CONTROL
    144                     || instance->ep->direction == USB_DIRECTION_OUT);
    145                 return USB_DIRECTION_OUT;
    146         }
    147         assert(false);
    148 }
     112extern void usb_transfer_batch_set_old_handlers(usb_transfer_batch_t *,
     113        usbhc_iface_transfer_in_callback_t,
     114        usbhc_iface_transfer_out_callback_t, void *);
    149115
    150116#endif
  • uspace/lib/usbhost/src/hcd.c

    r74b852b r5fd9c30  
    6969}
    7070
    71 typedef struct {
    72         void *original_data;
    73         usbhc_iface_transfer_out_callback_t original_callback;
    74         usb_target_t target;
    75         hcd_t *hcd;
    76 } toggle_t;
    77 
    78 static void toggle_reset_callback(int retval, void *arg)
    79 {
    80         assert(arg);
    81         toggle_t *toggle = arg;
    82         if (retval == EOK) {
    83                 usb_log_debug2("Reseting toggle on %d:%d.\n",
    84                     toggle->target.address, toggle->target.endpoint);
    85                 bus_reset_toggle(toggle->hcd->bus,
    86                     toggle->target, toggle->target.endpoint == 0);
    87         }
    88 
    89         toggle->original_callback(retval, toggle->original_data);
    90 }
    91 
    9271/** Prepare generic usb_transfer_batch and schedule it.
    9372 * @param hcd Host controller driver.
    94  * @param fun DDF fun
    9573 * @param target address and endpoint number.
    9674 * @param setup_data Data to use in setup stage (Control communication type)
     
    10179 * @return Error code.
    10280 */
    103 int hcd_send_batch(
    104     hcd_t *hcd, usb_target_t target, usb_direction_t direction,
    105     void *data, size_t size, uint64_t setup_data,
    106     usbhc_iface_transfer_in_callback_t in,
    107     usbhc_iface_transfer_out_callback_t out, void *arg, const char* name)
     81int hcd_send_batch(hcd_t *hcd, usb_target_t target, usb_direction_t direction,
     82        void *data, size_t size, uint64_t setup_data,
     83        usbhc_iface_transfer_in_callback_t in, usbhc_iface_transfer_out_callback_t out,
     84        void *arg, const char *name)
    10885{
    10986        assert(hcd);
     
    132109        }
    133110
    134         /* Check for commands that reset toggle bit */
    135         if (ep->transfer_type == USB_TRANSFER_CONTROL) {
    136                 const int reset_toggle = usb_request_needs_toggle_reset(
    137                     (usb_device_request_setup_packet_t *) &setup_data);
    138                 if (reset_toggle >= 0) {
    139                         assert(out);
    140                         toggle_t *toggle = malloc(sizeof(toggle_t));
    141                         if (!toggle)
    142                                 return ENOMEM;
    143                         toggle->target.address = target.address;
    144                         toggle->target.endpoint = reset_toggle;
    145                         toggle->original_callback = out;
    146                         toggle->original_data = arg;
    147                         toggle->hcd = hcd;
    148 
    149                         arg = toggle;
    150                         out = toggle_reset_callback;
    151                 }
    152         }
    153 
    154         usb_transfer_batch_t *batch = usb_transfer_batch_create(
    155             ep, data, size, setup_data, in, out, arg);
     111        usb_transfer_batch_t *batch = usb_transfer_batch_create(ep);
    156112        if (!batch) {
    157113                usb_log_error("Failed to create transfer batch.\n");
    158114                return ENOMEM;
    159115        }
     116
     117        batch->buffer = data;
     118        batch->buffer_size = size;
     119        batch->setup.packed = setup_data;
     120        batch->dir = direction;
     121
     122        /* Check for commands that reset toggle bit */
     123        if (ep->transfer_type == USB_TRANSFER_CONTROL)
     124                batch->toggle_reset_mode
     125                        = usb_request_get_toggle_reset_mode(&batch->setup.packet);
     126
     127        usb_transfer_batch_set_old_handlers(batch, in, out, arg);
    160128
    161129        const int ret = hcd->ops.schedule(hcd, batch);
  • uspace/lib/usbhost/src/usb_transfer_batch.c

    r74b852b r5fd9c30  
    3434
    3535#include <usb/host/usb_transfer_batch.h>
     36#include <usb/host/endpoint.h>
     37#include <usb/host/bus.h>
    3638#include <usb/debug.h>
    3739
    3840#include <assert.h>
    3941#include <errno.h>
    40 #include <macros.h>
    41 #include <mem.h>
    42 #include <stdlib.h>
    43 #include <usbhc_iface.h>
    4442
    45 /** Allocate and initialize usb_transfer_batch structure.
    46  * @param ep endpoint used by the transfer batch.
    47  * @param buffer data to send/recieve.
    48  * @param buffer_size Size of data buffer.
    49  * @param setup_buffer Data to send in SETUP stage of control transfer.
    50  * @param func_in callback on IN transfer completion.
    51  * @param func_out callback on OUT transfer completion.
    52  * @param fun DDF function (passed to callback function).
    53  * @param arg Argument to pass to the callback function.
    54  * @param private_data driver specific per batch data.
    55  * @param private_data_dtor Function to properly destroy private_data.
    56  * @return Pointer to valid usb_transfer_batch_t structure, NULL on failure.
     43
     44/** Create a batch on given endpoint.
    5745 */
    58 usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep, char *buffer,
    59     size_t buffer_size,
    60     uint64_t setup_buffer,
    61     usbhc_iface_transfer_in_callback_t func_in,
    62     usbhc_iface_transfer_out_callback_t func_out,
    63     void *arg)
     46usb_transfer_batch_t *usb_transfer_batch_create(endpoint_t *ep)
    6447{
    65         if (func_in == NULL && func_out == NULL)
    66                 return NULL;
    67         if (func_in != NULL && func_out != NULL)
    68                 return NULL;
     48        assert(ep);
     49        assert(ep->bus);
    6950
    70         usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
    71         if (instance) {
    72                 instance->ep = ep;
    73                 instance->callback_in = func_in;
    74                 instance->callback_out = func_out;
    75                 instance->arg = arg;
    76                 instance->buffer = buffer;
    77                 instance->buffer_size = buffer_size;
    78                 instance->setup_size = 0;
    79                 instance->transfered_size = 0;
    80                 instance->error = EOK;
    81                 if (ep && ep->transfer_type == USB_TRANSFER_CONTROL) {
    82                         memcpy(instance->setup_buffer, &setup_buffer,
    83                             USB_SETUP_PACKET_SIZE);
    84                         instance->setup_size = USB_SETUP_PACKET_SIZE;
    85                 }
    86                 if (instance->ep)
    87                         endpoint_use(instance->ep);
    88         }
    89         return instance;
     51        usb_transfer_batch_t *batch;
     52        if (ep->bus->ops.create_batch)
     53                batch = ep->bus->ops.create_batch(ep->bus, ep);
     54        else
     55                batch = malloc(sizeof(usb_transfer_batch_t));
     56
     57        return batch;
    9058}
    9159
    92 /** Correctly dispose all used data structures.
    93  *
    94  * @param[in] instance Batch structure to use.
     60/** Initialize given batch structure.
    9561 */
    96 void usb_transfer_batch_destroy(const usb_transfer_batch_t *instance)
     62void usb_transfer_batch_init(usb_transfer_batch_t *batch, endpoint_t *ep)
    9763{
    98         if (!instance)
    99                 return;
    100         usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n",
    101             instance, USB_TRANSFER_BATCH_ARGS(*instance));
    102         if (instance->ep) {
    103                 endpoint_release(instance->ep);
    104         }
    105         free(instance);
     64        memset(batch, 0, sizeof(*batch));
     65
     66        batch->ep = ep;
     67
     68        endpoint_use(ep);
    10669}
    10770
    108 /** Prepare data and call the right callback.
     71/** Call the handler of the batch.
    10972 *
    110  * @param[in] instance Batch structure to use.
    111  * @param[in] data Data to copy to the output buffer.
    112  * @param[in] size Size of @p data.
    113  * @param[in] error Error value to use.
     73 * @param[in] batch Batch structure to use.
    11474 */
    115 void usb_transfer_batch_finish_error(const usb_transfer_batch_t *instance,
    116     const void *data, size_t size, int error)
     75static int batch_complete(usb_transfer_batch_t *batch)
    11776{
    118         assert(instance);
    119         usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " finishing.\n",
    120             instance, USB_TRANSFER_BATCH_ARGS(*instance));
     77        assert(batch);
    12178
    122         /* NOTE: Only one of these pointers should be set. */
    123         if (instance->callback_out) {
    124                 instance->callback_out(error, instance->arg);
     79        usb_log_debug2("Batch %p " USB_TRANSFER_BATCH_FMT " completed.\n",
     80            batch, USB_TRANSFER_BATCH_ARGS(*batch));
     81
     82        if (batch->error == EOK && batch->toggle_reset_mode != RESET_NONE) {
     83                usb_log_debug2("Reseting %s due to transaction of %d:%d.\n",
     84                    batch->toggle_reset_mode == RESET_ALL ? "all EPs toggle" : "EP toggle",
     85                    batch->ep->target.address, batch->ep->target.endpoint);
     86                bus_reset_toggle(batch->ep->bus,
     87                    batch->ep->target, batch->toggle_reset_mode == RESET_ALL);
    12588        }
    12689
    127         if (instance->callback_in) {
    128                 /* We care about the data and there are some to copy */
    129                 const size_t safe_size = min(size, instance->buffer_size);
    130                 if (data) {
    131                         memcpy(instance->buffer, data, safe_size);
    132                 }
    133                 instance->callback_in(error, safe_size, instance->arg);
    134         }
     90        return batch->on_complete
     91                ? batch->on_complete(batch)
     92                : EOK;
     93}
     94
     95/** Destroy the batch.
     96 *
     97 * @param[in] batch Batch structure to use.
     98 */
     99void usb_transfer_batch_destroy(usb_transfer_batch_t *batch)
     100{
     101        assert(batch);
     102        assert(batch->ep);
     103        assert(batch->ep->bus);
     104
     105        usb_log_debug2("batch %p " USB_TRANSFER_BATCH_FMT " disposing.\n",
     106            batch, USB_TRANSFER_BATCH_ARGS(*batch));
     107
     108        bus_t *bus = batch->ep->bus;
     109        if (bus->ops.destroy_batch)
     110                bus->ops.destroy_batch(batch);
     111        else
     112                free(batch);
     113
     114        endpoint_release(batch->ep);
     115}
     116
     117/** Finish a transfer batch: call handler, destroy batch, release endpoint.
     118 *
     119 * Call only after the batch have been scheduled && completed!
     120 *
     121 * @param[in] batch Batch structure to use.
     122 */
     123void usb_transfer_batch_finish(usb_transfer_batch_t *batch)
     124{
     125        if (!batch_complete(batch))
     126                usb_log_warning("failed to complete batch %p!", batch);
     127
     128        usb_transfer_batch_destroy(batch);
     129}
     130
     131
     132struct old_handler_wrapper_data {
     133        usbhc_iface_transfer_in_callback_t in_callback;
     134        usbhc_iface_transfer_out_callback_t out_callback;
     135        void *arg;
     136};
     137
     138static int old_handler_wrapper(usb_transfer_batch_t *batch)
     139{
     140        struct old_handler_wrapper_data *data = batch->on_complete_data;
     141
     142        assert(data);
     143
     144        if (data->out_callback)
     145                data->out_callback(batch->error, data->arg);
     146
     147        if (data->in_callback)
     148                data->in_callback(batch->error, batch->transfered_size, data->arg);
     149
     150        free(data);
     151        return EOK;
     152}
     153
     154void usb_transfer_batch_set_old_handlers(usb_transfer_batch_t *batch,
     155        usbhc_iface_transfer_in_callback_t in_callback,
     156        usbhc_iface_transfer_out_callback_t out_callback,
     157        void *arg)
     158{
     159        struct old_handler_wrapper_data *data = malloc(sizeof(*data));
     160
     161        data->in_callback = in_callback;
     162        data->out_callback = out_callback;
     163        data->arg = arg;
     164
     165        batch->on_complete = old_handler_wrapper;
     166        batch->on_complete_data = data;
    135167}
    136168/**
Note: See TracChangeset for help on using the changeset viewer.