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

Changeset c7dd69d in mainline for uspace/drv/uhci-hcd/batch.c


Ignore:
Timestamp:
2011-04-15T13:19:59Z (11 years ago)
Author:
Lubos Slovak <lubos.slovak@…>
Branches:
lfn, master
Children:
da1dd48
Parents:
e3b5129 (diff), 8fd4ba0 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Development changes

File:
1 edited

Legend:

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

    re3b5129 rc7dd69d  
    3030 */
    3131/** @file
    32  * @brief UHCI driver USB transaction structure
     32 * @brief UHCI driver USB transfer structure
    3333 */
    3434#include <errno.h>
     
    4545#define DEFAULT_ERROR_COUNT 3
    4646
    47 typedef struct uhci_batch {
     47typedef struct uhci_transfer_batch {
    4848        qh_t *qh;
    4949        td_t *tds;
    50         size_t transfers;
    51 } uhci_batch_t;
     50        void *device_buffer;
     51        size_t td_count;
     52} uhci_transfer_batch_t;
     53/*----------------------------------------------------------------------------*/
     54static void uhci_transfer_batch_dispose(void *uhci_batch)
     55{
     56        uhci_transfer_batch_t *instance = uhci_batch;
     57        assert(instance);
     58        free32(instance->device_buffer);
     59        free(instance);
     60}
     61/*----------------------------------------------------------------------------*/
    5262
    5363static void batch_control(usb_transfer_batch_t *instance,
    5464    usb_packet_id data_stage, usb_packet_id status_stage);
    5565static void batch_data(usb_transfer_batch_t *instance, usb_packet_id pid);
    56 static void batch_call_in_and_dispose(usb_transfer_batch_t *instance);
    57 static void batch_call_out_and_dispose(usb_transfer_batch_t *instance);
    58 
    5966
    6067/** Allocate memory and initialize internal data structure.
    6168 *
    6269 * @param[in] fun DDF function to pass to callback.
    63  * @param[in] target Device and endpoint target of the transaction.
    64  * @param[in] transfer_type Interrupt, Control or Bulk.
    65  * @param[in] max_packet_size maximum allowed size of data transfers.
    66  * @param[in] speed Speed of the transaction.
     70 * @param[in] ep Communication target
    6771 * @param[in] buffer Data source/destination.
    6872 * @param[in] size Size of the buffer.
    6973 * @param[in] setup_buffer Setup data source (if not NULL)
    7074 * @param[in] setup_size Size of setup_buffer (should be always 8)
    71  * @param[in] func_in function to call on inbound transaction completion
    72  * @param[in] func_out function to call on outbound transaction completion
     75 * @param[in] func_in function to call on inbound transfer completion
     76 * @param[in] func_out function to call on outbound transfer completion
    7377 * @param[in] arg additional parameter to func_in or func_out
    74  * @param[in] ep Pointer to endpoint toggle management structure.
    75  * @return Valid pointer if all substructures were successfully created,
     78 * @return Valid pointer if all structures were successfully created,
    7679 * NULL otherwise.
    7780 *
    78  * Determines the number of needed transfers (TDs). Prepares a transport buffer
    79  * (that is accessible by the hardware). Initializes parameters needed for the
    80  * transaction and callback.
     81 * Determines the number of needed transfer descriptors (TDs).
     82 * Prepares a transport buffer (that is accessible by the hardware).
     83 * Initializes parameters needed for the transfer and callback.
    8184 */
    8285usb_transfer_batch_t * batch_get(ddf_fun_t *fun, endpoint_t *ep,
     
    9295        if (ptr == NULL) { \
    9396                usb_log_error(message); \
    94                 if (instance) { \
    95                         batch_dispose(instance); \
     97                if (uhci_data) { \
     98                        uhci_transfer_batch_dispose(uhci_data); \
    9699                } \
    97100                return NULL; \
    98101        } else (void)0
    99102
     103        uhci_transfer_batch_t *uhci_data =
     104            malloc(sizeof(uhci_transfer_batch_t));
     105        CHECK_NULL_DISPOSE_RETURN(uhci_data,
     106            "Failed to allocate UHCI batch.\n");
     107        bzero(uhci_data, sizeof(uhci_transfer_batch_t));
     108
     109        uhci_data->td_count =
     110            (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size;
     111        if (ep->transfer_type == USB_TRANSFER_CONTROL) {
     112                uhci_data->td_count += 2;
     113        }
     114
     115        assert((sizeof(td_t) % 16) == 0);
     116        const size_t total_size = (sizeof(td_t) * uhci_data->td_count)
     117            + sizeof(qh_t) + setup_size + buffer_size;
     118        uhci_data->device_buffer = malloc32(total_size);
     119        CHECK_NULL_DISPOSE_RETURN(uhci_data->device_buffer,
     120            "Failed to allocate UHCI buffer.\n");
     121        bzero(uhci_data->device_buffer, total_size);
     122
     123        uhci_data->tds = uhci_data->device_buffer;
     124        uhci_data->qh =
     125            (uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count));
     126
     127        qh_init(uhci_data->qh);
     128        qh_set_element_td(uhci_data->qh, uhci_data->tds);
     129
    100130        usb_transfer_batch_t *instance = malloc(sizeof(usb_transfer_batch_t));
    101131        CHECK_NULL_DISPOSE_RETURN(instance,
    102132            "Failed to allocate batch instance.\n");
     133        void *setup =
     134            uhci_data->device_buffer + (sizeof(td_t) * uhci_data->td_count)
     135            + sizeof(qh_t);
     136        void *data_buffer = setup + setup_size;
    103137        usb_target_t target =
    104138            { .address = ep->address, .endpoint = ep->endpoint };
    105         usb_transfer_batch_init(instance, target, ep->transfer_type, ep->speed,
    106             ep->max_packet_size, buffer, NULL, buffer_size, NULL, setup_size,
    107             func_in, func_out, arg, fun, ep, NULL);
    108 
    109 
    110         uhci_batch_t *data = malloc(sizeof(uhci_batch_t));
    111         CHECK_NULL_DISPOSE_RETURN(data, "Failed to allocate batch data.\n");
    112         bzero(data, sizeof(uhci_batch_t));
    113         instance->private_data = data;
    114 
    115         data->transfers =
    116             (buffer_size + ep->max_packet_size - 1) / ep->max_packet_size;
    117         if (ep->transfer_type == USB_TRANSFER_CONTROL) {
    118                 data->transfers += 2;
    119         }
    120 
    121         data->tds = malloc32(sizeof(td_t) * data->transfers);
    122         CHECK_NULL_DISPOSE_RETURN(
    123             data->tds, "Failed to allocate transfer descriptors.\n");
    124         bzero(data->tds, sizeof(td_t) * data->transfers);
    125 
    126         data->qh = malloc32(sizeof(qh_t));
    127         CHECK_NULL_DISPOSE_RETURN(data->qh,
    128             "Failed to allocate batch queue head.\n");
    129         qh_init(data->qh);
    130         qh_set_element_td(data->qh, addr_to_phys(data->tds));
    131 
    132         if (buffer_size > 0) {
    133                 instance->transport_buffer = malloc32(buffer_size);
    134                 CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer,
    135                     "Failed to allocate device accessible buffer.\n");
    136         }
    137 
    138         if (setup_size > 0) {
    139                 instance->setup_buffer = malloc32(setup_size);
    140                 CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer,
    141                     "Failed to allocate device accessible setup buffer.\n");
    142                 memcpy(instance->setup_buffer, setup_buffer, setup_size);
    143         }
    144 
     139        usb_transfer_batch_init(instance, ep, buffer, data_buffer, buffer_size,
     140            setup, setup_size, func_in, func_out, arg, fun,
     141            uhci_data, uhci_transfer_batch_dispose);
     142
     143        memcpy(instance->setup_buffer, setup_buffer, setup_size);
    145144        usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
    146145            instance, target.address, target.endpoint);
     
    154153 *
    155154 * Walk all TDs. Stop with false if there is an active one (it is to be
    156  * processed). Stop with true if an error is found. Return true if the last TS
     155 * processed). Stop with true if an error is found. Return true if the last TD
    157156 * is reached.
    158157 */
     
    160159{
    161160        assert(instance);
    162         uhci_batch_t *data = instance->private_data;
     161        uhci_transfer_batch_t *data = instance->private_data;
    163162        assert(data);
    164163
    165164        usb_log_debug2("Batch(%p) checking %d transfer(s) for completion.\n",
    166             instance, data->transfers);
     165            instance, data->td_count);
    167166        instance->transfered_size = 0;
    168167        size_t i = 0;
    169         for (;i < data->transfers; ++i) {
     168        for (;i < data->td_count; ++i) {
    170169                if (td_is_active(&data->tds[i])) {
    171170                        return false;
     
    177176                            instance, i, data->tds[i].status);
    178177                        td_print_status(&data->tds[i]);
     178
    179179                        assert(instance->ep != NULL);
    180 
    181180                        endpoint_toggle_set(instance->ep,
    182181                            td_toggle(&data->tds[i]));
     
    195194}
    196195/*----------------------------------------------------------------------------*/
    197 /** Prepares control write transaction.
    198  *
    199  * @param[in] instance Batch structure to use.
    200  *
    201  * Uses genercir control function with pids OUT and IN.
     196/** Prepares control write transfer.
     197 *
     198 * @param[in] instance Batch structure to use.
     199 *
     200 * Uses generic control function with pids OUT and IN.
    202201 */
    203202void batch_control_write(usb_transfer_batch_t *instance)
     
    205204        assert(instance);
    206205        /* We are data out, we are supposed to provide data */
    207         memcpy(instance->transport_buffer, instance->buffer,
    208             instance->buffer_size);
     206        memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
    209207        batch_control(instance, USB_PID_OUT, USB_PID_IN);
    210         instance->next_step = batch_call_out_and_dispose;
     208        instance->next_step = usb_transfer_batch_call_out_and_dispose;
    211209        usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
    212210}
    213211/*----------------------------------------------------------------------------*/
    214 /** Prepares control read transaction.
     212/** Prepares control read transfer.
    215213 *
    216214 * @param[in] instance Batch structure to use.
     
    222220        assert(instance);
    223221        batch_control(instance, USB_PID_IN, USB_PID_OUT);
    224         instance->next_step = batch_call_in_and_dispose;
     222        instance->next_step = usb_transfer_batch_call_in_and_dispose;
    225223        usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
    226224}
    227225/*----------------------------------------------------------------------------*/
    228 /** Prepare interrupt in transaction.
    229  *
    230  * @param[in] instance Batch structure to use.
    231  *
    232  * Data transaction with PID_IN.
     226/** Prepare interrupt in transfer.
     227 *
     228 * @param[in] instance Batch structure to use.
     229 *
     230 * Data transfer with PID_IN.
    233231 */
    234232void batch_interrupt_in(usb_transfer_batch_t *instance)
    235233{
    236234        assert(instance);
    237         instance->direction = USB_DIRECTION_IN;
    238235        batch_data(instance, USB_PID_IN);
    239         instance->next_step = batch_call_in_and_dispose;
     236        instance->next_step = usb_transfer_batch_call_in_and_dispose;
    240237        usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
    241238}
    242239/*----------------------------------------------------------------------------*/
    243 /** Prepare interrupt out transaction.
    244  *
    245  * @param[in] instance Batch structure to use.
    246  *
    247  * Data transaction with PID_OUT.
     240/** Prepare interrupt out transfer.
     241 *
     242 * @param[in] instance Batch structure to use.
     243 *
     244 * Data transfer with PID_OUT.
    248245 */
    249246void batch_interrupt_out(usb_transfer_batch_t *instance)
    250247{
    251248        assert(instance);
    252         instance->direction = USB_DIRECTION_OUT;
    253249        /* We are data out, we are supposed to provide data */
    254         memcpy(instance->transport_buffer, instance->buffer,
    255             instance->buffer_size);
     250        memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
    256251        batch_data(instance, USB_PID_OUT);
    257         instance->next_step = batch_call_out_and_dispose;
     252        instance->next_step = usb_transfer_batch_call_out_and_dispose;
    258253        usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
    259254}
    260255/*----------------------------------------------------------------------------*/
    261 /** Prepare bulk in transaction.
    262  *
    263  * @param[in] instance Batch structure to use.
    264  *
    265  * Data transaction with PID_IN.
     256/** Prepare bulk in transfer.
     257 *
     258 * @param[in] instance Batch structure to use.
     259 *
     260 * Data transfer with PID_IN.
    266261 */
    267262void batch_bulk_in(usb_transfer_batch_t *instance)
     
    269264        assert(instance);
    270265        batch_data(instance, USB_PID_IN);
    271         instance->direction = USB_DIRECTION_IN;
    272         instance->next_step = batch_call_in_and_dispose;
     266        instance->next_step = usb_transfer_batch_call_in_and_dispose;
    273267        usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
    274268}
    275269/*----------------------------------------------------------------------------*/
    276 /** Prepare bulk out transaction.
    277  *
    278  * @param[in] instance Batch structure to use.
    279  *
    280  * Data transaction with PID_OUT.
     270/** Prepare bulk out transfer.
     271 *
     272 * @param[in] instance Batch structure to use.
     273 *
     274 * Data transfer with PID_OUT.
    281275 */
    282276void batch_bulk_out(usb_transfer_batch_t *instance)
    283277{
    284278        assert(instance);
    285         instance->direction = USB_DIRECTION_OUT;
    286279        /* We are data out, we are supposed to provide data */
    287         memcpy(instance->transport_buffer, instance->buffer,
    288             instance->buffer_size);
     280        memcpy(instance->data_buffer, instance->buffer, instance->buffer_size);
    289281        batch_data(instance, USB_PID_OUT);
    290         instance->next_step = batch_call_out_and_dispose;
     282        instance->next_step = usb_transfer_batch_call_out_and_dispose;
    291283        usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
    292284}
    293285/*----------------------------------------------------------------------------*/
    294 /** Prepare generic data transaction
    295  *
    296  * @param[in] instance Batch structure to use.
    297  * @param[in] pid Pid to use for data transfers.
    298  *
    299  * Packets with alternating toggle bit and supplied pid value.
     286/** Prepare generic data transfer
     287 *
     288 * @param[in] instance Batch structure to use.
     289 * @param[in] pid Pid to use for data transactions.
     290 *
     291 * Transactions with alternating toggle bit and supplied pid value.
    300292 * The last transfer is marked with IOC flag.
    301293 */
     
    303295{
    304296        assert(instance);
    305         uhci_batch_t *data = instance->private_data;
     297        uhci_transfer_batch_t *data = instance->private_data;
    306298        assert(data);
    307299
    308         const bool low_speed = instance->speed == USB_SPEED_LOW;
     300        const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
    309301        int toggle = endpoint_toggle_get(instance->ep);
    310302        assert(toggle == 0 || toggle == 1);
    311303
    312         size_t transfer = 0;
     304        size_t td = 0;
    313305        size_t remain_size = instance->buffer_size;
     306        char *buffer = instance->data_buffer;
    314307        while (remain_size > 0) {
    315                 char *trans_data =
    316                     instance->transport_buffer + instance->buffer_size
    317                     - remain_size;
    318 
    319308                const size_t packet_size =
    320                     (instance->max_packet_size > remain_size) ?
    321                     remain_size : instance->max_packet_size;
    322 
    323                 td_t *next_transfer = (transfer + 1 < data->transfers)
    324                     ? &data->tds[transfer + 1] : NULL;
    325 
    326                 assert(transfer < data->transfers);
     309                    (instance->ep->max_packet_size > remain_size) ?
     310                    remain_size : instance->ep->max_packet_size;
     311
     312                td_t *next_td = (td + 1 < data->td_count)
     313                    ? &data->tds[td + 1] : NULL;
     314
     315
     316                usb_target_t target =
     317                    { instance->ep->address, instance->ep->endpoint };
     318
     319                assert(td < data->td_count);
     320                td_init(
     321                    &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
     322                    toggle, false, low_speed, target, pid, buffer, next_td);
     323
     324                ++td;
     325                toggle = 1 - toggle;
     326                buffer += packet_size;
    327327                assert(packet_size <= remain_size);
    328 
    329                 td_init(
    330                     &data->tds[transfer], DEFAULT_ERROR_COUNT, packet_size,
    331                     toggle, false, low_speed, instance->target, pid, trans_data,
    332                     next_transfer);
    333 
    334 
    335                 toggle = 1 - toggle;
    336328                remain_size -= packet_size;
    337                 ++transfer;
    338329        }
    339         td_set_ioc(&data->tds[transfer - 1]);
     330        td_set_ioc(&data->tds[td - 1]);
    340331        endpoint_toggle_set(instance->ep, toggle);
    341332}
    342333/*----------------------------------------------------------------------------*/
    343 /** Prepare generic control transaction
    344  *
    345  * @param[in] instance Batch structure to use.
    346  * @param[in] data_stage Pid to use for data transfers.
    347  * @param[in] status_stage Pid to use for data transfers.
     334/** Prepare generic control transfer
     335 *
     336 * @param[in] instance Batch structure to use.
     337 * @param[in] data_stage Pid to use for data tds.
     338 * @param[in] status_stage Pid to use for data tds.
    348339 *
    349340 * Setup stage with toggle 0 and USB_PID_SETUP.
     
    356347{
    357348        assert(instance);
    358         uhci_batch_t *data = instance->private_data;
     349        uhci_transfer_batch_t *data = instance->private_data;
    359350        assert(data);
    360         assert(data->transfers >= 2);
    361 
    362         const bool low_speed = instance->speed == USB_SPEED_LOW;
    363         int toggle = 0;
     351        assert(data->td_count >= 2);
     352
     353        const bool low_speed = instance->ep->speed == USB_SPEED_LOW;
     354        const usb_target_t target =
     355            { instance->ep->address, instance->ep->endpoint };
     356
    364357        /* setup stage */
    365358        td_init(
    366             data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, toggle, false,
    367             low_speed, instance->target, USB_PID_SETUP, instance->setup_buffer,
     359            data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, 0, false,
     360            low_speed, target, USB_PID_SETUP, instance->setup_buffer,
    368361            &data->tds[1]);
    369362
    370363        /* data stage */
    371         size_t transfer = 1;
     364        size_t td = 1;
     365        unsigned toggle = 1;
    372366        size_t remain_size = instance->buffer_size;
     367        char *buffer = instance->data_buffer;
    373368        while (remain_size > 0) {
    374                 char *control_data =
    375                     instance->transport_buffer + instance->buffer_size
    376                     - remain_size;
    377 
     369                const size_t packet_size =
     370                    (instance->ep->max_packet_size > remain_size) ?
     371                    remain_size : instance->ep->max_packet_size;
     372
     373                td_init(
     374                    &data->tds[td], DEFAULT_ERROR_COUNT, packet_size,
     375                    toggle, false, low_speed, target, data_stage,
     376                    buffer, &data->tds[td + 1]);
     377
     378                ++td;
    378379                toggle = 1 - toggle;
    379 
    380                 const size_t packet_size =
    381                     (instance->max_packet_size > remain_size) ?
    382                     remain_size : instance->max_packet_size;
    383 
    384                 td_init(
    385                     &data->tds[transfer], DEFAULT_ERROR_COUNT, packet_size,
    386                     toggle, false, low_speed, instance->target, data_stage,
    387                     control_data, &data->tds[transfer + 1]);
    388 
    389                 ++transfer;
    390                 assert(transfer < data->transfers);
     380                buffer += packet_size;
     381                assert(td < data->td_count);
    391382                assert(packet_size <= remain_size);
    392383                remain_size -= packet_size;
     
    394385
    395386        /* status stage */
    396         assert(transfer == data->transfers - 1);
     387        assert(td == data->td_count - 1);
    397388
    398389        td_init(
    399             &data->tds[transfer], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,
    400             instance->target, status_stage, NULL, NULL);
    401         td_set_ioc(&data->tds[transfer]);
     390            &data->tds[td], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,
     391            target, status_stage, NULL, NULL);
     392        td_set_ioc(&data->tds[td]);
    402393
    403394        usb_log_debug2("Control last TD status: %x.\n",
    404             data->tds[transfer].status);
    405 }
    406 /*----------------------------------------------------------------------------*/
     395            data->tds[td].status);
     396}
     397/*----------------------------------------------------------------------------*/
     398/** Provides access to QH data structure.
     399 * @param[in] instance Batch pointer to use.
     400 * @return Pointer to the QH used by the batch.
     401 */
    407402qh_t * batch_qh(usb_transfer_batch_t *instance)
    408403{
    409404        assert(instance);
    410         uhci_batch_t *data = instance->private_data;
     405        uhci_transfer_batch_t *data = instance->private_data;
    411406        assert(data);
    412407        return data->qh;
    413408}
    414 /*----------------------------------------------------------------------------*/
    415 /** Helper function calls callback and correctly disposes of batch structure.
    416  *
    417  * @param[in] instance Batch structure to use.
    418  */
    419 void batch_call_in_and_dispose(usb_transfer_batch_t *instance)
    420 {
    421         assert(instance);
    422         usb_transfer_batch_call_in(instance);
    423         batch_dispose(instance);
    424 }
    425 /*----------------------------------------------------------------------------*/
    426 /** Helper function calls callback and correctly disposes of batch structure.
    427  *
    428  * @param[in] instance Batch structure to use.
    429  */
    430 void batch_call_out_and_dispose(usb_transfer_batch_t *instance)
    431 {
    432         assert(instance);
    433         usb_transfer_batch_call_out(instance);
    434         batch_dispose(instance);
    435 }
    436 /*----------------------------------------------------------------------------*/
    437 /** Correctly dispose all used data structures.
    438  *
    439  * @param[in] instance Batch structure to use.
    440  */
    441 void batch_dispose(usb_transfer_batch_t *instance)
    442 {
    443         assert(instance);
    444         uhci_batch_t *data = instance->private_data;
    445         assert(data);
    446         usb_log_debug("Batch(%p) disposing.\n", instance);
    447         /* free32 is NULL safe */
    448         free32(data->tds);
    449         free32(data->qh);
    450         free32(instance->setup_buffer);
    451         free32(instance->transport_buffer);
    452         free(data);
    453         free(instance);
    454 }
    455409/**
    456410 * @}
Note: See TracChangeset for help on using the changeset viewer.