Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/uhci-hcd/batch.c

    ra7e2f0d r4abc304  
    3535#include <str_error.h>
    3636
    37 #include <usb/usb.h>
    3837#include <usb/debug.h>
    3938
     
    4746static int batch_schedule(batch_t *instance);
    4847
    49 static void batch_control(batch_t *instance,
    50     usb_packet_id data_stage, usb_packet_id status_stage);
    51 static void batch_data(batch_t *instance, usb_packet_id pid);
    5248static void batch_call_in(batch_t *instance);
    5349static void batch_call_out(batch_t *instance);
    5450static void batch_call_in_and_dispose(batch_t *instance);
    5551static void batch_call_out_and_dispose(batch_t *instance);
    56 static void batch_dispose(batch_t *instance);
    57 
    58 
    59 /** Allocates memory and initializes internal data structures.
    60  *
    61  * @param[in] fun DDF function to pass to callback.
    62  * @param[in] target Device and endpoint target of the transaction.
    63  * @param[in] transfer_type Interrupt, Control or Bulk.
    64  * @param[in] max_packet_size maximum allowed size of data packets.
    65  * @param[in] speed Speed of the transaction.
    66  * @param[in] buffer Data source/destination.
    67  * @param[in] size Size of the buffer.
    68  * @param[in] setup_buffer Setup data source (if not NULL)
    69  * @param[in] setup_size Size of setup_buffer (should be always 8)
    70  * @param[in] func_in function to call on inbound transaction completion
    71  * @param[in] func_out function to call on outbound transaction completion
    72  * @param[in] arg additional parameter to func_in or func_out
    73  * @param[in] manager Pointer to toggle management structure.
    74  * @return False, if there is an active TD, true otherwise.
    75  */
     52
     53
    7654batch_t * batch_get(ddf_fun_t *fun, usb_target_t target,
    7755    usb_transfer_type_t transfer_type, size_t max_packet_size,
     
    7957    char* setup_buffer, size_t setup_size,
    8058    usbhc_iface_transfer_in_callback_t func_in,
    81     usbhc_iface_transfer_out_callback_t func_out, void *arg,
    82     device_keeper_t *manager
    83     )
     59    usbhc_iface_transfer_out_callback_t func_out, void *arg)
    8460{
    8561        assert(func_in == NULL || func_out == NULL);
    8662        assert(func_in != NULL || func_out != NULL);
    8763
    88 #define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
    89         if (ptr == NULL) { \
    90                 usb_log_error(message); \
    91                 if (instance) { \
    92                         batch_dispose(instance); \
    93                 } \
    94                 return NULL; \
    95         } else (void)0
    96 
    9764        batch_t *instance = malloc(sizeof(batch_t));
    98         CHECK_NULL_DISPOSE_RETURN(instance,
    99             "Failed to allocate batch instance.\n");
    100         bzero(instance, sizeof(batch_t));
    101 
    102         instance->qh = malloc32(sizeof(queue_head_t));
    103         CHECK_NULL_DISPOSE_RETURN(instance->qh,
    104             "Failed to allocate batch queue head.\n");
    105         queue_head_init(instance->qh);
     65        if (instance == NULL) {
     66                usb_log_error("Failed to allocate batch instance.\n");
     67                return NULL;
     68        }
     69
     70        instance->qh = queue_head_get();
     71        if (instance->qh == NULL) {
     72                usb_log_error("Failed to allocate queue head.\n");
     73                free(instance);
     74                return NULL;
     75        }
    10676
    10777        instance->packets = (size + max_packet_size - 1) / max_packet_size;
     
    11080        }
    11181
    112         instance->tds = malloc32(sizeof(td_t) * instance->packets);
    113         CHECK_NULL_DISPOSE_RETURN(
    114             instance->tds, "Failed to allocate transfer descriptors.\n");
    115         bzero(instance->tds, sizeof(td_t) * instance->packets);
    116 
    117 //      const size_t transport_size = max_packet_size * instance->packets;
    118 
    119         if (size > 0) {
    120                 instance->transport_buffer = malloc32(size);
    121                 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer,
    122                     "Failed to allocate device accessible buffer.\n");
    123         }
    124 
    125         if (setup_size > 0) {
    126                 instance->setup_buffer = malloc32(setup_size);
    127                 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer,
    128                     "Failed to allocate device accessible setup buffer.\n");
     82        instance->tds = malloc32(sizeof(transfer_descriptor_t) * instance->packets);
     83        if (instance->tds == NULL) {
     84                usb_log_error("Failed to allocate transfer descriptors.\n");
     85                queue_head_dispose(instance->qh);
     86                free(instance);
     87                return NULL;
     88        }
     89        bzero(instance->tds, sizeof(transfer_descriptor_t) * instance->packets);
     90
     91        const size_t transport_size = max_packet_size * instance->packets;
     92
     93        instance->transport_buffer =
     94           (size > 0) ? malloc32(transport_size) : NULL;
     95        if ((size > 0) && (instance->transport_buffer == NULL)) {
     96                usb_log_error("Failed to allocate device accessible buffer.\n");
     97                queue_head_dispose(instance->qh);
     98                free32(instance->tds);
     99                free(instance);
     100                return NULL;
     101        }
     102
     103        instance->setup_buffer = setup_buffer ? malloc32(setup_size) : NULL;
     104        if ((setup_size > 0) && (instance->setup_buffer == NULL)) {
     105                usb_log_error("Failed to allocate device accessible setup buffer.\n");
     106                queue_head_dispose(instance->qh);
     107                free32(instance->tds);
     108                free32(instance->transport_buffer);
     109                free(instance);
     110                return NULL;
     111        }
     112        if (instance->setup_buffer) {
    129113                memcpy(instance->setup_buffer, setup_buffer, setup_size);
    130114        }
    131115
     116        instance->max_packet_size = max_packet_size;
    132117
    133118        link_initialize(&instance->link);
    134119
    135         instance->max_packet_size = max_packet_size;
    136120        instance->target = target;
    137121        instance->transfer_type = transfer_type;
     122
     123        if (func_out)
     124                instance->callback_out = func_out;
     125        if (func_in)
     126                instance->callback_in = func_in;
     127
    138128        instance->buffer = buffer;
    139129        instance->buffer_size = size;
     
    142132        instance->arg = arg;
    143133        instance->speed = speed;
    144         instance->manager = manager;
    145 
    146         if (func_out)
    147                 instance->callback_out = func_out;
    148         if (func_in)
    149                 instance->callback_in = func_in;
    150 
    151         queue_head_set_element_td(instance->qh, addr_to_phys(instance->tds));
    152 
     134
     135        queue_head_element_td(instance->qh, addr_to_phys(instance->tds));
    153136        usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
    154137            instance, target.address, target.endpoint);
     
    156139}
    157140/*----------------------------------------------------------------------------*/
    158 /** Checks batch TDs for activity.
    159  *
    160  * @param[in] instance Batch structure to use.
    161  * @return False, if there is an active TD, true otherwise.
    162  */
    163141bool batch_is_complete(batch_t *instance)
    164142{
     
    169147        size_t i = 0;
    170148        for (;i < instance->packets; ++i) {
    171                 if (td_is_active(&instance->tds[i])) {
     149                if (transfer_descriptor_is_active(&instance->tds[i])) {
    172150                        return false;
    173151                }
    174 
    175                 instance->error = td_status(&instance->tds[i]);
     152                instance->error = transfer_descriptor_status(&instance->tds[i]);
    176153                if (instance->error != EOK) {
     154                        if (i > 0)
     155                                instance->transfered_size -= instance->setup_size;
    177156                        usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
    178                             instance, i, instance->tds[i].status);
    179 
    180                         device_keeper_set_toggle(instance->manager,
    181                             instance->target, td_toggle(&instance->tds[i]));
    182                         if (i > 0)
    183                                 goto substract_ret;
     157                          instance, i, instance->tds[i].status);
    184158                        return true;
    185159                }
    186 
    187                 instance->transfered_size += td_act_size(&instance->tds[i]);
    188                 if (td_is_short(&instance->tds[i]))
    189                         goto substract_ret;
    190         }
    191 substract_ret:
     160                instance->transfered_size +=
     161                    transfer_descriptor_actual_size(&instance->tds[i]);
     162        }
    192163        instance->transfered_size -= instance->setup_size;
    193164        return true;
    194165}
    195166/*----------------------------------------------------------------------------*/
    196 /** Prepares control write transaction.
    197  *
    198  * @param[in] instance Batch structure to use.
    199  */
    200167void batch_control_write(batch_t *instance)
    201168{
    202169        assert(instance);
     170
    203171        /* we are data out, we are supposed to provide data */
    204         memcpy(instance->transport_buffer, instance->buffer,
    205             instance->buffer_size);
    206         batch_control(instance, USB_PID_OUT, USB_PID_IN);
     172        memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
     173
     174        const bool low_speed = instance->speed == USB_SPEED_LOW;
     175        int toggle = 0;
     176        /* setup stage */
     177        transfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT,
     178            instance->setup_size, toggle, false, low_speed,
     179            instance->target, USB_PID_SETUP, instance->setup_buffer,
     180            &instance->tds[1]);
     181
     182        /* data stage */
     183        size_t i = 1;
     184        for (;i < instance->packets - 1; ++i) {
     185                char *data =
     186                    instance->transport_buffer + ((i - 1) * instance->max_packet_size);
     187                toggle = 1 - toggle;
     188
     189                transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
     190                    instance->max_packet_size, toggle++, false, low_speed,
     191                    instance->target, USB_PID_OUT, data, &instance->tds[i + 1]);
     192        }
     193
     194        /* status stage */
     195        i = instance->packets - 1;
     196        transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
     197            0, 1, false, low_speed, instance->target, USB_PID_IN, NULL, NULL);
     198
     199        instance->tds[i].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
     200        usb_log_debug2("Control write last TD status: %x.\n",
     201                instance->tds[i].status);
     202
    207203        instance->next_step = batch_call_out_and_dispose;
    208204        usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
     
    210206}
    211207/*----------------------------------------------------------------------------*/
    212 /** Prepares control read transaction.
    213  *
    214  * @param[in] instance Batch structure to use.
    215  */
    216208void batch_control_read(batch_t *instance)
    217209{
    218210        assert(instance);
    219         batch_control(instance, USB_PID_IN, USB_PID_OUT);
     211
     212        const bool low_speed = instance->speed == USB_SPEED_LOW;
     213        int toggle = 0;
     214        /* setup stage */
     215        transfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT,
     216            instance->setup_size, toggle, false, low_speed, instance->target,
     217            USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]);
     218
     219        /* data stage */
     220        size_t i = 1;
     221        for (;i < instance->packets - 1; ++i) {
     222                char *data =
     223                    instance->transport_buffer + ((i - 1) * instance->max_packet_size);
     224                toggle = 1 - toggle;
     225
     226                transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
     227                    instance->max_packet_size, toggle, false, low_speed,
     228                                instance->target, USB_PID_IN, data, &instance->tds[i + 1]);
     229        }
     230
     231        /* status stage */
     232        i = instance->packets - 1;
     233        transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
     234            0, 1, false, low_speed, instance->target, USB_PID_OUT, NULL, NULL);
     235
     236        instance->tds[i].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
     237        usb_log_debug2("Control read last TD status: %x.\n",
     238                instance->tds[i].status);
     239
    220240        instance->next_step = batch_call_in_and_dispose;
    221241        usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
     
    223243}
    224244/*----------------------------------------------------------------------------*/
    225 /** Prepares interrupt in transaction.
    226  *
    227  * @param[in] instance Batch structure to use.
    228  */
    229245void batch_interrupt_in(batch_t *instance)
    230246{
    231247        assert(instance);
    232         batch_data(instance, USB_PID_IN);
     248
     249        const bool low_speed = instance->speed == USB_SPEED_LOW;
     250        int toggle = 1;
     251        size_t i = 0;
     252        for (;i < instance->packets; ++i) {
     253                char *data =
     254                    instance->transport_buffer + (i  * instance->max_packet_size);
     255                transfer_descriptor_t *next = (i + 1) < instance->packets ?
     256                    &instance->tds[i + 1] : NULL;
     257                toggle = 1 - toggle;
     258
     259                transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
     260                    instance->max_packet_size, toggle, false, low_speed,
     261                    instance->target, USB_PID_IN, data, next);
     262        }
     263
     264        instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
     265
    233266        instance->next_step = batch_call_in_and_dispose;
    234267        usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
     
    236269}
    237270/*----------------------------------------------------------------------------*/
    238 /** Prepares interrupt out transaction.
    239  *
    240  * @param[in] instance Batch structure to use.
    241  */
    242271void batch_interrupt_out(batch_t *instance)
    243272{
    244273        assert(instance);
    245         /* we are data out, we are supposed to provide data */
     274
    246275        memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
    247         batch_data(instance, USB_PID_OUT);
     276
     277        const bool low_speed = instance->speed == USB_SPEED_LOW;
     278        int toggle = 1;
     279        size_t i = 0;
     280        for (;i < instance->packets; ++i) {
     281                char *data =
     282                    instance->transport_buffer + (i  * instance->max_packet_size);
     283                transfer_descriptor_t *next = (i + 1) < instance->packets ?
     284                    &instance->tds[i + 1] : NULL;
     285                toggle = 1 - toggle;
     286
     287                transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
     288                    instance->max_packet_size, toggle++, false, low_speed,
     289                    instance->target, USB_PID_OUT, data, next);
     290        }
     291
     292        instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
     293
    248294        instance->next_step = batch_call_out_and_dispose;
    249295        usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
     
    251297}
    252298/*----------------------------------------------------------------------------*/
    253 /** Prepares bulk in transaction.
    254  *
    255  * @param[in] instance Batch structure to use.
    256  */
    257 void batch_bulk_in(batch_t *instance)
    258 {
    259         assert(instance);
    260         batch_data(instance, USB_PID_IN);
    261         instance->next_step = batch_call_in_and_dispose;
    262         usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
    263         batch_schedule(instance);
    264 }
    265 /*----------------------------------------------------------------------------*/
    266 /** Prepares bulk out transaction.
    267  *
    268  * @param[in] instance Batch structure to use.
    269  */
    270 void batch_bulk_out(batch_t *instance)
    271 {
    272         assert(instance);
    273         memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
    274         batch_data(instance, USB_PID_OUT);
    275         instance->next_step = batch_call_out_and_dispose;
    276         usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
    277         batch_schedule(instance);
    278 }
    279 /*----------------------------------------------------------------------------*/
    280 /** Prepares generic data transaction
    281  *
    282  * @param[in] instance Batch structure to use.
    283  * @param[in] pid to use for data packets.
    284  */
    285 void batch_data(batch_t *instance, usb_packet_id pid)
    286 {
    287         assert(instance);
    288         const bool low_speed = instance->speed == USB_SPEED_LOW;
    289         int toggle =
    290             device_keeper_get_toggle(instance->manager, instance->target);
    291         assert(toggle == 0 || toggle == 1);
    292 
    293         size_t packet = 0;
    294         size_t remain_size = instance->buffer_size;
    295         while (remain_size > 0) {
    296                 char *data =
    297                     instance->transport_buffer + instance->buffer_size
    298                     - remain_size;
    299 
    300                 const size_t packet_size =
    301                     (instance->max_packet_size > remain_size) ?
    302                     remain_size : instance->max_packet_size;
    303 
    304                 td_t *next_packet = (packet + 1 < instance->packets)
    305                     ? &instance->tds[packet + 1] : NULL;
    306 
    307                 assert(packet < instance->packets);
    308                 assert(packet_size <= remain_size);
    309 
    310                 td_init(
    311                     &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
    312                     toggle, false, low_speed, instance->target, pid, data,
    313                     next_packet);
    314 
    315 
    316                 toggle = 1 - toggle;
    317                 remain_size -= packet_size;
    318                 ++packet;
    319         }
    320         device_keeper_set_toggle(instance->manager, instance->target, toggle);
    321 }
    322 /*----------------------------------------------------------------------------*/
    323 /** Prepares generic control transaction
    324  *
    325  * @param[in] instance Batch structure to use.
    326  * @param[in] data_stage to use for data packets.
    327  * @param[in] status_stage to use for data packets.
    328  */
    329 void batch_control(batch_t *instance,
    330    usb_packet_id data_stage, usb_packet_id status_stage)
    331 {
    332         assert(instance);
    333 
    334         const bool low_speed = instance->speed == USB_SPEED_LOW;
    335         int toggle = 0;
    336         /* setup stage */
    337         td_init(instance->tds, DEFAULT_ERROR_COUNT,
    338             instance->setup_size, toggle, false, low_speed, instance->target,
    339             USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]);
    340 
    341         /* data stage */
    342         size_t packet = 1;
    343         size_t remain_size = instance->buffer_size;
    344         while (remain_size > 0) {
    345                 char *data =
    346                     instance->transport_buffer + instance->buffer_size
    347                     - remain_size;
    348 
    349                 toggle = 1 - toggle;
    350 
    351                 const size_t packet_size =
    352                     (instance->max_packet_size > remain_size) ?
    353                     remain_size : instance->max_packet_size;
    354 
    355                 td_init(
    356                     &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
    357                     toggle, false, low_speed, instance->target, data_stage,
    358                     data, &instance->tds[packet + 1]);
    359 
    360                 ++packet;
    361                 assert(packet < instance->packets);
    362                 assert(packet_size <= remain_size);
    363                 remain_size -= packet_size;
    364         }
    365 
    366         /* status stage */
    367         assert(packet == instance->packets - 1);
    368         td_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
    369             0, 1, false, low_speed, instance->target, status_stage, NULL, NULL);
    370 
    371 
    372         instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
    373         usb_log_debug2("Control last TD status: %x.\n",
    374             instance->tds[packet].status);
    375 }
    376 /*----------------------------------------------------------------------------*/
    377 /** Prepares data, gets error status and calls callback in.
    378  *
    379  * @param[in] instance Batch structure to use.
    380  */
    381299void batch_call_in(batch_t *instance)
    382300{
     
    384302        assert(instance->callback_in);
    385303
    386         /* we are data in, we need data */
    387         memcpy(instance->buffer, instance->transport_buffer,
    388             instance->buffer_size);
     304        memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size);
    389305
    390306        int err = instance->error;
     
    393309            instance->transfered_size);
    394310
    395         instance->callback_in(
    396             instance->fun, err, instance->transfered_size, instance->arg);
    397 }
    398 /*----------------------------------------------------------------------------*/
    399 /** Gets error status and calls callback out.
    400  *
    401  * @param[in] instance Batch structure to use.
    402  */
     311        instance->callback_in(instance->fun,
     312            err, instance->transfered_size,
     313            instance->arg);
     314}
     315/*----------------------------------------------------------------------------*/
    403316void batch_call_out(batch_t *instance)
    404317{
     
    413326}
    414327/*----------------------------------------------------------------------------*/
    415 /** Prepares data, gets error status, calls callback in and dispose.
    416  *
    417  * @param[in] instance Batch structure to use.
    418  */
    419328void batch_call_in_and_dispose(batch_t *instance)
    420329{
    421330        assert(instance);
    422331        batch_call_in(instance);
    423         batch_dispose(instance);
    424 }
    425 /*----------------------------------------------------------------------------*/
    426 /** Gets error status, calls callback out and dispose.
    427  *
    428  * @param[in] instance Batch structure to use.
    429  */
    430 void batch_call_out_and_dispose(batch_t *instance)
    431 {
    432         assert(instance);
    433         batch_call_out(instance);
    434         batch_dispose(instance);
    435 }
    436 /*----------------------------------------------------------------------------*/
    437 /** Correctly disposes all used data structures.
    438  *
    439  * @param[in] instance Batch structure to use.
    440  */
    441 void batch_dispose(batch_t *instance)
    442 {
    443         assert(instance);
    444332        usb_log_debug("Batch(%p) disposing.\n", instance);
    445         /* free32 is NULL safe */
    446333        free32(instance->tds);
    447334        free32(instance->qh);
     
    451338}
    452339/*----------------------------------------------------------------------------*/
     340void batch_call_out_and_dispose(batch_t *instance)
     341{
     342        assert(instance);
     343        batch_call_out(instance);
     344        usb_log_debug("Batch(%p) disposing.\n", instance);
     345        free32(instance->tds);
     346        free32(instance->qh);
     347        free32(instance->setup_buffer);
     348        free32(instance->transport_buffer);
     349        free(instance);
     350}
     351/*----------------------------------------------------------------------------*/
    453352int batch_schedule(batch_t *instance)
    454353{
Note: See TracChangeset for help on using the changeset viewer.