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


Ignore:
Timestamp:
2011-03-16T18:50:17Z (13 years ago)
Author:
Matus Dekanek <smekideki@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
42a3a57
Parents:
3e7b7cd (diff), fcf07e6 (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:

merge from usb/development

File:
1 edited

Legend:

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

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcihc
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI driver
     32 * @brief UHCI driver USB transaction structure
    3333 */
    3434#include <errno.h>
     
    4040#include "batch.h"
    4141#include "transfer_list.h"
    42 #include "uhci.h"
     42#include "uhci_hc.h"
    4343#include "utils/malloc32.h"
    4444
    4545#define DEFAULT_ERROR_COUNT 3
    4646
    47 static int batch_schedule(batch_t *instance);
    48 
    49 static void batch_control(
    50     batch_t *instance, int data_stage, int status_stage);
     47static void batch_control(batch_t *instance,
     48    usb_packet_id data_stage, usb_packet_id status_stage);
     49static void batch_data(batch_t *instance, usb_packet_id pid);
    5150static void batch_call_in(batch_t *instance);
    5251static void batch_call_out(batch_t *instance);
     
    5554
    5655
     56/** Allocate memory and initialize internal data structure.
     57 *
     58 * @param[in] fun DDF function to pass to callback.
     59 * @param[in] target Device and endpoint target of the transaction.
     60 * @param[in] transfer_type Interrupt, Control or Bulk.
     61 * @param[in] max_packet_size maximum allowed size of data packets.
     62 * @param[in] speed Speed of the transaction.
     63 * @param[in] buffer Data source/destination.
     64 * @param[in] size Size of the buffer.
     65 * @param[in] setup_buffer Setup data source (if not NULL)
     66 * @param[in] setup_size Size of setup_buffer (should be always 8)
     67 * @param[in] func_in function to call on inbound transaction completion
     68 * @param[in] func_out function to call on outbound transaction completion
     69 * @param[in] arg additional parameter to func_in or func_out
     70 * @param[in] manager Pointer to toggle management structure.
     71 * @return Valid pointer if all substructures were successfully created,
     72 * NULL otherwise.
     73 *
     74 * Determines the number of needed packets (TDs). Prepares a transport buffer
     75 * (that is accessible by the hardware). Initializes parameters needed for the
     76 * transaction and callback.
     77 */
    5778batch_t * batch_get(ddf_fun_t *fun, usb_target_t target,
    5879    usb_transfer_type_t transfer_type, size_t max_packet_size,
     
    6081    char* setup_buffer, size_t setup_size,
    6182    usbhc_iface_transfer_in_callback_t func_in,
    62     usbhc_iface_transfer_out_callback_t func_out, void *arg)
     83    usbhc_iface_transfer_out_callback_t func_out, void *arg,
     84    device_keeper_t *manager
     85    )
    6386{
    6487        assert(func_in == NULL || func_out == NULL);
    6588        assert(func_in != NULL || func_out != NULL);
    6689
     90#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
     91        if (ptr == NULL) { \
     92                usb_log_error(message); \
     93                if (instance) { \
     94                        batch_dispose(instance); \
     95                } \
     96                return NULL; \
     97        } else (void)0
     98
    6799        batch_t *instance = malloc(sizeof(batch_t));
    68         if (instance == NULL) {
    69                 usb_log_error("Failed to allocate batch instance.\n");
    70                 return NULL;
    71         }
    72 
    73         instance->qh = queue_head_get();
    74         if (instance->qh == NULL) {
    75                 usb_log_error("Failed to allocate queue head.\n");
    76                 free(instance);
    77                 return NULL;
    78         }
     100        CHECK_NULL_DISPOSE_RETURN(instance,
     101            "Failed to allocate batch instance.\n");
     102        bzero(instance, sizeof(batch_t));
     103
     104        instance->qh = malloc32(sizeof(qh_t));
     105        CHECK_NULL_DISPOSE_RETURN(instance->qh,
     106            "Failed to allocate batch queue head.\n");
     107        qh_init(instance->qh);
    79108
    80109        instance->packets = (size + max_packet_size - 1) / max_packet_size;
     
    83112        }
    84113
    85         instance->tds = malloc32(sizeof(transfer_descriptor_t) * instance->packets);
    86         if (instance->tds == NULL) {
    87                 usb_log_error("Failed to allocate transfer descriptors.\n");
    88                 queue_head_dispose(instance->qh);
    89                 free(instance);
    90                 return NULL;
    91         }
    92         bzero(instance->tds, sizeof(transfer_descriptor_t) * instance->packets);
    93 
    94         const size_t transport_size = max_packet_size * instance->packets;
    95 
    96         instance->transport_buffer =
    97            (size > 0) ? malloc32(transport_size) : NULL;
    98 
    99         if ((size > 0) && (instance->transport_buffer == NULL)) {
    100                 usb_log_error("Failed to allocate device accessible buffer.\n");
    101                 queue_head_dispose(instance->qh);
    102                 free32(instance->tds);
    103                 free(instance);
    104                 return NULL;
    105         }
    106 
    107         instance->setup_buffer = setup_buffer ? malloc32(setup_size) : NULL;
    108         if ((setup_size > 0) && (instance->setup_buffer == NULL)) {
    109                 usb_log_error("Failed to allocate device accessible setup buffer.\n");
    110                 queue_head_dispose(instance->qh);
    111                 free32(instance->tds);
    112                 free32(instance->transport_buffer);
    113                 free(instance);
    114                 return NULL;
    115         }
    116         if (instance->setup_buffer) {
     114        instance->tds = malloc32(sizeof(td_t) * instance->packets);
     115        CHECK_NULL_DISPOSE_RETURN(
     116            instance->tds, "Failed to allocate transfer descriptors.\n");
     117        bzero(instance->tds, sizeof(td_t) * 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");
    117129                memcpy(instance->setup_buffer, setup_buffer, setup_size);
    118130        }
    119131
     132
     133        link_initialize(&instance->link);
     134
    120135        instance->max_packet_size = max_packet_size;
    121 
    122         link_initialize(&instance->link);
    123 
    124136        instance->target = target;
    125137        instance->transfer_type = transfer_type;
    126 
    127         if (func_out)
    128                 instance->callback_out = func_out;
    129         if (func_in)
    130                 instance->callback_in = func_in;
    131 
    132138        instance->buffer = buffer;
    133139        instance->buffer_size = size;
     
    136142        instance->arg = arg;
    137143        instance->speed = speed;
    138 
    139         queue_head_element_td(instance->qh, addr_to_phys(instance->tds));
     144        instance->manager = manager;
     145        instance->callback_out = func_out;
     146        instance->callback_in = func_in;
     147
     148        qh_set_element_td(instance->qh, addr_to_phys(instance->tds));
     149
    140150        usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
    141151            instance, target.address, target.endpoint);
     
    143153}
    144154/*----------------------------------------------------------------------------*/
     155/** Check batch TDs for activity.
     156 *
     157 * @param[in] instance Batch structure to use.
     158 * @return False, if there is an active TD, true otherwise.
     159 *
     160 * Walk all TDs. Stop with false if there is an active one (it is to be
     161 * processed). Stop with true if an error is found. Return true if the last TS
     162 * is reached.
     163 */
    145164bool batch_is_complete(batch_t *instance)
    146165{
     
    151170        size_t i = 0;
    152171        for (;i < instance->packets; ++i) {
    153                 if (transfer_descriptor_is_active(&instance->tds[i])) {
     172                if (td_is_active(&instance->tds[i])) {
    154173                        return false;
    155174                }
    156                 instance->error = transfer_descriptor_status(&instance->tds[i]);
     175
     176                instance->error = td_status(&instance->tds[i]);
    157177                if (instance->error != EOK) {
     178                        usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
     179                            instance, i, instance->tds[i].status);
     180                        td_print_status(&instance->tds[i]);
     181
     182                        device_keeper_set_toggle(instance->manager,
     183                            instance->target, td_toggle(&instance->tds[i]));
    158184                        if (i > 0)
    159                                 instance->transfered_size -= instance->setup_size;
    160                         usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
    161                           instance, i, instance->tds[i].status);
     185                                goto substract_ret;
    162186                        return true;
    163187                }
    164                 instance->transfered_size +=
    165                     transfer_descriptor_actual_size(&instance->tds[i]);
    166         }
     188
     189                instance->transfered_size += td_act_size(&instance->tds[i]);
     190                if (td_is_short(&instance->tds[i]))
     191                        goto substract_ret;
     192        }
     193substract_ret:
    167194        instance->transfered_size -= instance->setup_size;
    168195        return true;
    169196}
    170197/*----------------------------------------------------------------------------*/
     198/** Prepares control write transaction.
     199 *
     200 * @param[in] instance Batch structure to use.
     201 *
     202 * Uses genercir control function with pids OUT and IN.
     203 */
    171204void batch_control_write(batch_t *instance)
    172205{
    173206        assert(instance);
    174         /* we are data out, we are supposed to provide data */
    175         memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
     207        /* We are data out, we are supposed to provide data */
     208        memcpy(instance->transport_buffer, instance->buffer,
     209            instance->buffer_size);
    176210        batch_control(instance, USB_PID_OUT, USB_PID_IN);
    177211        instance->next_step = batch_call_out_and_dispose;
    178212        usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
    179         batch_schedule(instance);
    180 }
    181 /*----------------------------------------------------------------------------*/
     213}
     214/*----------------------------------------------------------------------------*/
     215/** Prepares control read transaction.
     216 *
     217 * @param[in] instance Batch structure to use.
     218 *
     219 * Uses generic control with pids IN and OUT.
     220 */
    182221void batch_control_read(batch_t *instance)
    183222{
     
    186225        instance->next_step = batch_call_in_and_dispose;
    187226        usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
    188         batch_schedule(instance);
    189 }
    190 /*----------------------------------------------------------------------------*/
     227}
     228/*----------------------------------------------------------------------------*/
     229/** Prepare interrupt in transaction.
     230 *
     231 * @param[in] instance Batch structure to use.
     232 *
     233 * Data transaction with PID_IN.
     234 */
    191235void batch_interrupt_in(batch_t *instance)
    192236{
    193237        assert(instance);
    194 
    195         const bool low_speed = instance->speed == USB_SPEED_LOW;
    196         int toggle = 1;
    197         size_t i = 0;
    198         for (;i < instance->packets; ++i) {
    199                 char *data =
    200                     instance->transport_buffer + (i  * instance->max_packet_size);
    201                 transfer_descriptor_t *next = (i + 1) < instance->packets ?
    202                     &instance->tds[i + 1] : NULL;
    203                 toggle = 1 - toggle;
    204 
    205                 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
    206                     instance->max_packet_size, toggle, false, low_speed,
    207                     instance->target, USB_PID_IN, data, next);
    208         }
    209 
    210         instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
    211 
     238        batch_data(instance, USB_PID_IN);
    212239        instance->next_step = batch_call_in_and_dispose;
    213240        usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
    214         batch_schedule(instance);
    215 }
    216 /*----------------------------------------------------------------------------*/
     241}
     242/*----------------------------------------------------------------------------*/
     243/** Prepare interrupt out transaction.
     244 *
     245 * @param[in] instance Batch structure to use.
     246 *
     247 * Data transaction with PID_OUT.
     248 */
    217249void batch_interrupt_out(batch_t *instance)
    218250{
    219251        assert(instance);
     252        /* We are data out, we are supposed to provide data */
    220253        memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
    221 
    222         const bool low_speed = instance->speed == USB_SPEED_LOW;
    223         int toggle = 1;
    224         size_t i = 0;
    225         for (;i < instance->packets; ++i) {
    226                 char *data =
    227                     instance->transport_buffer + (i  * instance->max_packet_size);
    228                 transfer_descriptor_t *next = (i + 1) < instance->packets ?
    229                     &instance->tds[i + 1] : NULL;
    230                 toggle = 1 - toggle;
    231 
    232                 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
    233                     instance->max_packet_size, toggle++, false, low_speed,
    234                     instance->target, USB_PID_OUT, data, next);
    235         }
    236 
    237         instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
    238 
     254        batch_data(instance, USB_PID_OUT);
    239255        instance->next_step = batch_call_out_and_dispose;
    240256        usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
    241         batch_schedule(instance);
    242 }
    243 /*----------------------------------------------------------------------------*/
    244 static void batch_control(
    245     batch_t *instance, int data_stage, int status_stage)
     257}
     258/*----------------------------------------------------------------------------*/
     259/** Prepare bulk in transaction.
     260 *
     261 * @param[in] instance Batch structure to use.
     262 *
     263 * Data transaction with PID_IN.
     264 */
     265void batch_bulk_in(batch_t *instance)
     266{
     267        assert(instance);
     268        batch_data(instance, USB_PID_IN);
     269        instance->next_step = batch_call_in_and_dispose;
     270        usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
     271}
     272/*----------------------------------------------------------------------------*/
     273/** Prepare bulk out transaction.
     274 *
     275 * @param[in] instance Batch structure to use.
     276 *
     277 * Data transaction with PID_OUT.
     278 */
     279void batch_bulk_out(batch_t *instance)
     280{
     281        assert(instance);
     282        /* We are data out, we are supposed to provide data */
     283        memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
     284        batch_data(instance, USB_PID_OUT);
     285        instance->next_step = batch_call_out_and_dispose;
     286        usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
     287}
     288/*----------------------------------------------------------------------------*/
     289/** Prepare generic data transaction
     290 *
     291 * @param[in] instance Batch structure to use.
     292 * @param[in] pid to use for data packets.
     293 *
     294 * Packets with alternating toggle bit and supplied pid value.
     295 * The last packet is marked with IOC flag.
     296 */
     297void batch_data(batch_t *instance, usb_packet_id pid)
     298{
     299        assert(instance);
     300        const bool low_speed = instance->speed == USB_SPEED_LOW;
     301        int toggle =
     302            device_keeper_get_toggle(instance->manager, instance->target);
     303        assert(toggle == 0 || toggle == 1);
     304
     305        size_t packet = 0;
     306        size_t remain_size = instance->buffer_size;
     307        while (remain_size > 0) {
     308                char *data =
     309                    instance->transport_buffer + instance->buffer_size
     310                    - remain_size;
     311
     312                const size_t packet_size =
     313                    (instance->max_packet_size > remain_size) ?
     314                    remain_size : instance->max_packet_size;
     315
     316                td_t *next_packet = (packet + 1 < instance->packets)
     317                    ? &instance->tds[packet + 1] : NULL;
     318
     319                assert(packet < instance->packets);
     320                assert(packet_size <= remain_size);
     321
     322                td_init(
     323                    &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
     324                    toggle, false, low_speed, instance->target, pid, data,
     325                    next_packet);
     326
     327
     328                toggle = 1 - toggle;
     329                remain_size -= packet_size;
     330                ++packet;
     331        }
     332        td_set_ioc(&instance->tds[packet - 1]);
     333        device_keeper_set_toggle(instance->manager, instance->target, toggle);
     334}
     335/*----------------------------------------------------------------------------*/
     336/** Prepare generic control transaction
     337 *
     338 * @param[in] instance Batch structure to use.
     339 * @param[in] data_stage to use for data packets.
     340 * @param[in] status_stage to use for data packets.
     341 *
     342 * Setup stage with toggle 0 and USB_PID_SETUP.
     343 * Data stage with alternating toggle and pid supplied by parameter.
     344 * Status stage with toggle 1 and pid supplied by parameter.
     345 * The last packet is marked with IOC.
     346 */
     347void batch_control(batch_t *instance,
     348   usb_packet_id data_stage, usb_packet_id status_stage)
    246349{
    247350        assert(instance);
     
    250353        int toggle = 0;
    251354        /* setup stage */
    252         transfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT,
     355        td_init(instance->tds, DEFAULT_ERROR_COUNT,
    253356            instance->setup_size, toggle, false, low_speed, instance->target,
    254357            USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]);
     
    268371                    remain_size : instance->max_packet_size;
    269372
    270                 transfer_descriptor_init(&instance->tds[packet],
    271                     DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,
    272                     instance->target, data_stage, data,
    273                     &instance->tds[packet + 1]);
     373                td_init(
     374                    &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
     375                    toggle, false, low_speed, instance->target, data_stage,
     376                    data, &instance->tds[packet + 1]);
    274377
    275378                ++packet;
     
    281384        /* status stage */
    282385        assert(packet == instance->packets - 1);
    283         transfer_descriptor_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
     386        td_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
    284387            0, 1, false, low_speed, instance->target, status_stage, NULL, NULL);
    285388
    286 
    287         instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
     389        td_set_ioc(&instance->tds[packet]);
    288390        usb_log_debug2("Control last TD status: %x.\n",
    289391            instance->tds[packet].status);
    290392}
    291393/*----------------------------------------------------------------------------*/
     394/** Prepare data, get error status and call callback in.
     395 *
     396 * @param[in] instance Batch structure to use.
     397 * Copies data from transport buffer, and calls callback with appropriate
     398 * parameters.
     399 */
    292400void batch_call_in(batch_t *instance)
    293401{
     
    295403        assert(instance->callback_in);
    296404
    297         memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size);
     405        /* We are data in, we need data */
     406        memcpy(instance->buffer, instance->transport_buffer,
     407            instance->buffer_size);
    298408
    299409        int err = instance->error;
     
    302412            instance->transfered_size);
    303413
    304         instance->callback_in(instance->fun,
    305             err, instance->transfered_size,
    306             instance->arg);
    307 }
    308 /*----------------------------------------------------------------------------*/
     414        instance->callback_in(
     415            instance->fun, err, instance->transfered_size, instance->arg);
     416}
     417/*----------------------------------------------------------------------------*/
     418/** Get error status and call callback out.
     419 *
     420 * @param[in] instance Batch structure to use.
     421 */
    309422void batch_call_out(batch_t *instance)
    310423{
     
    319432}
    320433/*----------------------------------------------------------------------------*/
     434/** Helper function calls callback and correctly disposes of batch structure.
     435 *
     436 * @param[in] instance Batch structure to use.
     437 */
    321438void batch_call_in_and_dispose(batch_t *instance)
    322439{
    323440        assert(instance);
    324441        batch_call_in(instance);
     442        batch_dispose(instance);
     443}
     444/*----------------------------------------------------------------------------*/
     445/** Helper function calls callback and correctly disposes of batch structure.
     446 *
     447 * @param[in] instance Batch structure to use.
     448 */
     449void batch_call_out_and_dispose(batch_t *instance)
     450{
     451        assert(instance);
     452        batch_call_out(instance);
     453        batch_dispose(instance);
     454}
     455/*----------------------------------------------------------------------------*/
     456/** Correctly dispose all used data structures.
     457 *
     458 * @param[in] instance Batch structure to use.
     459 */
     460void batch_dispose(batch_t *instance)
     461{
     462        assert(instance);
    325463        usb_log_debug("Batch(%p) disposing.\n", instance);
     464        /* free32 is NULL safe */
    326465        free32(instance->tds);
    327466        free32(instance->qh);
     
    330469        free(instance);
    331470}
    332 /*----------------------------------------------------------------------------*/
    333 void batch_call_out_and_dispose(batch_t *instance)
    334 {
    335         assert(instance);
    336         batch_call_out(instance);
    337         usb_log_debug("Batch(%p) disposing.\n", instance);
    338         free32(instance->tds);
    339         free32(instance->qh);
    340         free32(instance->setup_buffer);
    341         free32(instance->transport_buffer);
    342         free(instance);
    343 }
    344 /*----------------------------------------------------------------------------*/
    345 int batch_schedule(batch_t *instance)
    346 {
    347         assert(instance);
    348         uhci_t *hc = fun_to_uhci(instance->fun);
    349         assert(hc);
    350         return uhci_schedule(hc, instance);
    351 }
    352471/**
    353472 * @}
Note: See TracChangeset for help on using the changeset viewer.