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


Ignore:
Timestamp:
2011-03-21T14:23:15Z (13 years ago)
Author:
Matej Klonfar <maklf@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
55e388a1
Parents:
c32688d (diff), 48fe0c9 (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 with development

File:
1 edited

Legend:

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

    rc32688d r361e61b  
    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"
     44#include "uhci_struct/transfer_descriptor.h"
    4445
    4546#define DEFAULT_ERROR_COUNT 3
    4647
    47 static int batch_schedule(batch_t *instance);
     48typedef struct uhci_batch {
     49        qh_t *qh;
     50        td_t *tds;
     51        size_t packets;
     52        device_keeper_t *manager;
     53} uhci_batch_t;
    4854
    4955static void batch_control(batch_t *instance,
    5056    usb_packet_id data_stage, usb_packet_id status_stage);
    5157static void batch_data(batch_t *instance, usb_packet_id pid);
    52 static void batch_call_in(batch_t *instance);
    53 static void batch_call_out(batch_t *instance);
    5458static void batch_call_in_and_dispose(batch_t *instance);
    5559static 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
     62/** Allocate memory and initialize internal data structure.
    6063 *
    6164 * @param[in] fun DDF function to pass to callback.
     
    7275 * @param[in] arg additional parameter to func_in or func_out
    7376 * @param[in] manager Pointer to toggle management structure.
    74  * @return False, if there is an active TD, true otherwise.
     77 * @return Valid pointer if all substructures were successfully created,
     78 * NULL otherwise.
     79 *
     80 * Determines the number of needed packets (TDs). Prepares a transport buffer
     81 * (that is accessible by the hardware). Initializes parameters needed for the
     82 * transaction and callback.
    7583 */
    7684batch_t * batch_get(ddf_fun_t *fun, usb_target_t target,
    7785    usb_transfer_type_t transfer_type, size_t max_packet_size,
    78     usb_speed_t speed, char *buffer, size_t size,
     86    usb_speed_t speed, char *buffer, size_t buffer_size,
    7987    char* setup_buffer, size_t setup_size,
    8088    usbhc_iface_transfer_in_callback_t func_in,
     
    98106        CHECK_NULL_DISPOSE_RETURN(instance,
    99107            "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,
     108        batch_init(instance, target, transfer_type, speed, max_packet_size,
     109            buffer, NULL, buffer_size, NULL, setup_size, func_in,
     110            func_out, arg, fun, NULL);
     111
     112
     113        uhci_batch_t *data = malloc(sizeof(uhci_batch_t));
     114        CHECK_NULL_DISPOSE_RETURN(instance,
     115            "Failed to allocate batch instance.\n");
     116        bzero(data, sizeof(uhci_batch_t));
     117        data->manager = manager;
     118        instance->private_data = data;
     119
     120        data->packets = (buffer_size + max_packet_size - 1) / max_packet_size;
     121        if (transfer_type == USB_TRANSFER_CONTROL) {
     122                data->packets += 2;
     123        }
     124
     125        data->tds = malloc32(sizeof(td_t) * data->packets);
     126        CHECK_NULL_DISPOSE_RETURN(
     127            data->tds, "Failed to allocate transfer descriptors.\n");
     128        bzero(data->tds, sizeof(td_t) * data->packets);
     129
     130        data->qh = malloc32(sizeof(qh_t));
     131        CHECK_NULL_DISPOSE_RETURN(data->qh,
    104132            "Failed to allocate batch queue head.\n");
    105         queue_head_init(instance->qh);
    106 
    107         instance->packets = (size + max_packet_size - 1) / max_packet_size;
    108         if (transfer_type == USB_TRANSFER_CONTROL) {
    109                 instance->packets += 2;
    110         }
    111 
    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);
     133        qh_init(data->qh);
     134        qh_set_element_td(data->qh, addr_to_phys(data->tds));
     135
     136        if (buffer_size > 0) {
     137                instance->transport_buffer = malloc32(buffer_size);
    121138                CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer,
    122139                    "Failed to allocate device accessible buffer.\n");
     
    130147        }
    131148
    132 
    133         link_initialize(&instance->link);
    134 
    135         instance->max_packet_size = max_packet_size;
    136         instance->target = target;
    137         instance->transfer_type = transfer_type;
    138         instance->buffer = buffer;
    139         instance->buffer_size = size;
    140         instance->setup_size = setup_size;
    141         instance->fun = fun;
    142         instance->arg = arg;
    143         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 
    153149        usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
    154150            instance, target.address, target.endpoint);
     
    156152}
    157153/*----------------------------------------------------------------------------*/
    158 /** Checks batch TDs for activity.
     154/** Check batch TDs for activity.
    159155 *
    160156 * @param[in] instance Batch structure to use.
    161157 * @return False, if there is an active TD, true otherwise.
     158 *
     159 * Walk all TDs. Stop with false if there is an active one (it is to be
     160 * processed). Stop with true if an error is found. Return true if the last TS
     161 * is reached.
    162162 */
    163163bool batch_is_complete(batch_t *instance)
    164164{
    165165        assert(instance);
     166        uhci_batch_t *data = instance->private_data;
     167        assert(data);
     168
    166169        usb_log_debug2("Batch(%p) checking %d packet(s) for completion.\n",
    167             instance, instance->packets);
     170            instance, data->packets);
    168171        instance->transfered_size = 0;
    169172        size_t i = 0;
    170         for (;i < instance->packets; ++i) {
    171                 if (td_is_active(&instance->tds[i])) {
     173        for (;i < data->packets; ++i) {
     174                if (td_is_active(&data->tds[i])) {
    172175                        return false;
    173176                }
    174177
    175                 instance->error = td_status(&instance->tds[i]);
     178                instance->error = td_status(&data->tds[i]);
    176179                if (instance->error != EOK) {
    177180                        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]));
     181                            instance, i, data->tds[i].status);
     182                        td_print_status(&data->tds[i]);
     183
     184                        device_keeper_set_toggle(data->manager,
     185                            instance->target, instance->direction,
     186                            td_toggle(&data->tds[i]));
    182187                        if (i > 0)
    183188                                goto substract_ret;
     
    185190                }
    186191
    187                 instance->transfered_size += td_act_size(&instance->tds[i]);
    188                 if (td_is_short(&instance->tds[i]))
     192                instance->transfered_size += td_act_size(&data->tds[i]);
     193                if (td_is_short(&data->tds[i]))
    189194                        goto substract_ret;
    190195        }
     
    197202 *
    198203 * @param[in] instance Batch structure to use.
     204 *
     205 * Uses genercir control function with pids OUT and IN.
    199206 */
    200207void batch_control_write(batch_t *instance)
    201208{
    202209        assert(instance);
    203         /* we are data out, we are supposed to provide data */
     210        /* We are data out, we are supposed to provide data */
    204211        memcpy(instance->transport_buffer, instance->buffer,
    205212            instance->buffer_size);
     
    207214        instance->next_step = batch_call_out_and_dispose;
    208215        usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
    209         batch_schedule(instance);
    210216}
    211217/*----------------------------------------------------------------------------*/
     
    213219 *
    214220 * @param[in] instance Batch structure to use.
     221 *
     222 * Uses generic control with pids IN and OUT.
    215223 */
    216224void batch_control_read(batch_t *instance)
     
    220228        instance->next_step = batch_call_in_and_dispose;
    221229        usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
    222         batch_schedule(instance);
    223 }
    224 /*----------------------------------------------------------------------------*/
    225 /** Prepares interrupt in transaction.
    226  *
    227  * @param[in] instance Batch structure to use.
     230}
     231/*----------------------------------------------------------------------------*/
     232/** Prepare interrupt in transaction.
     233 *
     234 * @param[in] instance Batch structure to use.
     235 *
     236 * Data transaction with PID_IN.
    228237 */
    229238void batch_interrupt_in(batch_t *instance)
    230239{
    231240        assert(instance);
     241        instance->direction = USB_DIRECTION_IN;
    232242        batch_data(instance, USB_PID_IN);
    233243        instance->next_step = batch_call_in_and_dispose;
    234244        usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
    235         batch_schedule(instance);
    236 }
    237 /*----------------------------------------------------------------------------*/
    238 /** Prepares interrupt out transaction.
    239  *
    240  * @param[in] instance Batch structure to use.
     245}
     246/*----------------------------------------------------------------------------*/
     247/** Prepare interrupt out transaction.
     248 *
     249 * @param[in] instance Batch structure to use.
     250 *
     251 * Data transaction with PID_OUT.
    241252 */
    242253void batch_interrupt_out(batch_t *instance)
    243254{
    244255        assert(instance);
    245         /* we are data out, we are supposed to provide data */
    246         memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
     256        instance->direction = USB_DIRECTION_OUT;
     257        /* We are data out, we are supposed to provide data */
     258        memcpy(instance->transport_buffer, instance->buffer,
     259            instance->buffer_size);
    247260        batch_data(instance, USB_PID_OUT);
    248261        instance->next_step = batch_call_out_and_dispose;
    249262        usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
    250         batch_schedule(instance);
    251 }
    252 /*----------------------------------------------------------------------------*/
    253 /** Prepares bulk in transaction.
    254  *
    255  * @param[in] instance Batch structure to use.
     263}
     264/*----------------------------------------------------------------------------*/
     265/** Prepare bulk in transaction.
     266 *
     267 * @param[in] instance Batch structure to use.
     268 *
     269 * Data transaction with PID_IN.
    256270 */
    257271void batch_bulk_in(batch_t *instance)
     
    259273        assert(instance);
    260274        batch_data(instance, USB_PID_IN);
     275        instance->direction = USB_DIRECTION_IN;
    261276        instance->next_step = batch_call_in_and_dispose;
    262277        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.
     278}
     279/*----------------------------------------------------------------------------*/
     280/** Prepare bulk out transaction.
     281 *
     282 * @param[in] instance Batch structure to use.
     283 *
     284 * Data transaction with PID_OUT.
    269285 */
    270286void batch_bulk_out(batch_t *instance)
    271287{
    272288        assert(instance);
    273         memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
     289        instance->direction = USB_DIRECTION_OUT;
     290        /* We are data out, we are supposed to provide data */
     291        memcpy(instance->transport_buffer, instance->buffer,
     292            instance->buffer_size);
    274293        batch_data(instance, USB_PID_OUT);
    275294        instance->next_step = batch_call_out_and_dispose;
    276295        usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
    277         batch_schedule(instance);
    278 }
    279 /*----------------------------------------------------------------------------*/
    280 /** Prepares generic data transaction
     296}
     297/*----------------------------------------------------------------------------*/
     298/** Prepare generic data transaction
    281299 *
    282300 * @param[in] instance Batch structure to use.
    283301 * @param[in] pid to use for data packets.
     302 *
     303 * Packets with alternating toggle bit and supplied pid value.
     304 * The last packet is marked with IOC flag.
    284305 */
    285306void batch_data(batch_t *instance, usb_packet_id pid)
    286307{
    287308        assert(instance);
     309        uhci_batch_t *data = instance->private_data;
     310        assert(data);
     311
    288312        const bool low_speed = instance->speed == USB_SPEED_LOW;
    289         int toggle =
    290             device_keeper_get_toggle(instance->manager, instance->target);
     313        int toggle = device_keeper_get_toggle(
     314            data->manager, instance->target, instance->direction);
    291315        assert(toggle == 0 || toggle == 1);
    292316
     
    294318        size_t remain_size = instance->buffer_size;
    295319        while (remain_size > 0) {
    296                 char *data =
     320                char *trans_data =
    297321                    instance->transport_buffer + instance->buffer_size
    298322                    - remain_size;
     
    302326                    remain_size : instance->max_packet_size;
    303327
    304                 td_t *next_packet = (packet + 1 < instance->packets)
    305                     ? &instance->tds[packet + 1] : NULL;
    306 
    307                 assert(packet < instance->packets);
     328                td_t *next_packet = (packet + 1 < data->packets)
     329                    ? &data->tds[packet + 1] : NULL;
     330
     331                assert(packet < data->packets);
    308332                assert(packet_size <= remain_size);
    309333
    310334                td_init(
    311                     &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
    312                     toggle, false, low_speed, instance->target, pid, data,
     335                    &data->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
     336                    toggle, false, low_speed, instance->target, pid, trans_data,
    313337                    next_packet);
    314338
     
    318342                ++packet;
    319343        }
    320         device_keeper_set_toggle(instance->manager, instance->target, toggle);
    321 }
    322 /*----------------------------------------------------------------------------*/
    323 /** Prepares generic control transaction
     344        td_set_ioc(&data->tds[packet - 1]);
     345        device_keeper_set_toggle(data->manager, instance->target,
     346            instance->direction, toggle);
     347}
     348/*----------------------------------------------------------------------------*/
     349/** Prepare generic control transaction
    324350 *
    325351 * @param[in] instance Batch structure to use.
    326352 * @param[in] data_stage to use for data packets.
    327353 * @param[in] status_stage to use for data packets.
     354 *
     355 * Setup stage with toggle 0 and USB_PID_SETUP.
     356 * Data stage with alternating toggle and pid supplied by parameter.
     357 * Status stage with toggle 1 and pid supplied by parameter.
     358 * The last packet is marked with IOC.
    328359 */
    329360void batch_control(batch_t *instance,
     
    331362{
    332363        assert(instance);
     364        uhci_batch_t *data = instance->private_data;
     365        assert(data);
     366        assert(data->packets >= 2);
    333367
    334368        const bool low_speed = instance->speed == USB_SPEED_LOW;
    335369        int toggle = 0;
    336370        /* 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]);
     371        td_init(
     372            data->tds, DEFAULT_ERROR_COUNT, instance->setup_size, toggle, false,
     373            low_speed, instance->target, USB_PID_SETUP, instance->setup_buffer,
     374            &data->tds[1]);
    340375
    341376        /* data stage */
     
    343378        size_t remain_size = instance->buffer_size;
    344379        while (remain_size > 0) {
    345                 char *data =
     380                char *control_data =
    346381                    instance->transport_buffer + instance->buffer_size
    347382                    - remain_size;
     
    354389
    355390                td_init(
    356                     &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
     391                    &data->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
    357392                    toggle, false, low_speed, instance->target, data_stage,
    358                     data, &instance->tds[packet + 1]);
     393                    control_data, &data->tds[packet + 1]);
    359394
    360395                ++packet;
    361                 assert(packet < instance->packets);
     396                assert(packet < data->packets);
    362397                assert(packet_size <= remain_size);
    363398                remain_size -= packet_size;
     
    365400
    366401        /* 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;
     402        assert(packet == data->packets - 1);
     403
     404        td_init(
     405            &data->tds[packet], DEFAULT_ERROR_COUNT, 0, 1, false, low_speed,
     406            instance->target, status_stage, NULL, NULL);
     407        td_set_ioc(&data->tds[packet]);
     408
    373409        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  */
    381 void batch_call_in(batch_t *instance)
    382 {
    383         assert(instance);
    384         assert(instance->callback_in);
    385 
    386         /* we are data in, we need data */
    387         memcpy(instance->buffer, instance->transport_buffer,
    388             instance->buffer_size);
    389 
    390         int err = instance->error;
    391         usb_log_debug("Batch(%p) callback IN(type:%d): %s(%d), %zu.\n",
    392             instance, instance->transfer_type, str_error(err), err,
    393             instance->transfered_size);
    394 
    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  */
    403 void batch_call_out(batch_t *instance)
    404 {
    405         assert(instance);
    406         assert(instance->callback_out);
    407 
    408         int err = instance->error;
    409         usb_log_debug("Batch(%p) callback OUT(type:%d): %s(%d).\n",
    410             instance, instance->transfer_type, str_error(err), err);
    411         instance->callback_out(instance->fun,
    412             err, instance->arg);
    413 }
    414 /*----------------------------------------------------------------------------*/
    415 /** Prepares data, gets error status, calls callback in and dispose.
     410            data->tds[packet].status);
     411}
     412/*----------------------------------------------------------------------------*/
     413qh_t * batch_qh(batch_t *instance)
     414{
     415        assert(instance);
     416        uhci_batch_t *data = instance->private_data;
     417        assert(data);
     418        return data->qh;
     419}
     420/*----------------------------------------------------------------------------*/
     421/** Helper function calls callback and correctly disposes of batch structure.
    416422 *
    417423 * @param[in] instance Batch structure to use.
     
    424430}
    425431/*----------------------------------------------------------------------------*/
    426 /** Gets error status, calls callback out and dispose.
     432/** Helper function calls callback and correctly disposes of batch structure.
    427433 *
    428434 * @param[in] instance Batch structure to use.
     
    435441}
    436442/*----------------------------------------------------------------------------*/
    437 /** Correctly disposes all used data structures.
     443/** Correctly dispose all used data structures.
    438444 *
    439445 * @param[in] instance Batch structure to use.
     
    442448{
    443449        assert(instance);
     450        uhci_batch_t *data = instance->private_data;
     451        assert(data);
    444452        usb_log_debug("Batch(%p) disposing.\n", instance);
    445453        /* free32 is NULL safe */
    446         free32(instance->tds);
    447         free32(instance->qh);
     454        free32(data->tds);
     455        free32(data->qh);
    448456        free32(instance->setup_buffer);
    449457        free32(instance->transport_buffer);
     458        free(data);
    450459        free(instance);
    451 }
    452 /*----------------------------------------------------------------------------*/
    453 int batch_schedule(batch_t *instance)
    454 {
    455         assert(instance);
    456         uhci_t *hc = fun_to_uhci(instance->fun);
    457         assert(hc);
    458         return uhci_schedule(hc, instance);
    459460}
    460461/**
Note: See TracChangeset for help on using the changeset viewer.