Ignore:
File:
1 edited

Legend:

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

    reae83aa ra7e2f0d  
    5454static void batch_call_in_and_dispose(batch_t *instance);
    5555static void batch_call_out_and_dispose(batch_t *instance);
    56 
    57 
     56static 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 */
    5876batch_t * batch_get(ddf_fun_t *fun, usb_target_t target,
    5977    usb_transfer_type_t transfer_type, size_t max_packet_size,
     
    6179    char* setup_buffer, size_t setup_size,
    6280    usbhc_iface_transfer_in_callback_t func_in,
    63     usbhc_iface_transfer_out_callback_t func_out, void *arg)
     81    usbhc_iface_transfer_out_callback_t func_out, void *arg,
     82    device_keeper_t *manager
     83    )
    6484{
    6585        assert(func_in == NULL || func_out == NULL);
    6686        assert(func_in != NULL || func_out != NULL);
    6787
     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
    6897        batch_t *instance = malloc(sizeof(batch_t));
    69         if (instance == NULL) {
    70                 usb_log_error("Failed to allocate batch instance.\n");
    71                 return NULL;
    72         }
    73 
    74         instance->qh = queue_head_get();
    75         if (instance->qh == NULL) {
    76                 usb_log_error("Failed to allocate queue head.\n");
    77                 free(instance);
    78                 return NULL;
    79         }
     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);
    80106
    81107        instance->packets = (size + max_packet_size - 1) / max_packet_size;
     
    85111
    86112        instance->tds = malloc32(sizeof(td_t) * instance->packets);
    87         if (instance->tds == NULL) {
    88                 usb_log_error("Failed to allocate transfer descriptors.\n");
    89                 queue_head_dispose(instance->qh);
    90                 free(instance);
    91                 return NULL;
    92         }
     113        CHECK_NULL_DISPOSE_RETURN(
     114            instance->tds, "Failed to allocate transfer descriptors.\n");
    93115        bzero(instance->tds, sizeof(td_t) * instance->packets);
    94116
    95         const size_t transport_size = max_packet_size * instance->packets;
    96 
    97         instance->transport_buffer =
    98            (size > 0) ? malloc32(transport_size) : NULL;
    99 
    100         if ((size > 0) && (instance->transport_buffer == NULL)) {
    101                 usb_log_error("Failed to allocate device accessible buffer.\n");
    102                 queue_head_dispose(instance->qh);
    103                 free32(instance->tds);
    104                 free(instance);
    105                 return NULL;
    106         }
    107 
    108         instance->setup_buffer = setup_buffer ? malloc32(setup_size) : NULL;
    109         if ((setup_size > 0) && (instance->setup_buffer == NULL)) {
    110                 usb_log_error("Failed to allocate device accessible setup buffer.\n");
    111                 queue_head_dispose(instance->qh);
    112                 free32(instance->tds);
    113                 free32(instance->transport_buffer);
    114                 free(instance);
    115                 return NULL;
    116         }
    117         if (instance->setup_buffer) {
     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");
    118129                memcpy(instance->setup_buffer, setup_buffer, setup_size);
    119130        }
    120131
     132
     133        link_initialize(&instance->link);
     134
    121135        instance->max_packet_size = max_packet_size;
    122 
    123         link_initialize(&instance->link);
    124 
    125136        instance->target = target;
    126137        instance->transfer_type = transfer_type;
    127 
    128         if (func_out)
    129                 instance->callback_out = func_out;
    130         if (func_in)
    131                 instance->callback_in = func_in;
    132 
    133138        instance->buffer = buffer;
    134139        instance->buffer_size = size;
     
    137142        instance->arg = arg;
    138143        instance->speed = speed;
    139 
    140         queue_head_element_td(instance->qh, addr_to_phys(instance->tds));
     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
    141153        usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
    142154            instance, target.address, target.endpoint);
     
    144156}
    145157/*----------------------------------------------------------------------------*/
     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 */
    146163bool batch_is_complete(batch_t *instance)
    147164{
     
    160177                        usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
    161178                            instance, i, instance->tds[i].status);
     179
     180                        device_keeper_set_toggle(instance->manager,
     181                            instance->target, td_toggle(&instance->tds[i]));
    162182                        if (i > 0)
    163183                                goto substract_ret;
     
    174194}
    175195/*----------------------------------------------------------------------------*/
     196/** Prepares control write transaction.
     197 *
     198 * @param[in] instance Batch structure to use.
     199 */
    176200void batch_control_write(batch_t *instance)
    177201{
    178202        assert(instance);
    179203        /* we are data out, we are supposed to provide data */
    180         memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
     204        memcpy(instance->transport_buffer, instance->buffer,
     205            instance->buffer_size);
    181206        batch_control(instance, USB_PID_OUT, USB_PID_IN);
    182207        instance->next_step = batch_call_out_and_dispose;
     
    185210}
    186211/*----------------------------------------------------------------------------*/
     212/** Prepares control read transaction.
     213 *
     214 * @param[in] instance Batch structure to use.
     215 */
    187216void batch_control_read(batch_t *instance)
    188217{
     
    194223}
    195224/*----------------------------------------------------------------------------*/
     225/** Prepares interrupt in transaction.
     226 *
     227 * @param[in] instance Batch structure to use.
     228 */
    196229void batch_interrupt_in(batch_t *instance)
    197230{
     
    203236}
    204237/*----------------------------------------------------------------------------*/
     238/** Prepares interrupt out transaction.
     239 *
     240 * @param[in] instance Batch structure to use.
     241 */
    205242void batch_interrupt_out(batch_t *instance)
    206243{
    207244        assert(instance);
     245        /* we are data out, we are supposed to provide data */
    208246        memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
    209247        batch_data(instance, USB_PID_OUT);
     
    213251}
    214252/*----------------------------------------------------------------------------*/
     253/** Prepares bulk in transaction.
     254 *
     255 * @param[in] instance Batch structure to use.
     256 */
    215257void batch_bulk_in(batch_t *instance)
    216258{
     
    222264}
    223265/*----------------------------------------------------------------------------*/
     266/** Prepares bulk out transaction.
     267 *
     268 * @param[in] instance Batch structure to use.
     269 */
    224270void batch_bulk_out(batch_t *instance)
    225271{
     
    232278}
    233279/*----------------------------------------------------------------------------*/
    234 static void batch_data(batch_t *instance, usb_packet_id pid)
     280/** Prepares generic data transaction
     281 *
     282 * @param[in] instance Batch structure to use.
     283 * @param[in] pid to use for data packets.
     284 */
     285void batch_data(batch_t *instance, usb_packet_id pid)
    235286{
    236287        assert(instance);
    237288        const bool low_speed = instance->speed == USB_SPEED_LOW;
    238         int toggle = 1;
     289        int toggle =
     290            device_keeper_get_toggle(instance->manager, instance->target);
     291        assert(toggle == 0 || toggle == 1);
    239292
    240293        size_t packet = 0;
     
    245298                    - remain_size;
    246299
    247                 toggle = 1 - toggle;
    248 
    249300                const size_t packet_size =
    250301                    (instance->max_packet_size > remain_size) ?
    251302                    remain_size : instance->max_packet_size;
    252303
    253                 td_init(&instance->tds[packet],
    254                     DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,
    255                     instance->target, pid, data,
    256                     &instance->tds[packet + 1]);
    257 
     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;
    258318                ++packet;
    259                 assert(packet <= instance->packets);
    260                 assert(packet_size <= remain_size);
    261                 remain_size -= packet_size;
    262         }
    263 
    264         instance->tds[packet - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
    265         instance->tds[packet - 1].next = 0 | LINK_POINTER_TERMINATE_FLAG;
    266 }
    267 /*----------------------------------------------------------------------------*/
    268 static void batch_control(batch_t *instance,
     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 */
     329void batch_control(batch_t *instance,
    269330   usb_packet_id data_stage, usb_packet_id status_stage)
    270331{
     
    292353                    remain_size : instance->max_packet_size;
    293354
    294                 td_init(&instance->tds[packet],
    295                     DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,
    296                     instance->target, data_stage, data,
    297                     &instance->tds[packet + 1]);
     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]);
    298359
    299360                ++packet;
     
    314375}
    315376/*----------------------------------------------------------------------------*/
     377/** Prepares data, gets error status and calls callback in.
     378 *
     379 * @param[in] instance Batch structure to use.
     380 */
    316381void batch_call_in(batch_t *instance)
    317382{
     
    319384        assert(instance->callback_in);
    320385
    321         memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size);
     386        /* we are data in, we need data */
     387        memcpy(instance->buffer, instance->transport_buffer,
     388            instance->buffer_size);
    322389
    323390        int err = instance->error;
     
    326393            instance->transfered_size);
    327394
    328         instance->callback_in(instance->fun,
    329             err, instance->transfered_size,
    330             instance->arg);
    331 }
    332 /*----------------------------------------------------------------------------*/
     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 */
    333403void batch_call_out(batch_t *instance)
    334404{
     
    343413}
    344414/*----------------------------------------------------------------------------*/
     415/** Prepares data, gets error status, calls callback in and dispose.
     416 *
     417 * @param[in] instance Batch structure to use.
     418 */
    345419void batch_call_in_and_dispose(batch_t *instance)
    346420{
    347421        assert(instance);
    348422        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 */
     430void 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 */
     441void batch_dispose(batch_t *instance)
     442{
     443        assert(instance);
    349444        usb_log_debug("Batch(%p) disposing.\n", instance);
     445        /* free32 is NULL safe */
    350446        free32(instance->tds);
    351447        free32(instance->qh);
     
    355451}
    356452/*----------------------------------------------------------------------------*/
    357 void batch_call_out_and_dispose(batch_t *instance)
    358 {
    359         assert(instance);
    360         batch_call_out(instance);
    361         usb_log_debug("Batch(%p) disposing.\n", instance);
    362         free32(instance->tds);
    363         free32(instance->qh);
    364         free32(instance->setup_buffer);
    365         free32(instance->transport_buffer);
    366         free(instance);
    367 }
    368 /*----------------------------------------------------------------------------*/
    369453int batch_schedule(batch_t *instance)
    370454{
Note: See TracChangeset for help on using the changeset viewer.