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


Ignore:
Timestamp:
2011-03-16T18:50:17Z (15 years ago)
Author:
Matus Dekanek <smekideki@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/fix-logger-deadlock, 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

Location:
uspace/drv/uhci-hcd
Files:
2 added
1 deleted
19 edited
2 moved

Legend:

Unmodified
Added
Removed
  • uspace/drv/uhci-hcd/Makefile

    r3e7b7cd r72af8da  
    3535        iface.c \
    3636        main.c \
    37         root_hub.c \
    3837        transfer_list.c \
    3938        uhci.c \
     39        uhci_hc.c \
     40        uhci_rh.c \
    4041        uhci_struct/transfer_descriptor.c \
    4142        utils/device_keeper.c \
  • 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 * @}
  • uspace/drv/uhci-hcd/batch.h

    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#ifndef DRV_UHCI_BATCH_H
     
    4242#include "uhci_struct/transfer_descriptor.h"
    4343#include "uhci_struct/queue_head.h"
     44#include "utils/device_keeper.h"
    4445
    4546typedef struct batch
     
    4950        usb_target_t target;
    5051        usb_transfer_type_t transfer_type;
    51         union {
    52                 usbhc_iface_transfer_in_callback_t callback_in;
    53                 usbhc_iface_transfer_out_callback_t callback_out;
    54         };
     52        usbhc_iface_transfer_in_callback_t callback_in;
     53        usbhc_iface_transfer_out_callback_t callback_out;
    5554        void *arg;
    5655        char *transport_buffer;
     
    6463        int error;
    6564        ddf_fun_t *fun;
    66         queue_head_t *qh;
    67         transfer_descriptor_t *tds;
     65        qh_t *qh;
     66        td_t *tds;
    6867        void (*next_step)(struct batch*);
     68        device_keeper_t *manager;
    6969} batch_t;
    7070
     
    7474                char *setup_buffer, size_t setup_size,
    7575    usbhc_iface_transfer_in_callback_t func_in,
    76     usbhc_iface_transfer_out_callback_t func_out, void *arg);
     76    usbhc_iface_transfer_out_callback_t func_out, void *arg,
     77                device_keeper_t *manager
     78                );
     79
     80void batch_dispose(batch_t *instance);
    7781
    7882bool batch_is_complete(batch_t *instance);
     
    8690void batch_interrupt_out(batch_t *instance);
    8791
    88 /* DEPRECATED FUNCTIONS NEEDED BY THE OLD API */
    89 void batch_control_setup_old(batch_t *instance);
     92void batch_bulk_in(batch_t *instance);
    9093
    91 void batch_control_write_data_old(batch_t *instance);
    92 
    93 void batch_control_read_data_old(batch_t *instance);
    94 
    95 void batch_control_write_status_old(batch_t *instance);
    96 
    97 void batch_control_read_status_old(batch_t *instance);
     94void batch_bulk_out(batch_t *instance);
    9895#endif
    9996/**
  • uspace/drv/uhci-hcd/iface.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 hc interface implementation
    3333 */
    3434#include <ddf/driver.h>
     
    4040
    4141#include "iface.h"
    42 #include "uhci.h"
     42#include "uhci_hc.h"
    4343#include "utils/device_keeper.h"
    4444
     45/** Reserve default address interface function
     46 *
     47 * @param[in] fun DDF function that was called.
     48 * @param[in] speed Speed to associate with the new default address.
     49 * @return Error code.
     50 */
    4551/*----------------------------------------------------------------------------*/
    4652static int reserve_default_address(ddf_fun_t *fun, usb_speed_t speed)
    4753{
    4854        assert(fun);
    49         uhci_t *hc = fun_to_uhci(fun);
     55        uhci_hc_t *hc = fun_to_uhci_hc(fun);
    5056        assert(hc);
    5157        usb_log_debug("Default address request with speed %d.\n", speed);
     
    5460}
    5561/*----------------------------------------------------------------------------*/
     62/** Release default address interface function
     63 *
     64 * @param[in] fun DDF function that was called.
     65 * @return Error code.
     66 */
    5667static int release_default_address(ddf_fun_t *fun)
    5768{
    5869        assert(fun);
    59         uhci_t *hc = fun_to_uhci(fun);
     70        uhci_hc_t *hc = fun_to_uhci_hc(fun);
    6071        assert(hc);
    6172        usb_log_debug("Default address release.\n");
     
    6475}
    6576/*----------------------------------------------------------------------------*/
     77/** Request address interface function
     78 *
     79 * @param[in] fun DDF function that was called.
     80 * @param[in] speed Speed to associate with the new default address.
     81 * @param[out] address Place to write a new address.
     82 * @return Error code.
     83 */
    6684static int request_address(ddf_fun_t *fun, usb_speed_t speed,
    6785    usb_address_t *address)
    6886{
    6987        assert(fun);
    70         uhci_t *hc = fun_to_uhci(fun);
     88        uhci_hc_t *hc = fun_to_uhci_hc(fun);
    7189        assert(hc);
    7290        assert(address);
     
    8098}
    8199/*----------------------------------------------------------------------------*/
     100/** Bind address interface function
     101 *
     102 * @param[in] fun DDF function that was called.
     103 * @param[in] address Address of the device
     104 * @param[in] handle Devman handle of the device driver.
     105 * @return Error code.
     106 */
    82107static int bind_address(
    83108  ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
    84109{
    85110        assert(fun);
    86         uhci_t *hc = fun_to_uhci(fun);
     111        uhci_hc_t *hc = fun_to_uhci_hc(fun);
    87112        assert(hc);
    88113        usb_log_debug("Address bind %d-%d.\n", address, handle);
     
    91116}
    92117/*----------------------------------------------------------------------------*/
     118/** Release address interface function
     119 *
     120 * @param[in] fun DDF function that was called.
     121 * @param[in] address USB address to be released.
     122 * @return Error code.
     123 */
    93124static int release_address(ddf_fun_t *fun, usb_address_t address)
    94125{
    95126        assert(fun);
    96         uhci_t *hc = fun_to_uhci(fun);
     127        uhci_hc_t *hc = fun_to_uhci_hc(fun);
    97128        assert(hc);
    98129        usb_log_debug("Address release %d.\n", address);
     
    101132}
    102133/*----------------------------------------------------------------------------*/
     134/** Interrupt out transaction interface function
     135 *
     136 * @param[in] fun DDF function that was called.
     137 * @param[in] target USB device to write to.
     138 * @param[in] max_packet_size maximum size of data packet the device accepts
     139 * @param[in] data Source of data.
     140 * @param[in] size Size of data source.
     141 * @param[in] callback Function to call on transaction completion
     142 * @param[in] arg Additional for callback function.
     143 * @return Error code.
     144 */
    103145static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
    104146    size_t max_packet_size, void *data, size_t size,
     
    106148{
    107149        assert(fun);
    108         uhci_t *hc = fun_to_uhci(fun);
     150        uhci_hc_t *hc = fun_to_uhci_hc(fun);
    109151        assert(hc);
    110152        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     
    114156
    115157        batch_t *batch = batch_get(fun, target, USB_TRANSFER_INTERRUPT,
    116             max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg);
     158            max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg,
     159            &hc->device_manager);
    117160        if (!batch)
    118161                return ENOMEM;
    119162        batch_interrupt_out(batch);
    120         return EOK;
    121 }
    122 /*----------------------------------------------------------------------------*/
     163        const int ret = uhci_hc_schedule(hc, batch);
     164        if (ret != EOK) {
     165                batch_dispose(batch);
     166                return ret;
     167        }
     168        return EOK;
     169}
     170/*----------------------------------------------------------------------------*/
     171/** Interrupt in transaction interface function
     172 *
     173 * @param[in] fun DDF function that was called.
     174 * @param[in] target USB device to write to.
     175 * @param[in] max_packet_size maximum size of data packet the device accepts
     176 * @param[out] data Data destination.
     177 * @param[in] size Size of data source.
     178 * @param[in] callback Function to call on transaction completion
     179 * @param[in] arg Additional for callback function.
     180 * @return Error code.
     181 */
    123182static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
    124183    size_t max_packet_size, void *data, size_t size,
     
    126185{
    127186        assert(fun);
    128         uhci_t *hc = fun_to_uhci(fun);
     187        uhci_hc_t *hc = fun_to_uhci_hc(fun);
    129188        assert(hc);
    130189        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     
    133192
    134193        batch_t *batch = batch_get(fun, target, USB_TRANSFER_INTERRUPT,
    135             max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg);
     194            max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg,
     195                        &hc->device_manager);
    136196        if (!batch)
    137197                return ENOMEM;
    138198        batch_interrupt_in(batch);
    139         return EOK;
    140 }
    141 /*----------------------------------------------------------------------------*/
     199        const int ret = uhci_hc_schedule(hc, batch);
     200        if (ret != EOK) {
     201                batch_dispose(batch);
     202                return ret;
     203        }
     204        return EOK;
     205}
     206/*----------------------------------------------------------------------------*/
     207/** Bulk out transaction interface function
     208 *
     209 * @param[in] fun DDF function that was called.
     210 * @param[in] target USB device to write to.
     211 * @param[in] max_packet_size maximum size of data packet the device accepts
     212 * @param[in] data Source of data.
     213 * @param[in] size Size of data source.
     214 * @param[in] callback Function to call on transaction completion
     215 * @param[in] arg Additional for callback function.
     216 * @return Error code.
     217 */
     218static int bulk_out(ddf_fun_t *fun, usb_target_t target,
     219    size_t max_packet_size, void *data, size_t size,
     220    usbhc_iface_transfer_out_callback_t callback, void *arg)
     221{
     222        assert(fun);
     223        uhci_hc_t *hc = fun_to_uhci_hc(fun);
     224        assert(hc);
     225        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     226
     227        usb_log_debug("Bulk OUT %d:%d %zu(%zu).\n",
     228            target.address, target.endpoint, size, max_packet_size);
     229
     230        batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK,
     231            max_packet_size, speed, data, size, NULL, 0, NULL, callback, arg,
     232            &hc->device_manager);
     233        if (!batch)
     234                return ENOMEM;
     235        batch_bulk_out(batch);
     236        const int ret = uhci_hc_schedule(hc, batch);
     237        if (ret != EOK) {
     238                batch_dispose(batch);
     239                return ret;
     240        }
     241        return EOK;
     242}
     243/*----------------------------------------------------------------------------*/
     244/** Bulk in transaction interface function
     245 *
     246 * @param[in] fun DDF function that was called.
     247 * @param[in] target USB device to write to.
     248 * @param[in] max_packet_size maximum size of data packet the device accepts
     249 * @param[out] data Data destination.
     250 * @param[in] size Size of data source.
     251 * @param[in] callback Function to call on transaction completion
     252 * @param[in] arg Additional for callback function.
     253 * @return Error code.
     254 */
     255static int bulk_in(ddf_fun_t *fun, usb_target_t target,
     256    size_t max_packet_size, void *data, size_t size,
     257    usbhc_iface_transfer_in_callback_t callback, void *arg)
     258{
     259        assert(fun);
     260        uhci_hc_t *hc = fun_to_uhci_hc(fun);
     261        assert(hc);
     262        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     263        usb_log_debug("Bulk IN %d:%d %zu(%zu).\n",
     264            target.address, target.endpoint, size, max_packet_size);
     265
     266        batch_t *batch = batch_get(fun, target, USB_TRANSFER_BULK,
     267            max_packet_size, speed, data, size, NULL, 0, callback, NULL, arg,
     268            &hc->device_manager);
     269        if (!batch)
     270                return ENOMEM;
     271        batch_bulk_in(batch);
     272        const int ret = uhci_hc_schedule(hc, batch);
     273        if (ret != EOK) {
     274                batch_dispose(batch);
     275                return ret;
     276        }
     277        return EOK;
     278}
     279/*----------------------------------------------------------------------------*/
     280/** Control write transaction interface function
     281 *
     282 * @param[in] fun DDF function that was called.
     283 * @param[in] target USB device to write to.
     284 * @param[in] max_packet_size maximum size of data packet the device accepts.
     285 * @param[in] setup_data Data to send with SETUP packet.
     286 * @param[in] setup_size Size of data to send with SETUP packet (should be 8B).
     287 * @param[in] data Source of data.
     288 * @param[in] size Size of data source.
     289 * @param[in] callback Function to call on transaction completion.
     290 * @param[in] arg Additional for callback function.
     291 * @return Error code.
     292 */
    142293static int control_write(ddf_fun_t *fun, usb_target_t target,
    143294    size_t max_packet_size,
     
    146297{
    147298        assert(fun);
    148         uhci_t *hc = fun_to_uhci(fun);
    149         assert(hc);
    150         usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
    151         usb_log_debug("Control WRITE %d:%d %zu(%zu).\n",
    152             target.address, target.endpoint, size, max_packet_size);
     299        uhci_hc_t *hc = fun_to_uhci_hc(fun);
     300        assert(hc);
     301        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     302        usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n",
     303            speed, target.address, target.endpoint, size, max_packet_size);
     304
     305        if (setup_size != 8)
     306                return EINVAL;
    153307
    154308        batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL,
    155309            max_packet_size, speed, data, size, setup_data, setup_size,
    156             NULL, callback, arg);
    157         if (!batch)
    158                 return ENOMEM;
     310            NULL, callback, arg, &hc->device_manager);
     311        if (!batch)
     312                return ENOMEM;
     313        device_keeper_reset_if_need(&hc->device_manager, target, setup_data);
    159314        batch_control_write(batch);
    160         return EOK;
    161 }
    162 /*----------------------------------------------------------------------------*/
     315        const int ret = uhci_hc_schedule(hc, batch);
     316        if (ret != EOK) {
     317                batch_dispose(batch);
     318                return ret;
     319        }
     320        return EOK;
     321}
     322/*----------------------------------------------------------------------------*/
     323/** Control read transaction interface function
     324 *
     325 * @param[in] fun DDF function that was called.
     326 * @param[in] target USB device to write to.
     327 * @param[in] max_packet_size maximum size of data packet the device accepts.
     328 * @param[in] setup_data Data to send with SETUP packet.
     329 * @param[in] setup_size Size of data to send with SETUP packet (should be 8B).
     330 * @param[out] data Source of data.
     331 * @param[in] size Size of data source.
     332 * @param[in] callback Function to call on transaction completion.
     333 * @param[in] arg Additional for callback function.
     334 * @return Error code.
     335 */
    163336static int control_read(ddf_fun_t *fun, usb_target_t target,
    164337    size_t max_packet_size,
     
    167340{
    168341        assert(fun);
    169         uhci_t *hc = fun_to_uhci(fun);
    170         assert(hc);
    171         usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
    172 
    173         usb_log_debug("Control READ %d:%d %zu(%zu).\n",
    174             target.address, target.endpoint, size, max_packet_size);
     342        uhci_hc_t *hc = fun_to_uhci_hc(fun);
     343        assert(hc);
     344        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     345
     346        usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n",
     347            speed, target.address, target.endpoint, size, max_packet_size);
    175348        batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL,
    176349            max_packet_size, speed, data, size, setup_data, setup_size, callback,
    177             NULL, arg);
     350            NULL, arg, &hc->device_manager);
    178351        if (!batch)
    179352                return ENOMEM;
    180353        batch_control_read(batch);
    181         return EOK;
    182 }
    183 
    184 
    185 /*----------------------------------------------------------------------------*/
    186 usbhc_iface_t uhci_iface = {
     354        const int ret = uhci_hc_schedule(hc, batch);
     355        if (ret != EOK) {
     356                batch_dispose(batch);
     357                return ret;
     358        }
     359        return EOK;
     360}
     361/*----------------------------------------------------------------------------*/
     362usbhc_iface_t uhci_hc_iface = {
    187363        .reserve_default_address = reserve_default_address,
    188364        .release_default_address = release_default_address,
     
    194370        .interrupt_in = interrupt_in,
    195371
     372        .bulk_in = bulk_in,
     373        .bulk_out = bulk_out,
     374
    196375        .control_read = control_read,
    197376        .control_write = control_write,
  • uspace/drv/uhci-hcd/iface.h

    r3e7b7cd r72af8da  
    2727 */
    2828
    29 /** @addtogroup usb
     29/** @addtogroup drvusbuhcihc
    3030 * @{
    3131 */
    3232/** @file
    33  * @brief UHCI driver
     33 * @brief UHCI driver iface
    3434 */
    3535#ifndef DRV_UHCI_IFACE_H
     
    3838#include <usbhc_iface.h>
    3939
    40 extern usbhc_iface_t uhci_iface;
     40extern usbhc_iface_t uhci_hc_iface;
    4141
    4242#endif
  • uspace/drv/uhci-hcd/main.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 initialization
    3333 */
    3434#include <ddf/driver.h>
    35 #include <ddf/interrupt.h>
    36 #include <device/hw_res.h>
    3735#include <errno.h>
    3836#include <str_error.h>
    3937
    40 #include <usb_iface.h>
    4138#include <usb/ddfiface.h>
    4239#include <usb/debug.h>
    4340
    4441#include "iface.h"
    45 #include "pci.h"
    46 #include "root_hub.h"
    4742#include "uhci.h"
    4843
     
    6055};
    6156/*----------------------------------------------------------------------------*/
    62 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
     57/** Initialize a new ddf driver instance for uhci hc and hub.
     58 *
     59 * @param[in] device DDF instance of the device to initialize.
     60 * @return Error code.
     61 */
     62int uhci_add_device(ddf_dev_t *device)
    6363{
    64         assert(dev);
    65         uhci_t *hc = dev_to_uhci(dev);
    66         uint16_t status = IPC_GET_ARG1(*call);
    67         assert(hc);
    68         uhci_interrupt(hc, status);
     64        usb_log_info("uhci_add_device() called\n");
     65        assert(device);
     66        uhci_t *uhci = malloc(sizeof(uhci_t));
     67        if (uhci == NULL) {
     68                usb_log_error("Failed to allocate UHCI driver.\n");
     69                return ENOMEM;
     70        }
     71
     72        int ret = uhci_init(uhci, device);
     73        if (ret != EOK) {
     74                usb_log_error("Failed to initialzie UHCI driver.\n");
     75                return ret;
     76        }
     77        device->driver_data = uhci;
     78        return EOK;
    6979}
    7080/*----------------------------------------------------------------------------*/
    71 static int uhci_add_device(ddf_dev_t *device)
    72 {
    73         assert(device);
    74         uhci_t *hcd = NULL;
    75 #define CHECK_RET_FREE_HC_RETURN(ret, message...) \
    76 if (ret != EOK) { \
    77         usb_log_error(message); \
    78         if (hcd != NULL) \
    79                 free(hcd); \
    80         return ret; \
    81 }
    82 
    83         usb_log_info("uhci_add_device() called\n");
    84 
    85         uintptr_t io_reg_base = 0;
    86         size_t io_reg_size = 0;
    87         int irq = 0;
    88 
    89         int ret =
    90             pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq);
    91         CHECK_RET_FREE_HC_RETURN(ret,
    92             "Failed(%d) to get I/O addresses:.\n", ret, device->handle);
    93         usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n",
    94             io_reg_base, io_reg_size, irq);
    95 
    96         ret = pci_disable_legacy(device);
    97         CHECK_RET_FREE_HC_RETURN(ret,
    98             "Failed(%d) disable legacy USB: %s.\n", ret, str_error(ret));
    99 
    100 #if 0
    101         ret = pci_enable_interrupts(device);
    102         if (ret != EOK) {
    103                 usb_log_warning(
    104                     "Failed(%d) to enable interrupts, fall back to polling.\n",
    105                     ret);
    106         }
    107 #endif
    108 
    109         hcd = malloc(sizeof(uhci_t));
    110         ret = (hcd != NULL) ? EOK : ENOMEM;
    111         CHECK_RET_FREE_HC_RETURN(ret,
    112             "Failed(%d) to allocate memory for uhci hcd.\n", ret);
    113 
    114         ret = uhci_init(hcd, device, (void*)io_reg_base, io_reg_size);
    115         CHECK_RET_FREE_HC_RETURN(ret, "Failed(%d) to init uhci-hcd.\n",
    116             ret);
    117 #undef CHECK_RET_FREE_HC_RETURN
    118 
    119         /*
    120          * We might free hcd, but that does not matter since no one
    121          * else would access driver_data anyway.
    122          */
    123         device->driver_data = hcd;
    124 
    125         ddf_fun_t *rh = NULL;
    126 #define CHECK_RET_FINI_FREE_RETURN(ret, message...) \
    127 if (ret != EOK) { \
    128         usb_log_error(message); \
    129         if (hcd != NULL) {\
    130                 uhci_fini(hcd); \
    131                 free(hcd); \
    132         } \
    133         if (rh != NULL) \
    134                 free(rh); \
    135         return ret; \
    136 }
    137 
    138         /* It does no harm if we register this on polling */
    139         ret = register_interrupt_handler(device, irq, irq_handler,
    140             &hcd->interrupt_code);
    141         CHECK_RET_FINI_FREE_RETURN(ret,
    142             "Failed(%d) to register interrupt handler.\n", ret);
    143 
    144         ret = setup_root_hub(&rh, device);
    145         CHECK_RET_FINI_FREE_RETURN(ret,
    146             "Failed(%d) to setup UHCI root hub.\n", ret);
    147         rh->driver_data = hcd->ddf_instance;
    148 
    149         ret = ddf_fun_bind(rh);
    150         CHECK_RET_FINI_FREE_RETURN(ret,
    151             "Failed(%d) to register UHCI root hub.\n", ret);
    152 
    153         return EOK;
    154 #undef CHECK_RET_FINI_FREE_RETURN
    155 }
    156 /*----------------------------------------------------------------------------*/
     81/** Initialize global driver structures (NONE).
     82 *
     83 * @param[in] argc Nmber of arguments in argv vector (ignored).
     84 * @param[in] argv Cmdline argument vector (ignored).
     85 * @return Error code.
     86 *
     87 * Driver debug level is set here.
     88 */
    15789int main(int argc, char *argv[])
    15890{
    159         sleep(3);
     91        sleep(3); /* TODO: remove in final version */
    16092        usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
    16193
  • uspace/drv/uhci-hcd/pci.c

    r3e7b7cd r72af8da  
    2727 */
    2828/**
    29  * @addtogroup drvusbuhci
     29 * @addtogroup drvusbuhcihc
    3030 * @{
    3131 */
     
    6565
    6666        int rc;
    67 
    6867        hw_resource_list_t hw_resources;
    6968        rc = hw_res_get_resource_list(parent_phone, &hw_resources);
     
    8281        for (i = 0; i < hw_resources.count; i++) {
    8382                hw_resource_t *res = &hw_resources.resources[i];
    84                 switch (res->type) {
    85                         case INTERRUPT:
    86                                 irq = res->res.interrupt.irq;
    87                                 irq_found = true;
    88                                 usb_log_debug2("Found interrupt: %d.\n", irq);
    89                                 break;
    90                         case IO_RANGE:
    91                                 io_address = res->res.io_range.address;
    92                                 io_size = res->res.io_range.size;
    93                                 usb_log_debug2("Found io: %llx %zu.\n",
    94                                     res->res.io_range.address, res->res.io_range.size);
    95                                 io_found = true;
    96                                 break;
    97                         default:
    98                                 break;
     83                switch (res->type)
     84                {
     85                case INTERRUPT:
     86                        irq = res->res.interrupt.irq;
     87                        irq_found = true;
     88                        usb_log_debug2("Found interrupt: %d.\n", irq);
     89                        break;
     90
     91                case IO_RANGE:
     92                        io_address = res->res.io_range.address;
     93                        io_size = res->res.io_range.size;
     94                        usb_log_debug2("Found io: %llx %zu.\n",
     95                            res->res.io_range.address, res->res.io_range.size);
     96                        io_found = true;
     97
     98                default:
     99                        break;
    99100                }
    100101        }
    101102
    102         if (!io_found) {
    103                 rc = ENOENT;
    104                 goto leave;
    105         }
    106 
    107         if (!irq_found) {
     103        if (!io_found || !irq_found) {
    108104                rc = ENOENT;
    109105                goto leave;
     
    121117}
    122118/*----------------------------------------------------------------------------*/
     119/** Call the PCI driver with a request to enable interrupts
     120 *
     121 * @param[in] device Device asking for interrupts
     122 * @return Error code.
     123 */
    123124int pci_enable_interrupts(ddf_dev_t *device)
    124125{
     
    130131}
    131132/*----------------------------------------------------------------------------*/
     133/** Call the PCI driver with a request to clear legacy support register
     134 *
     135 * @param[in] device Device asking to disable interrupts
     136 * @return Error code.
     137 */
    132138int pci_disable_legacy(ddf_dev_t *device)
    133139{
    134140        assert(device);
    135         int parent_phone = devman_parent_device_connect(device->handle,
    136                 IPC_FLAG_BLOCKING);
     141        int parent_phone =
     142            devman_parent_device_connect(device->handle, IPC_FLAG_BLOCKING);
    137143        if (parent_phone < 0) {
    138144                return parent_phone;
     
    144150        sysarg_t value = 0x8f00;
    145151
    146   int rc = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
     152        int rc = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    147153            IPC_M_CONFIG_SPACE_WRITE_16, address, value);
    148154        async_hangup(parent_phone);
    149155
    150   return rc;
     156        return rc;
    151157}
    152158/*----------------------------------------------------------------------------*/
  • uspace/drv/uhci-hcd/pci.h

    r3e7b7cd r72af8da  
    2727 */
    2828
    29 /** @addtogroup drvusbuhci
     29/** @addtogroup drvusbuhcihc
    3030 * @{
    3131 */
    3232/** @file
    33  * @brief UHCI driver
     33 * @brief UHCI driver PCI helper functions
    3434 */
    3535#ifndef DRV_UHCI_PCI_H
  • uspace/drv/uhci-hcd/transfer_list.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 transfer list implementation
    3333 */
    3434#include <errno.h>
    35 
    3635#include <usb/debug.h>
    3736
    3837#include "transfer_list.h"
    3938
     39static void transfer_list_remove_batch(
     40    transfer_list_t *instance, batch_t *batch);
     41/*----------------------------------------------------------------------------*/
     42/** Initialize transfer list structures.
     43 *
     44 * @param[in] instance Memory place to use.
     45 * @param[in] name Name of the new list.
     46 * @return Error code
     47 *
     48 * Allocates memory for internal qh_t structure.
     49 */
    4050int transfer_list_init(transfer_list_t *instance, const char *name)
    4151{
    4252        assert(instance);
    43         instance->next = NULL;
    4453        instance->name = name;
    45         instance->queue_head = queue_head_get();
     54        instance->queue_head = malloc32(sizeof(qh_t));
    4655        if (!instance->queue_head) {
    4756                usb_log_error("Failed to allocate queue head.\n");
    4857                return ENOMEM;
    4958        }
    50         instance->queue_head_pa = (uintptr_t)addr_to_phys(instance->queue_head);
    51 
    52         queue_head_init(instance->queue_head);
     59        instance->queue_head_pa = addr_to_phys(instance->queue_head);
     60
     61        qh_init(instance->queue_head);
    5362        list_initialize(&instance->batch_list);
    5463        fibril_mutex_initialize(&instance->guard);
     
    5665}
    5766/*----------------------------------------------------------------------------*/
     67/** Set the next list in transfer list chain.
     68 *
     69 * @param[in] instance List to lead.
     70 * @param[in] next List to append.
     71 * @return Error code
     72 *
     73 * Does not check whether this replaces an existing list .
     74 */
    5875void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next)
    5976{
     
    6279        if (!instance->queue_head)
    6380                return;
    64         queue_head_append_qh(instance->queue_head, next->queue_head_pa);
    65         instance->queue_head->element = instance->queue_head->next_queue;
    66 }
    67 /*----------------------------------------------------------------------------*/
     81        /* Set both next and element to point to the same QH */
     82        qh_set_next_qh(instance->queue_head, next->queue_head_pa);
     83        qh_set_element_qh(instance->queue_head, next->queue_head_pa);
     84}
     85/*----------------------------------------------------------------------------*/
     86/** Submit transfer batch to the list and queue.
     87 *
     88 * @param[in] instance List to use.
     89 * @param[in] batch Transfer batch to submit.
     90 * @return Error code
     91 *
     92 * The batch is added to the end of the list and queue.
     93 */
    6894void transfer_list_add_batch(transfer_list_t *instance, batch_t *batch)
    6995{
    7096        assert(instance);
    7197        assert(batch);
    72         usb_log_debug2("Adding batch(%p) to queue %s.\n", batch, instance->name);
    73 
    74         uint32_t pa = (uintptr_t)addr_to_phys(batch->qh);
     98        usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch);
     99
     100        const uint32_t pa = addr_to_phys(batch->qh);
    75101        assert((pa & LINK_POINTER_ADDRESS_MASK) == pa);
    76         pa |= LINK_POINTER_QUEUE_HEAD_FLAG;
    77 
    78         batch->qh->next_queue = instance->queue_head->next_queue;
     102
     103        /* New batch will be added to the end of the current list
     104         * so set the link accordingly */
     105        qh_set_next_qh(batch->qh, instance->queue_head->next);
    79106
    80107        fibril_mutex_lock(&instance->guard);
    81108
    82         if (instance->queue_head->element == instance->queue_head->next_queue) {
    83                 /* there is nothing scheduled */
    84                 list_append(&batch->link, &instance->batch_list);
    85                 instance->queue_head->element = pa;
    86                 usb_log_debug("Batch(%p) added to queue %s first.\n",
    87                         batch, instance->name);
    88                 fibril_mutex_unlock(&instance->guard);
    89                 return;
    90         }
    91         /* now we can be sure that there is someting scheduled */
    92         assert(!list_empty(&instance->batch_list));
     109        /* Add to the hardware queue. */
     110        if (list_empty(&instance->batch_list)) {
     111                /* There is nothing scheduled */
     112                qh_t *qh = instance->queue_head;
     113                assert(qh->element == qh->next);
     114                qh_set_element_qh(qh, pa);
     115        } else {
     116                /* There is something scheduled */
     117                batch_t *last = list_get_instance(
     118                    instance->batch_list.prev, batch_t, link);
     119                qh_set_next_qh(last->qh, pa);
     120        }
     121        /* Add to the driver list */
     122        list_append(&batch->link, &instance->batch_list);
     123
    93124        batch_t *first = list_get_instance(
    94                   instance->batch_list.next, batch_t, link);
    95         batch_t *last = list_get_instance(
    96             instance->batch_list.prev, batch_t, link);
    97         queue_head_append_qh(last->qh, pa);
    98         list_append(&batch->link, &instance->batch_list);
    99         usb_log_debug("Batch(%p) added to queue %s last, first is %p.\n",
    100                 batch, instance->name, first );
     125            instance->batch_list.next, batch_t, link);
     126        usb_log_debug("Batch(%p) added to queue %s, first is %p.\n",
     127                batch, instance->name, first);
    101128        fibril_mutex_unlock(&instance->guard);
    102129}
    103130/*----------------------------------------------------------------------------*/
    104 static void transfer_list_remove_batch(
    105     transfer_list_t *instance, batch_t *batch)
     131/** Remove a transfer batch from the list and queue.
     132 *
     133 * @param[in] instance List to use.
     134 * @param[in] batch Transfer batch to remove.
     135 * @return Error code
     136 *
     137 * Does not lock the transfer list, caller is responsible for that.
     138 */
     139void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch)
    106140{
    107141        assert(instance);
     
    109143        assert(instance->queue_head);
    110144        assert(batch->qh);
    111         usb_log_debug2("Removing batch(%p) from queue %s.\n", batch, instance->name);
    112 
    113         /* I'm the first one here */
     145        usb_log_debug2(
     146            "Queue %s: removing batch(%p).\n", instance->name, batch);
     147
     148        const char * pos = NULL;
     149        /* Remove from the hardware queue */
    114150        if (batch->link.prev == &instance->batch_list) {
    115                 usb_log_debug("Batch(%p) removed (FIRST) from queue %s, next element %x.\n",
    116                         batch, instance->name, batch->qh->next_queue);
    117                 instance->queue_head->element = batch->qh->next_queue;
     151                /* I'm the first one here */
     152                qh_set_element_qh(instance->queue_head, batch->qh->next);
     153                pos = "FIRST";
    118154        } else {
    119                 usb_log_debug("Batch(%p) removed (NOT FIRST) from queue, next element %x.\n",
    120                         batch, instance->name, batch->qh->next_queue);
    121                 batch_t *prev = list_get_instance(batch->link.prev, batch_t, link);
    122                 prev->qh->next_queue = batch->qh->next_queue;
    123         }
     155                batch_t *prev =
     156                    list_get_instance(batch->link.prev, batch_t, link);
     157                qh_set_next_qh(prev->qh, batch->qh->next);
     158                pos = "NOT FIRST";
     159        }
     160        /* Remove from the driver list */
    124161        list_remove(&batch->link);
    125 }
    126 /*----------------------------------------------------------------------------*/
     162        usb_log_debug("Batch(%p) removed (%s) from %s, next element %x.\n",
     163            batch, pos, instance->name, batch->qh->next);
     164}
     165/*----------------------------------------------------------------------------*/
     166/** Check list for finished batches.
     167 *
     168 * @param[in] instance List to use.
     169 * @return Error code
     170 *
     171 * Creates a local list of finished batches and calls next_step on each and
     172 * every one. This is safer because next_step may theoretically access
     173 * this transfer list leading to the deadlock if its done inline.
     174 */
    127175void transfer_list_remove_finished(transfer_list_t *instance)
    128176{
     
    138186
    139187                if (batch_is_complete(batch)) {
     188                        /* Save for post-processing */
    140189                        transfer_list_remove_batch(instance, batch);
    141190                        list_append(current, &done);
  • uspace/drv/uhci-hcd/transfer_list.h

    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 transfer list structure
    3333 */
    3434#ifndef DRV_UHCI_TRANSFER_LIST_H
     
    4444{
    4545        fibril_mutex_t guard;
    46         queue_head_t *queue_head;
     46        qh_t *queue_head;
    4747        uint32_t queue_head_pa;
    48         struct transfer_list *next;
    4948        const char *name;
    5049        link_t batch_list;
    5150} transfer_list_t;
     51
     52/** Dispose transfer list structures.
     53 *
     54 * @param[in] instance Memory place to use.
     55 *
     56 * Frees memory for internal qh_t structure.
     57 */
     58static inline void transfer_list_fini(transfer_list_t *instance)
     59{
     60        assert(instance);
     61        free32(instance->queue_head);
     62}
    5263
    5364int transfer_list_init(transfer_list_t *instance, const char *name);
     
    5566void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next);
    5667
    57 static inline void transfer_list_fini(transfer_list_t *instance)
    58 {
    59         assert(instance);
    60         queue_head_dispose(instance->queue_head);
    61 }
    6268void transfer_list_remove_finished(transfer_list_t *instance);
    6369
  • uspace/drv/uhci-hcd/uhci.c

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28
     29/** @addtogroup drvusbuhci
    2930 * @{
    3031 */
     
    3435#include <errno.h>
    3536#include <str_error.h>
    36 #include <adt/list.h>
    37 #include <libarch/ddi.h>
    38 
     37#include <ddf/interrupt.h>
     38#include <usb_iface.h>
     39#include <usb/ddfiface.h>
    3940#include <usb/debug.h>
    40 #include <usb/usb.h>
    41 #include <usb/ddfiface.h>
    42 #include <usb_iface.h>
    4341
    4442#include "uhci.h"
    4543#include "iface.h"
    46 
    47 static irq_cmd_t uhci_cmds[] = {
    48         {
    49                 .cmd = CMD_PIO_READ_16,
    50                 .addr = NULL, /* patched for every instance */
    51                 .dstarg = 1
    52         },
    53         {
    54                 .cmd = CMD_PIO_WRITE_16,
    55                 .addr = NULL, /* pathed for every instance */
    56                 .value = 0x1f
    57         },
    58         {
    59                 .cmd = CMD_ACCEPT
    60         }
    61 };
    62 
    63 static int usb_iface_get_address(ddf_fun_t *fun, devman_handle_t handle,
    64     usb_address_t *address)
     44#include "pci.h"
     45
     46
     47/** IRQ handling callback, identifies device
     48 *
     49 * @param[in] dev DDF instance of the device to use.
     50 * @param[in] iid (Unused).
     51 * @param[in] call Pointer to the call that represents interrupt.
     52 */
     53static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
     54{
     55        assert(dev);
     56        uhci_hc_t *hc = &((uhci_t*)dev->driver_data)->hc;
     57        uint16_t status = IPC_GET_ARG1(*call);
     58        assert(hc);
     59        uhci_hc_interrupt(hc, status);
     60}
     61/*----------------------------------------------------------------------------*/
     62/** Get address of the device identified by handle.
     63 *
     64 * @param[in] dev DDF instance of the device to use.
     65 * @param[in] iid (Unused).
     66 * @param[in] call Pointer to the call that represents interrupt.
     67 */
     68static int usb_iface_get_address(
     69    ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
    6570{
    6671        assert(fun);
    67         uhci_t *hc = fun_to_uhci(fun);
    68         assert(hc);
    69 
    70         usb_address_t addr = device_keeper_find(&hc->device_manager,
    71             handle);
     72        device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.device_manager;
     73
     74        usb_address_t addr = device_keeper_find(manager, handle);
    7275        if (addr < 0) {
    7376                return addr;
     
    8184}
    8285/*----------------------------------------------------------------------------*/
    83 static usb_iface_t hc_usb_iface = {
    84         .get_hc_handle = usb_iface_get_hc_handle_hc_impl,
     86/** Gets handle of the respective hc (this or parent device).
     87 *
     88 * @param[in] root_hub_fun Root hub function seeking hc handle.
     89 * @param[out] handle Place to write the handle.
     90 * @return Error code.
     91 */
     92static int usb_iface_get_hc_handle(
     93    ddf_fun_t *fun, devman_handle_t *handle)
     94{
     95        assert(handle);
     96        ddf_fun_t *hc_fun = ((uhci_t*)fun->dev->driver_data)->hc_fun;
     97        assert(hc_fun != NULL);
     98
     99        *handle = hc_fun->handle;
     100        return EOK;
     101}
     102/*----------------------------------------------------------------------------*/
     103/** This iface is generic for both RH and HC. */
     104static usb_iface_t usb_iface = {
     105        .get_hc_handle = usb_iface_get_hc_handle,
    85106        .get_address = usb_iface_get_address
    86107};
    87108/*----------------------------------------------------------------------------*/
    88 static ddf_dev_ops_t uhci_ops = {
    89         .interfaces[USB_DEV_IFACE] = &hc_usb_iface,
    90         .interfaces[USBHC_DEV_IFACE] = &uhci_iface,
    91 };
    92 /*----------------------------------------------------------------------------*/
    93 static int uhci_init_transfer_lists(uhci_t *instance);
    94 static int uhci_init_mem_structures(uhci_t *instance);
    95 static void uhci_init_hw(uhci_t *instance);
    96 
    97 static int uhci_interrupt_emulator(void *arg);
    98 static int uhci_debug_checker(void *arg);
    99 
    100 static bool allowed_usb_packet(
    101         bool low_speed, usb_transfer_type_t, size_t size);
    102 
    103 
    104 int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size)
    105 {
    106         assert(reg_size >= sizeof(regs_t));
    107         int ret;
    108 
     109static ddf_dev_ops_t uhci_hc_ops = {
     110        .interfaces[USB_DEV_IFACE] = &usb_iface,
     111        .interfaces[USBHC_DEV_IFACE] = &uhci_hc_iface, /* see iface.h/c */
     112};
     113/*----------------------------------------------------------------------------*/
     114/** Get root hub hw resources (I/O registers).
     115 *
     116 * @param[in] fun Root hub function.
     117 * @return Pointer to the resource list used by the root hub.
     118 */
     119static hw_resource_list_t *get_resource_list(ddf_fun_t *fun)
     120{
     121        assert(fun);
     122        return &((uhci_rh_t*)fun->driver_data)->resource_list;
     123}
     124/*----------------------------------------------------------------------------*/
     125static hw_res_ops_t hw_res_iface = {
     126        .get_resource_list = get_resource_list,
     127        .enable_interrupt = NULL
     128};
     129/*----------------------------------------------------------------------------*/
     130static ddf_dev_ops_t uhci_rh_ops = {
     131        .interfaces[USB_DEV_IFACE] = &usb_iface,
     132        .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface
     133};
     134/*----------------------------------------------------------------------------*/
     135/** Initialize hc and rh ddf structures and their respective drivers.
     136 *
     137 * @param[in] instance UHCI structure to use.
     138 * @param[in] device DDF instance of the device to use.
     139 *
     140 * This function does all the preparatory work for hc and rh drivers:
     141 *  - gets device hw resources
     142 *  - disables UHCI legacy support
     143 *  - asks for interrupt
     144 *  - registers interrupt handler
     145 */
     146int uhci_init(uhci_t *instance, ddf_dev_t *device)
     147{
     148        assert(instance);
     149        instance->hc_fun = NULL;
     150        instance->rh_fun = NULL;
    109151#define CHECK_RET_DEST_FUN_RETURN(ret, message...) \
    110         if (ret != EOK) { \
    111                 usb_log_error(message); \
    112                 if (instance->ddf_instance) \
    113                         ddf_fun_destroy(instance->ddf_instance); \
    114                 return ret; \
    115         } else (void) 0
    116 
    117         /* Create UHCI function. */
    118         instance->ddf_instance = ddf_fun_create(dev, fun_exposed, "uhci");
    119         ret = (instance->ddf_instance == NULL) ? ENOMEM : EOK;
    120         CHECK_RET_DEST_FUN_RETURN(ret,
    121             "Failed to create UHCI device function.\n");
    122 
    123         instance->ddf_instance->ops = &uhci_ops;
    124         instance->ddf_instance->driver_data = instance;
    125 
    126         ret = ddf_fun_bind(instance->ddf_instance);
     152if (ret != EOK) { \
     153        usb_log_error(message); \
     154        if (instance->hc_fun) \
     155                ddf_fun_destroy(instance->hc_fun); \
     156        if (instance->rh_fun) \
     157                ddf_fun_destroy(instance->rh_fun); \
     158        return ret; \
     159}
     160
     161        uintptr_t io_reg_base = 0;
     162        size_t io_reg_size = 0;
     163        int irq = 0;
     164
     165        int ret =
     166            pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq);
     167        CHECK_RET_DEST_FUN_RETURN(ret,
     168            "Failed(%d) to get I/O addresses:.\n", ret, device->handle);
     169        usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n",
     170            io_reg_base, io_reg_size, irq);
     171
     172        ret = pci_disable_legacy(device);
     173        CHECK_RET_DEST_FUN_RETURN(ret,
     174            "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret));
     175
     176        bool interrupts = false;
     177        ret = pci_enable_interrupts(device);
     178        if (ret != EOK) {
     179                usb_log_warning(
     180                    "Failed(%d) to enable interrupts, fall back to polling.\n",
     181                    ret);
     182        } else {
     183                usb_log_debug("Hw interrupts enabled.\n");
     184                interrupts = true;
     185        }
     186
     187        instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci-hc");
     188        ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
     189        CHECK_RET_DEST_FUN_RETURN(ret,
     190            "Failed(%d) to create HC function.\n", ret);
     191
     192        ret = uhci_hc_init(&instance->hc, instance->hc_fun,
     193            (void*)io_reg_base, io_reg_size, interrupts);
     194        CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret);
     195        instance->hc_fun->ops = &uhci_hc_ops;
     196        instance->hc_fun->driver_data = &instance->hc;
     197        ret = ddf_fun_bind(instance->hc_fun);
    127198        CHECK_RET_DEST_FUN_RETURN(ret,
    128199            "Failed(%d) to bind UHCI device function: %s.\n",
    129200            ret, str_error(ret));
    130 
    131         /* allow access to hc control registers */
    132         regs_t *io;
    133         ret = pio_enable(regs, reg_size, (void**)&io);
    134         CHECK_RET_DEST_FUN_RETURN(ret,
    135             "Failed(%d) to gain access to registers at %p: %s.\n",
    136             ret, str_error(ret), io);
    137         instance->registers = io;
    138         usb_log_debug("Device registers at %p(%u) accessible.\n",
    139             io, reg_size);
    140 
    141         ret = uhci_init_mem_structures(instance);
    142         CHECK_RET_DEST_FUN_RETURN(ret,
    143             "Failed to initialize UHCI memory structures.\n");
    144 
    145         uhci_init_hw(instance);
    146         instance->cleaner =
    147             fibril_create(uhci_interrupt_emulator, instance);
    148         fibril_add_ready(instance->cleaner);
    149 
    150         instance->debug_checker = fibril_create(uhci_debug_checker, instance);
    151         fibril_add_ready(instance->debug_checker);
    152 
    153         usb_log_info("Started UHCI driver.\n");
     201#undef CHECK_RET_HC_RETURN
     202
     203#define CHECK_RET_FINI_RETURN(ret, message...) \
     204if (ret != EOK) { \
     205        usb_log_error(message); \
     206        if (instance->hc_fun) \
     207                ddf_fun_destroy(instance->hc_fun); \
     208        if (instance->rh_fun) \
     209                ddf_fun_destroy(instance->rh_fun); \
     210        uhci_hc_fini(&instance->hc); \
     211        return ret; \
     212}
     213
     214        /* It does no harm if we register this on polling */
     215        ret = register_interrupt_handler(device, irq, irq_handler,
     216            &instance->hc.interrupt_code);
     217        CHECK_RET_FINI_RETURN(ret,
     218            "Failed(%d) to register interrupt handler.\n", ret);
     219
     220        instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh");
     221        ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
     222        CHECK_RET_FINI_RETURN(ret,
     223            "Failed(%d) to create root hub function.\n", ret);
     224
     225        ret = uhci_rh_init(&instance->rh, instance->rh_fun,
     226            (uintptr_t)instance->hc.registers + 0x10, 4);
     227        CHECK_RET_FINI_RETURN(ret,
     228            "Failed(%d) to setup UHCI root hub.\n", ret);
     229
     230        instance->rh_fun->ops = &uhci_rh_ops;
     231        instance->rh_fun->driver_data = &instance->rh;
     232        ret = ddf_fun_bind(instance->rh_fun);
     233        CHECK_RET_FINI_RETURN(ret,
     234            "Failed(%d) to register UHCI root hub.\n", ret);
     235
    154236        return EOK;
    155 #undef CHECK_RET_DEST_FUN_RETURN
    156 }
    157 /*----------------------------------------------------------------------------*/
    158 void uhci_init_hw(uhci_t *instance)
    159 {
    160         assert(instance);
    161 
    162         /* reset everything, who knows what touched it before us */
    163         pio_write_16(&instance->registers->usbcmd, UHCI_CMD_GLOBAL_RESET);
    164         async_usleep(10000); /* 10ms according to USB spec */
    165         pio_write_16(&instance->registers->usbcmd, 0);
    166 
    167         /* reset hc, all states and counters */
    168         pio_write_16(&instance->registers->usbcmd, UHCI_CMD_HCRESET);
    169         while ((pio_read_16(&instance->registers->usbcmd) & UHCI_CMD_HCRESET) != 0)
    170                 { async_usleep(10); }
    171 
    172         /* set framelist pointer */
    173         const uint32_t pa = addr_to_phys(instance->frame_list);
    174         pio_write_32(&instance->registers->flbaseadd, pa);
    175 
    176         /* enable all interrupts, but resume interrupt */
    177         pio_write_16(&instance->registers->usbintr,
    178             UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET);
    179 
    180         /* Start the hc with large(64B) packet FSBR */
    181         pio_write_16(&instance->registers->usbcmd,
    182             UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET | UHCI_CMD_CONFIGURE);
    183 }
    184 /*----------------------------------------------------------------------------*/
    185 int uhci_init_mem_structures(uhci_t *instance)
    186 {
    187         assert(instance);
    188 #define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \
    189         if (ret != EOK) { \
    190                 usb_log_error(message); \
    191                 if (instance->interrupt_code.cmds != NULL) \
    192                         free(instance->interrupt_code.cmds); \
    193                 return ret; \
    194         } else (void) 0
    195 
    196         /* init interrupt code */
    197         instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds));
    198         int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK;
    199         CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to allocate interrupt cmds space.\n");
    200 
    201         {
    202                 irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds;
    203                 memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds));
    204                 interrupt_commands[0].addr = (void*)&instance->registers->usbsts;
    205                 interrupt_commands[1].addr = (void*)&instance->registers->usbsts;
    206                 instance->interrupt_code.cmdcount =
    207                     sizeof(uhci_cmds) / sizeof(irq_cmd_t);
    208         }
    209 
    210         /* init transfer lists */
    211         ret = uhci_init_transfer_lists(instance);
    212         CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to initialize transfer lists.\n");
    213         usb_log_debug("Initialized transfer lists.\n");
    214 
    215         /* frame list initialization */
    216         instance->frame_list = get_page();
    217         ret = instance ? EOK : ENOMEM;
    218         CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n");
    219         usb_log_debug("Initialized frame list.\n");
    220 
    221         /* initialize all frames to point to the first queue head */
    222         const uint32_t queue =
    223           instance->transfers_interrupt.queue_head_pa
    224           | LINK_POINTER_QUEUE_HEAD_FLAG;
    225 
    226         unsigned i = 0;
    227         for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
    228                 instance->frame_list[i] = queue;
    229         }
    230 
    231         /* init address keeper(libusb) */
    232         device_keeper_init(&instance->device_manager);
    233         usb_log_debug("Initialized device manager.\n");
    234 
    235         return EOK;
    236 #undef CHECK_RET_DEST_CMDS_RETURN
    237 }
    238 /*----------------------------------------------------------------------------*/
    239 int uhci_init_transfer_lists(uhci_t *instance)
    240 {
    241         assert(instance);
    242 #define CHECK_RET_CLEAR_RETURN(ret, message...) \
    243         if (ret != EOK) { \
    244                 usb_log_error(message); \
    245                 transfer_list_fini(&instance->transfers_bulk_full); \
    246                 transfer_list_fini(&instance->transfers_control_full); \
    247                 transfer_list_fini(&instance->transfers_control_slow); \
    248                 transfer_list_fini(&instance->transfers_interrupt); \
    249                 return ret; \
    250         } else (void) 0
    251 
    252         /* initialize TODO: check errors */
    253         int ret;
    254         ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL");
    255         CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list.");
    256 
    257         ret = transfer_list_init(&instance->transfers_control_full, "CONTROL_FULL");
    258         CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list.");
    259 
    260         ret = transfer_list_init(&instance->transfers_control_slow, "CONTROL_SLOW");
    261         CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list.");
    262 
    263         ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT");
    264         CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list.");
    265 
    266         transfer_list_set_next(&instance->transfers_control_full,
    267                 &instance->transfers_bulk_full);
    268         transfer_list_set_next(&instance->transfers_control_slow,
    269                 &instance->transfers_control_full);
    270         transfer_list_set_next(&instance->transfers_interrupt,
    271                 &instance->transfers_control_slow);
    272 
    273         /*FSBR*/
    274 #ifdef FSBR
    275         transfer_list_set_next(&instance->transfers_bulk_full,
    276                 &instance->transfers_control_full);
    277 #endif
    278 
    279         instance->transfers[0][USB_TRANSFER_INTERRUPT] =
    280           &instance->transfers_interrupt;
    281         instance->transfers[1][USB_TRANSFER_INTERRUPT] =
    282           &instance->transfers_interrupt;
    283         instance->transfers[0][USB_TRANSFER_CONTROL] =
    284           &instance->transfers_control_full;
    285         instance->transfers[1][USB_TRANSFER_CONTROL] =
    286           &instance->transfers_control_slow;
    287         instance->transfers[0][USB_TRANSFER_BULK] =
    288           &instance->transfers_bulk_full;
    289 
    290         return EOK;
    291 #undef CHECK_RET_CLEAR_RETURN
    292 }
    293 /*----------------------------------------------------------------------------*/
    294 int uhci_schedule(uhci_t *instance, batch_t *batch)
    295 {
    296         assert(instance);
    297         assert(batch);
    298         const int low_speed = (batch->speed == USB_SPEED_LOW);
    299         if (!allowed_usb_packet(
    300             low_speed, batch->transfer_type, batch->max_packet_size)) {
    301                 usb_log_warning("Invalid USB packet specified %s SPEED %d %zu.\n",
    302                     low_speed ? "LOW" : "FULL" , batch->transfer_type,
    303                     batch->max_packet_size);
    304                 return ENOTSUP;
    305         }
    306         /* TODO: check available bandwith here */
    307 
    308         transfer_list_t *list =
    309             instance->transfers[low_speed][batch->transfer_type];
    310         assert(list);
    311         transfer_list_add_batch(list, batch);
    312 
    313         return EOK;
    314 }
    315 /*----------------------------------------------------------------------------*/
    316 void uhci_interrupt(uhci_t *instance, uint16_t status)
    317 {
    318         assert(instance);
    319         transfer_list_remove_finished(&instance->transfers_interrupt);
    320         transfer_list_remove_finished(&instance->transfers_control_slow);
    321         transfer_list_remove_finished(&instance->transfers_control_full);
    322         transfer_list_remove_finished(&instance->transfers_bulk_full);
    323 }
    324 /*----------------------------------------------------------------------------*/
    325 int uhci_interrupt_emulator(void* arg)
    326 {
    327         usb_log_debug("Started interrupt emulator.\n");
    328         uhci_t *instance = (uhci_t*)arg;
    329         assert(instance);
    330 
    331         while (1) {
    332                 uint16_t status = pio_read_16(&instance->registers->usbsts);
    333                 if (status != 0)
    334                         usb_log_debug2("UHCI status: %x.\n", status);
    335                 status |= 1;
    336                 uhci_interrupt(instance, status);
    337                 pio_write_16(&instance->registers->usbsts, 0x1f);
    338                 async_usleep(UHCI_CLEANER_TIMEOUT * 5);
    339         }
    340         return EOK;
    341 }
    342 /*---------------------------------------------------------------------------*/
    343 int uhci_debug_checker(void *arg)
    344 {
    345         uhci_t *instance = (uhci_t*)arg;
    346         assert(instance);
    347 
    348 #define QH(queue) \
    349         instance->transfers_##queue.queue_head
    350 
    351         while (1) {
    352                 const uint16_t cmd = pio_read_16(&instance->registers->usbcmd);
    353                 const uint16_t sts = pio_read_16(&instance->registers->usbsts);
    354                 const uint16_t intr =
    355                     pio_read_16(&instance->registers->usbintr);
    356 
    357                 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
    358                         usb_log_debug2("Command: %X Status: %X Intr: %x\n",
    359                             cmd, sts, intr);
    360                 }
    361 
    362                 uintptr_t frame_list =
    363                     pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
    364                 if (frame_list != addr_to_phys(instance->frame_list)) {
    365                         usb_log_debug("Framelist address: %p vs. %p.\n",
    366                             frame_list, addr_to_phys(instance->frame_list));
    367                 }
    368 
    369                 int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff;
    370                 usb_log_debug2("Framelist item: %d \n", frnum );
    371 
    372                 uintptr_t expected_pa = instance->frame_list[frnum] & (~0xf);
    373                 uintptr_t real_pa = addr_to_phys(QH(interrupt));
    374                 if (expected_pa != real_pa) {
    375                         usb_log_debug("Interrupt QH: %p vs. %p.\n",
    376                             expected_pa, real_pa);
    377                 }
    378 
    379                 expected_pa = QH(interrupt)->next_queue & (~0xf);
    380                 real_pa = addr_to_phys(QH(control_slow));
    381                 if (expected_pa != real_pa) {
    382                         usb_log_debug("Control Slow QH: %p vs. %p.\n",
    383                             expected_pa, real_pa);
    384                 }
    385 
    386                 expected_pa = QH(control_slow)->next_queue & (~0xf);
    387                 real_pa = addr_to_phys(QH(control_full));
    388                 if (expected_pa != real_pa) {
    389                         usb_log_debug("Control Full QH: %p vs. %p.\n",
    390                             expected_pa, real_pa);
    391                 }
    392 
    393                 expected_pa = QH(control_full)->next_queue & (~0xf);
    394                 real_pa = addr_to_phys(QH(bulk_full));
    395                 if (expected_pa != real_pa ) {
    396                         usb_log_debug("Bulk QH: %p vs. %p.\n",
    397                             expected_pa, real_pa);
    398                 }
    399                 async_usleep(UHCI_DEBUGER_TIMEOUT);
    400         }
    401         return 0;
    402 #undef QH
    403 }
    404 /*----------------------------------------------------------------------------*/
    405 bool allowed_usb_packet(
    406     bool low_speed, usb_transfer_type_t transfer, size_t size)
    407 {
    408         /* see USB specification chapter 5.5-5.8 for magic numbers used here */
    409         switch(transfer)
    410         {
    411         case USB_TRANSFER_ISOCHRONOUS:
    412                 return (!low_speed && size < 1024);
    413         case USB_TRANSFER_INTERRUPT:
    414                 return size <= (low_speed ? 8 : 64);
    415         case USB_TRANSFER_CONTROL: /* device specifies its own max size */
    416                 return (size <= (low_speed ? 8 : 64));
    417         case USB_TRANSFER_BULK: /* device specifies its own max size */
    418                 return (!low_speed && size <= 64);
    419         }
    420         return false;
     237#undef CHECK_RET_FINI_RETURN
    421238}
    422239/**
  • uspace/drv/uhci-hcd/uhci.h

    r3e7b7cd r72af8da  
    11/*
    2  * Copyright (c) 2010 Jan Vesely
     2 * Copyright (c) 2011 Jan Vesely
    33 * All rights reserved.
    44 *
     
    3131 */
    3232/** @file
    33  * @brief UHCI driver
     33 * @brief UHCI driver main structure for both host controller and root-hub.
    3434 */
    3535#ifndef DRV_UHCI_UHCI_H
    3636#define DRV_UHCI_UHCI_H
     37#include <ddi.h>
     38#include <ddf/driver.h>
    3739
    38 #include <fibril.h>
    39 #include <fibril_synch.h>
    40 #include <adt/list.h>
    41 #include <ddi.h>
    42 
    43 #include <usbhc_iface.h>
    44 
    45 #include "batch.h"
    46 #include "transfer_list.h"
    47 #include "utils/device_keeper.h"
    48 
    49 typedef struct uhci_regs {
    50         uint16_t usbcmd;
    51 #define UHCI_CMD_MAX_PACKET (1 << 7)
    52 #define UHCI_CMD_CONFIGURE  (1 << 6)
    53 #define UHCI_CMD_DEBUG  (1 << 5)
    54 #define UHCI_CMD_FORCE_GLOBAL_RESUME  (1 << 4)
    55 #define UHCI_CMD_FORCE_GLOBAL_SUSPEND  (1 << 3)
    56 #define UHCI_CMD_GLOBAL_RESET  (1 << 2)
    57 #define UHCI_CMD_HCRESET  (1 << 1)
    58 #define UHCI_CMD_RUN_STOP  (1 << 0)
    59 
    60         uint16_t usbsts;
    61 #define UHCI_STATUS_HALTED (1 << 5)
    62 #define UHCI_STATUS_PROCESS_ERROR (1 << 4)
    63 #define UHCI_STATUS_SYSTEM_ERROR (1 << 3)
    64 #define UHCI_STATUS_RESUME (1 << 2)
    65 #define UHCI_STATUS_ERROR_INTERRUPT (1 << 1)
    66 #define UHCI_STATUS_INTERRUPT (1 << 0)
    67 
    68         uint16_t usbintr;
    69 #define UHCI_INTR_SHORT_PACKET (1 << 3)
    70 #define UHCI_INTR_COMPLETE (1 << 2)
    71 #define UHCI_INTR_RESUME (1 << 1)
    72 #define UHCI_INTR_CRC (1 << 0)
    73 
    74         uint16_t frnum;
    75         uint32_t flbaseadd;
    76         uint8_t sofmod;
    77 } regs_t;
    78 
    79 #define UHCI_FRAME_LIST_COUNT 1024
    80 #define UHCI_CLEANER_TIMEOUT 10000
    81 #define UHCI_DEBUGER_TIMEOUT 5000000
     40#include "uhci_hc.h"
     41#include "uhci_rh.h"
    8242
    8343typedef struct uhci {
    84         device_keeper_t device_manager;
     44        ddf_fun_t *hc_fun;
     45        ddf_fun_t *rh_fun;
    8546
    86         volatile regs_t *registers;
    87 
    88         link_pointer_t *frame_list;
    89 
    90         transfer_list_t transfers_bulk_full;
    91         transfer_list_t transfers_control_full;
    92         transfer_list_t transfers_control_slow;
    93         transfer_list_t transfers_interrupt;
    94 
    95         transfer_list_t *transfers[2][4];
    96 
    97         irq_code_t interrupt_code;
    98 
    99         fid_t cleaner;
    100         fid_t debug_checker;
    101 
    102         ddf_fun_t *ddf_instance;
     47        uhci_hc_t hc;
     48        uhci_rh_t rh;
    10349} uhci_t;
    10450
    105 /* init uhci specifics in device.driver_data */
    106 int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size);
    107 
    108 static inline void uhci_fini(uhci_t *instance) {};
    109 
    110 int uhci_schedule(uhci_t *instance, batch_t *batch);
    111 
    112 void uhci_interrupt(uhci_t *instance, uint16_t status);
    113 
    114 static inline uhci_t * dev_to_uhci(ddf_dev_t *dev)
    115         { return (uhci_t*)dev->driver_data; }
    116 
    117 static inline uhci_t * fun_to_uhci(ddf_fun_t *fun)
    118         { return (uhci_t*)fun->driver_data; }
    119 
     51int uhci_init(uhci_t *instance, ddf_dev_t *device);
    12052
    12153#endif
  • uspace/drv/uhci-hcd/uhci_rh.c

    r3e7b7cd r72af8da  
    11/*
    2  * Copyright (c) 2010 Vojtech Horky
     2 * Copyright (c) 2011 Jan Vesely
    33 * All rights reserved.
    44 *
     
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 
    29 /** @addtogroup libusb
     28/** @addtogroup drvusbuhci
    3029 * @{
    3130 */
    3231/** @file
    33  * @brief Common definitions for both HC driver and hub driver.
     32 * @brief UHCI driver
    3433 */
    35 #ifndef LIBUSB_HCDHUBD_PRIVATE_H_
    36 #define LIBUSB_HCDHUBD_PRIVATE_H_
     34#include <assert.h>
     35#include <errno.h>
     36#include <str_error.h>
     37#include <stdio.h>
    3738
    38 #define USB_HUB_DEVICE_NAME "usbhub"
    39 #define USB_KBD_DEVICE_NAME "hid"
     39#include <usb/debug.h>
    4040
    41 extern link_t hc_list;
    42 extern usb_hc_driver_t *hc_driver;
     41#include "uhci_rh.h"
     42#include "uhci_hc.h"
    4343
    44 extern usbhc_iface_t usbhc_interface;
     44/** Root hub initialization
     45 * @param[in] instance RH structure to initialize
     46 * @param[in] fun DDF function representing UHCI root hub
     47 * @param[in] reg_addr Address of root hub status and control registers.
     48 * @param[in] reg_size Size of accessible address space.
     49 * @return Error code.
     50 */
     51int uhci_rh_init(
     52    uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size)
     53{
     54        assert(fun);
    4555
    46 usb_address_t usb_get_address_by_handle(devman_handle_t);
    47 int usb_add_hc_device(device_t *);
     56        char *match_str = NULL;
     57        int ret = asprintf(&match_str, "usb&uhci&root-hub");
     58        if (ret < 0) {
     59                usb_log_error("Failed to create root hub match string.\n");
     60                return ENOMEM;
     61        }
    4862
    49 /** lowest allowed usb address */
    50 extern int usb_lowest_address;
     63        ret = ddf_fun_add_match_id(fun, match_str, 100);
     64        if (ret != EOK) {
     65                usb_log_error("Failed(%d) to add root hub match id: %s\n",
     66                    ret, str_error(ret));
     67                return ret;
     68        }
    5169
    52 /** highest allowed usb address */
    53 extern int usb_highest_address;
     70        hw_resource_list_t *resource_list = &instance->resource_list;
     71        resource_list->count = 1;
     72        resource_list->resources = &instance->io_regs;
     73        assert(resource_list->resources);
     74        instance->io_regs.type = IO_RANGE;
     75        instance->io_regs.res.io_range.address = reg_addr;
     76        instance->io_regs.res.io_range.size = reg_size;
     77        instance->io_regs.res.io_range.endianness = LITTLE_ENDIAN;
    5478
    55 /**
    56  * @brief initialize address list of given hcd
    57  *
    58  * This function should be used only for hcd initialization.
    59  * It creates interval list of free addresses, thus it is initialized as
    60  * list with one interval with whole address space. Using an address shrinks
    61  * the interval, freeing an address extends an interval or creates a
    62  * new one.
    63  *
    64  * @param hcd
    65  * @return
    66  */
    67 void  usb_create_address_list(usb_hc_device_t * hcd);
    68 
    69 
    70 
    71 
    72 
    73 
    74 #endif
     79        return EOK;
     80}
    7581/**
    7682 * @}
  • uspace/drv/uhci-hcd/uhci_rh.h

    r3e7b7cd r72af8da  
    11/*
    2  * Copyright (c) 2010 Jan Vesely
     2 * Copyright (c) 2011 Jan Vesely
    33 * All rights reserved.
    44 *
     
    3333 * @brief UHCI driver
    3434 */
    35 #ifndef DRV_UHCI_ROOT_HUB_H
    36 #define DRV_UHCI_ROOT_HUB_H
     35#ifndef DRV_UHCI_UHCI_RH_H
     36#define DRV_UHCI_UHCI_RH_H
    3737
    3838#include <ddf/driver.h>
     39#include <ops/hw_res.h>
    3940
    40 int setup_root_hub(ddf_fun_t **device, ddf_dev_t *hc);
     41typedef struct uhci_rh {
     42        hw_resource_list_t resource_list;
     43        hw_resource_t io_regs;
     44} uhci_rh_t;
     45
     46int uhci_rh_init(
     47    uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size);
    4148
    4249#endif
  • uspace/drv/uhci-hcd/uhci_struct/link_pointer.h

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcihc
    2929 * @{
    3030 */
     
    4646#define LINK_POINTER_ADDRESS_MASK 0xfffffff0 /* upper 28 bits */
    4747
     48#define LINK_POINTER_QH(address) \
     49        ((address & LINK_POINTER_ADDRESS_MASK) | LINK_POINTER_QUEUE_HEAD_FLAG)
     50
    4851#endif
    4952/**
  • uspace/drv/uhci-hcd/uhci_struct/queue_head.h

    r3e7b7cd r72af8da  
    1 
    21/*
    32 * Copyright (c) 2010 Jan Vesely
     
    2726 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2827 */
    29 /** @addtogroup usb
     28/** @addtogroup drv usbuhcihc
    3029 * @{
    3130 */
     
    4342
    4443typedef struct queue_head {
    45         volatile link_pointer_t next_queue;
     44        volatile link_pointer_t next;
    4645        volatile link_pointer_t element;
    47 } __attribute__((packed)) queue_head_t;
    48 
    49 static inline void queue_head_init(queue_head_t *instance)
     46} __attribute__((packed)) qh_t;
     47/*----------------------------------------------------------------------------*/
     48/** Initialize queue head structure
     49 *
     50 * @param[in] instance qh_t structure to initialize.
     51 *
     52 * Sets both pointer to terminal NULL.
     53 */
     54static inline void qh_init(qh_t *instance)
    5055{
    5156        assert(instance);
    5257
    5358        instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
    54         instance->next_queue = 0 | LINK_POINTER_TERMINATE_FLAG;
     59        instance->next = 0 | LINK_POINTER_TERMINATE_FLAG;
    5560}
    56 
    57 static inline void queue_head_append_qh(queue_head_t *instance, uint32_t pa)
     61/*----------------------------------------------------------------------------*/
     62/** Set queue head next pointer
     63 *
     64 * @param[in] instance qh_t structure to use.
     65 * @param[in] pa Physical address of the next queue head.
     66 *
     67 * Adds proper flag. If the pointer is NULL or terminal, sets next to terminal
     68 * NULL.
     69 */
     70static inline void qh_set_next_qh(qh_t *instance, uint32_t pa)
    5871{
    59         if (pa) {
    60                 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK)
     72        /* Address is valid and not terminal */
     73        if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
     74                instance->next = (pa & LINK_POINTER_ADDRESS_MASK)
    6175                    | LINK_POINTER_QUEUE_HEAD_FLAG;
     76        } else {
     77                instance->next = 0 | LINK_POINTER_TERMINATE_FLAG;
    6278        }
    6379}
    64 
    65 static inline void queue_head_element_qh(queue_head_t *instance, uint32_t pa)
     80/*----------------------------------------------------------------------------*/
     81/** Set queue head element pointer
     82 *
     83 * @param[in] instance qh_t structure to initialize.
     84 * @param[in] pa Physical address of the next queue head.
     85 *
     86 * Adds proper flag. If the pointer is NULL or terminal, sets element
     87 * to terminal NULL.
     88 */
     89static inline void qh_set_element_qh(qh_t *instance, uint32_t pa)
    6690{
    67         if (pa) {
    68                 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK)
     91        /* Address is valid and not terminal */
     92        if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
     93                instance->element = (pa & LINK_POINTER_ADDRESS_MASK)
    6994                    | LINK_POINTER_QUEUE_HEAD_FLAG;
     95        } else {
     96                instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
    7097        }
    7198}
    72 
    73 static inline void queue_head_element_td(queue_head_t *instance, uint32_t pa)
     99/*----------------------------------------------------------------------------*/
     100/** Set queue head element pointer
     101 *
     102 * @param[in] instance qh_t structure to initialize.
     103 * @param[in] pa Physical address of the TD structure.
     104 *
     105 * Adds proper flag. If the pointer is NULL or terminal, sets element
     106 * to terminal NULL.
     107 */
     108static inline void qh_set_element_td(qh_t *instance, uint32_t pa)
    74109{
    75         if (pa) {
     110        if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
    76111                instance->element = (pa & LINK_POINTER_ADDRESS_MASK);
     112        } else {
     113                instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
    77114        }
    78115}
    79 
    80 static inline queue_head_t * queue_head_get() {
    81         queue_head_t *ret = malloc32(sizeof(queue_head_t));
    82         if (ret)
    83                 queue_head_init(ret);
    84         return ret;
    85 }
    86 
    87 static inline void queue_head_dispose(queue_head_t *head)
    88         { free32(head); }
    89 
    90116
    91117#endif
  • uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcihc
    2929 * @{
    3030 */
     
    3838#include "utils/malloc32.h"
    3939
    40 void transfer_descriptor_init(transfer_descriptor_t *instance,
    41     int error_count, size_t size, bool toggle, bool isochronous, bool low_speed,
    42     usb_target_t target, int pid, void *buffer, transfer_descriptor_t *next)
     40/** Initialize Transfer Descriptor
     41 *
     42 * @param[in] instance Memory place to initialize.
     43 * @param[in] err_count Number of retries hc should attempt.
     44 * @param[in] size Size of data source.
     45 * @param[in] toggle Value of toggle bit.
     46 * @param[in] iso True if TD represents Isochronous transfer.
     47 * @param[in] low_speed Target device's speed.
     48 * @param[in] target Address and endpoint receiving the transfer.
     49 * @param[in] pid Packet identification (SETUP, IN or OUT).
     50 * @param[in] buffer Source of data.
     51 * @param[in] next Net TD in transaction.
     52 * @return Error code.
     53 *
     54 * Uses a mix of supplied and default values.
     55 * Implicit values:
     56 *  - all TDs have vertical flag set (makes transfers to endpoints atomic)
     57 *  - in the error field only active it is set
     58 *  - if the packet uses PID_IN and is not isochronous SPD is set
     59 *
     60 * Dumps 8 bytes of buffer if PID_SETUP is used.
     61 */
     62void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso,
     63    bool low_speed, usb_target_t target, usb_packet_id pid, void *buffer,
     64    td_t *next)
    4365{
    4466        assert(instance);
     67        assert(size < 1024);
     68        assert((pid == USB_PID_SETUP) || (pid == USB_PID_IN)
     69            || (pid == USB_PID_OUT));
    4570
    4671        instance->next = 0
     
    4974
    5075        instance->status = 0
    51           | ((error_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS)
    52                 | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0)
    53           | TD_STATUS_ERROR_ACTIVE;
     76            | ((err_count & TD_STATUS_ERROR_COUNT_MASK) << TD_STATUS_ERROR_COUNT_POS)
     77            | (low_speed ? TD_STATUS_LOW_SPEED_FLAG : 0)
     78            | (iso ? TD_STATUS_ISOCHRONOUS_FLAG : 0)
     79            | TD_STATUS_ERROR_ACTIVE;
    5480
    55         assert(size < 1024);
     81        if (pid == USB_PID_IN && !iso) {
     82                instance->status |= TD_STATUS_SPD_FLAG;
     83        }
     84
    5685        instance->device = 0
    57                 | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS)
    58                 | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0)
    59                 | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS)
    60                 | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS)
    61                 | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS);
     86            | (((size - 1) & TD_DEVICE_MAXLEN_MASK) << TD_DEVICE_MAXLEN_POS)
     87            | (toggle ? TD_DEVICE_DATA_TOGGLE_ONE_FLAG : 0)
     88            | ((target.address & TD_DEVICE_ADDRESS_MASK) << TD_DEVICE_ADDRESS_POS)
     89            | ((target.endpoint & TD_DEVICE_ENDPOINT_MASK) << TD_DEVICE_ENDPOINT_POS)
     90            | ((pid & TD_DEVICE_PID_MASK) << TD_DEVICE_PID_POS);
    6291
    6392        instance->buffer_ptr = 0;
     
    6796        }
    6897
    69         usb_log_debug2("Created TD: %X:%X:%X:%X(%p).\n",
    70                 instance->next, instance->status, instance->device,
    71           instance->buffer_ptr, buffer);
     98        usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).\n",
     99            instance, instance->next, instance->status, instance->device,
     100            instance->buffer_ptr, buffer);
     101        td_print_status(instance);
     102        if (pid == USB_PID_SETUP) {
     103                usb_log_debug("SETUP BUFFER: %s\n",
     104                    usb_debug_str_buffer(buffer, 8, 8));
     105        }
    72106}
    73107/*----------------------------------------------------------------------------*/
    74 int transfer_descriptor_status(transfer_descriptor_t *instance)
     108/** Convert TD status into standard error code
     109 *
     110 * @param[in] instance TD structure to use.
     111 * @return Error code.
     112 */
     113int td_status(td_t *instance)
    75114{
    76115        assert(instance);
     
    96135        return EOK;
    97136}
     137/*----------------------------------------------------------------------------*/
     138/** Print values in status field (dw1) in a human readable way.
     139 *
     140 * @param[in] instance TD structure to use.
     141 */
     142void td_print_status(td_t *instance)
     143{
     144        assert(instance);
     145        const uint32_t s = instance->status;
     146        usb_log_debug2("TD(%p) status(%#x):%s %d,%s%s%s%s%s%s%s%s%s%s%s %d.\n",
     147            instance, instance->status,
     148            (s & TD_STATUS_SPD_FLAG) ? " SPD," : "",
     149            (s >> TD_STATUS_ERROR_COUNT_POS) & TD_STATUS_ERROR_COUNT_MASK,
     150            (s & TD_STATUS_LOW_SPEED_FLAG) ? " LOW SPEED," : "",
     151            (s & TD_STATUS_ISOCHRONOUS_FLAG) ? " ISOCHRONOUS," : "",
     152            (s & TD_STATUS_IOC_FLAG) ? " IOC," : "",
     153            (s & TD_STATUS_ERROR_ACTIVE) ? " ACTIVE," : "",
     154            (s & TD_STATUS_ERROR_STALLED) ? " STALLED," : "",
     155            (s & TD_STATUS_ERROR_BUFFER) ? " BUFFER," : "",
     156            (s & TD_STATUS_ERROR_BABBLE) ? " BABBLE," : "",
     157            (s & TD_STATUS_ERROR_NAK) ? " NAK," : "",
     158            (s & TD_STATUS_ERROR_CRC) ? " CRC/TIMEOUT," : "",
     159            (s & TD_STATUS_ERROR_BIT_STUFF) ? " BIT_STUFF," : "",
     160            (s & TD_STATUS_ERROR_RESERVED) ? " RESERVED," : "",
     161            (s >> TD_STATUS_ACTLEN_POS) & TD_STATUS_ACTLEN_MASK
     162        );
     163}
    98164/**
    99165 * @}
  • uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h

    r3e7b7cd r72af8da  
    11/*
    2  * Copyright (c) 2010 Jan Vesely
     2 * Copyright (c) 2011 Jan Vesely
    33 * All rights reserved.
    44 *
     
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcihc
    2929 * @{
    3030 */
     
    4545
    4646        volatile uint32_t status;
    47 
    4847#define TD_STATUS_RESERVED_MASK 0xc000f800
    4948#define TD_STATUS_SPD_FLAG ( 1 << 29 )
    5049#define TD_STATUS_ERROR_COUNT_POS ( 27 )
    5150#define TD_STATUS_ERROR_COUNT_MASK ( 0x3 )
    52 #define TD_STATUS_ERROR_COUNT_DEFAULT 3
    5351#define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26 )
    5452#define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25 )
    55 #define TD_STATUS_COMPLETE_INTERRUPT_FLAG ( 1 << 24 )
     53#define TD_STATUS_IOC_FLAG ( 1 << 24 )
    5654
    5755#define TD_STATUS_ERROR_ACTIVE ( 1 << 23 )
     
    7068
    7169        volatile uint32_t device;
    72 
    7370#define TD_DEVICE_MAXLEN_POS 21
    7471#define TD_DEVICE_MAXLEN_MASK ( 0x7ff )
     
    8582
    8683        /* there is 16 bytes of data available here, according to UHCI
    87          * Design guide, according to linux kernel the hardware does not care
    88          * we don't use it anyway
     84         * Design guide, according to linux kernel the hardware does not care,
     85         * it just needs to be aligned, we don't use it anyway
    8986         */
    90 } __attribute__((packed)) transfer_descriptor_t;
     87} __attribute__((packed)) td_t;
    9188
    9289
    93 void transfer_descriptor_init(transfer_descriptor_t *instance,
    94     int error_count, size_t size, bool toggle, bool isochronous, bool low_speed,
    95     usb_target_t target, int pid, void *buffer, transfer_descriptor_t * next);
     90void td_init(td_t *instance, int error_count, size_t size, bool toggle,
     91    bool iso, bool low_speed, usb_target_t target, usb_packet_id pid,
     92    void *buffer, td_t *next);
    9693
    97 int transfer_descriptor_status(transfer_descriptor_t *instance);
     94int td_status(td_t *instance);
    9895
    99 static inline size_t transfer_descriptor_actual_size(
    100     transfer_descriptor_t *instance)
     96void td_print_status(td_t *instance);
     97/*----------------------------------------------------------------------------*/
     98/** Helper function for parsing actual size out of TD.
     99 *
     100 * @param[in] instance TD structure to use.
     101 * @return Parsed actual size.
     102 */
     103static inline size_t td_act_size(td_t *instance)
    101104{
    102105        assert(instance);
     106        const uint32_t s = instance->status;
     107        return ((s >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;
     108}
     109/*----------------------------------------------------------------------------*/
     110/** Check whether less than max data were recieved and packet is marked as SPD.
     111 *
     112 * @param[in] instance TD structure to use.
     113 * @return True if packet is short (less than max bytes and SPD set), false
     114 *     otherwise.
     115 */
     116static inline bool td_is_short(td_t *instance)
     117{
     118        const size_t act_size = td_act_size(instance);
     119        const size_t max_size =
     120            ((instance->device >> TD_DEVICE_MAXLEN_POS) + 1)
     121            & TD_DEVICE_MAXLEN_MASK;
    103122        return
    104             ((instance->status >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;
     123            (instance->status | TD_STATUS_SPD_FLAG) && act_size < max_size;
    105124}
    106 
    107 static inline bool transfer_descriptor_is_active(
    108     transfer_descriptor_t *instance)
     125/*----------------------------------------------------------------------------*/
     126/** Helper function for parsing value of toggle bit.
     127 *
     128 * @param[in] instance TD structure to use.
     129 * @return Toggle bit value.
     130 */
     131static inline int td_toggle(td_t *instance)
     132{
     133        assert(instance);
     134        return (instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) ? 1 : 0;
     135}
     136/*----------------------------------------------------------------------------*/
     137/** Helper function for parsing value of active bit
     138 *
     139 * @param[in] instance TD structure to use.
     140 * @return Active bit value.
     141 */
     142static inline bool td_is_active(td_t *instance)
    109143{
    110144        assert(instance);
    111145        return (instance->status & TD_STATUS_ERROR_ACTIVE) != 0;
    112146}
     147/*----------------------------------------------------------------------------*/
     148/** Helper function for setting IOC bit.
     149 *
     150 * @param[in] instance TD structure to use.
     151 */
     152static inline void td_set_ioc(td_t *instance)
     153{
     154        assert(instance);
     155        instance->status |= TD_STATUS_IOC_FLAG;
     156}
     157/*----------------------------------------------------------------------------*/
    113158#endif
    114159/**
  • uspace/drv/uhci-hcd/utils/device_keeper.c

    r3e7b7cd r72af8da  
    2727 */
    2828
    29 /** @addtogroup drvusbuhci
     29/** @addtogroup drvusbuhcihc
    3030 * @{
    3131 */
     
    3535#include <assert.h>
    3636#include <errno.h>
     37#include <usb/debug.h>
    3738
    3839#include "device_keeper.h"
    3940
    4041/*----------------------------------------------------------------------------*/
     42/** Initialize device keeper structure.
     43 *
     44 * @param[in] instance Memory place to initialize.
     45 *
     46 * Set all values to false/0.
     47 */
    4148void device_keeper_init(device_keeper_t *instance)
    4249{
     
    4956                instance->devices[i].occupied = false;
    5057                instance->devices[i].handle = 0;
    51         }
    52 }
    53 /*----------------------------------------------------------------------------*/
    54 void device_keeper_reserve_default(
    55     device_keeper_t *instance, usb_speed_t speed)
     58                instance->devices[i].toggle_status = 0;
     59        }
     60}
     61/*----------------------------------------------------------------------------*/
     62/** Attempt to obtain address 0, blocks.
     63 *
     64 * @param[in] instance Device keeper structure to use.
     65 * @param[in] speed Speed of the device requesting default address.
     66 */
     67void device_keeper_reserve_default(device_keeper_t *instance, usb_speed_t speed)
    5668{
    5769        assert(instance);
     
    6678}
    6779/*----------------------------------------------------------------------------*/
     80/** Attempt to obtain address 0, blocks.
     81 *
     82 * @param[in] instance Device keeper structure to use.
     83 * @param[in] speed Speed of the device requesting default address.
     84 */
    6885void device_keeper_release_default(device_keeper_t *instance)
    6986{
     
    7592}
    7693/*----------------------------------------------------------------------------*/
     94/** Check setup packet data for signs of toggle reset.
     95 *
     96 * @param[in] instance Device keeper structure to use.
     97 * @param[in] target Device to receive setup packet.
     98 * @param[in] data Setup packet data.
     99 *
     100 * Really ugly one.
     101 */
     102void device_keeper_reset_if_need(
     103    device_keeper_t *instance, usb_target_t target, const unsigned char *data)
     104{
     105        assert(instance);
     106        fibril_mutex_lock(&instance->guard);
     107        if (target.endpoint > 15 || target.endpoint < 0
     108            || target.address >= USB_ADDRESS_COUNT || target.address < 0
     109            || !instance->devices[target.address].occupied) {
     110                fibril_mutex_unlock(&instance->guard);
     111                usb_log_error("Invalid data when checking for toggle reset.\n");
     112                return;
     113        }
     114
     115        switch (data[1])
     116        {
     117        case 0x01: /*clear feature*/
     118                /* recipient is endpoint, value is zero (ENDPOINT_STALL) */
     119                if (((data[0] & 0xf) == 1) && ((data[2] | data[3]) == 0)) {
     120                        /* endpoint number is < 16, thus first byte is enough */
     121                        instance->devices[target.address].toggle_status &=
     122                            ~(1 << data[4]);
     123                }
     124        break;
     125
     126        case 0x9: /* set configuration */
     127        case 0x11: /* set interface */
     128                /* target must be device */
     129                if ((data[0] & 0xf) == 0) {
     130                        instance->devices[target.address].toggle_status = 0;
     131                }
     132        break;
     133        }
     134        fibril_mutex_unlock(&instance->guard);
     135}
     136/*----------------------------------------------------------------------------*/
     137/** Get current value of endpoint toggle.
     138 *
     139 * @param[in] instance Device keeper structure to use.
     140 * @param[in] target Device and endpoint used.
     141 * @return Error code
     142 */
     143int device_keeper_get_toggle(device_keeper_t *instance, usb_target_t target)
     144{
     145        assert(instance);
     146        int ret;
     147        fibril_mutex_lock(&instance->guard);
     148        if (target.endpoint > 15 || target.endpoint < 0
     149            || target.address >= USB_ADDRESS_COUNT || target.address < 0
     150            || !instance->devices[target.address].occupied) {
     151                usb_log_error("Invalid data when asking for toggle value.\n");
     152                ret = EINVAL;
     153        } else {
     154                ret = (instance->devices[target.address].toggle_status
     155                        >> target.endpoint) & 1;
     156        }
     157        fibril_mutex_unlock(&instance->guard);
     158        return ret;
     159}
     160/*----------------------------------------------------------------------------*/
     161/** Set current value of endpoint toggle.
     162 *
     163 * @param[in] instance Device keeper structure to use.
     164 * @param[in] target Device and endpoint used.
     165 * @param[in] toggle Toggle value.
     166 * @return Error code.
     167 */
     168int device_keeper_set_toggle(
     169    device_keeper_t *instance, usb_target_t target, bool toggle)
     170{
     171        assert(instance);
     172        int ret;
     173        fibril_mutex_lock(&instance->guard);
     174        if (target.endpoint > 15 || target.endpoint < 0
     175            || target.address >= USB_ADDRESS_COUNT || target.address < 0
     176            || !instance->devices[target.address].occupied) {
     177                usb_log_error("Invalid data when setting toggle value.\n");
     178                ret = EINVAL;
     179        } else {
     180                if (toggle) {
     181                        instance->devices[target.address].toggle_status |= (1 << target.endpoint);
     182                } else {
     183                        instance->devices[target.address].toggle_status &= ~(1 << target.endpoint);
     184                }
     185                ret = EOK;
     186        }
     187        fibril_mutex_unlock(&instance->guard);
     188        return ret;
     189}
     190/*----------------------------------------------------------------------------*/
     191/** Get a free USB address
     192 *
     193 * @param[in] instance Device keeper structure to use.
     194 * @param[in] speed Speed of the device requiring address.
     195 * @return Free address, or error code.
     196 */
    77197usb_address_t device_keeper_request(
    78198    device_keeper_t *instance, usb_speed_t speed)
     
    96216        instance->devices[new_address].occupied = true;
    97217        instance->devices[new_address].speed = speed;
     218        instance->devices[new_address].toggle_status = 0;
    98219        instance->last_address = new_address;
    99220        fibril_mutex_unlock(&instance->guard);
     
    101222}
    102223/*----------------------------------------------------------------------------*/
     224/** Bind USB address to devman handle.
     225 *
     226 * @param[in] instance Device keeper structure to use.
     227 * @param[in] address Device address
     228 * @param[in] handle Devman handle of the device.
     229 */
    103230void device_keeper_bind(
    104231    device_keeper_t *instance, usb_address_t address, devman_handle_t handle)
     
    113240}
    114241/*----------------------------------------------------------------------------*/
     242/** Release used USB address.
     243 *
     244 * @param[in] instance Device keeper structure to use.
     245 * @param[in] address Device address
     246 */
    115247void device_keeper_release(device_keeper_t *instance, usb_address_t address)
    116248{
     
    125257}
    126258/*----------------------------------------------------------------------------*/
     259/** Find USB address associated with the device
     260 *
     261 * @param[in] instance Device keeper structure to use.
     262 * @param[in] handle Devman handle of the device seeking its address.
     263 * @return USB Address, or error code.
     264 */
    127265usb_address_t device_keeper_find(
    128266    device_keeper_t *instance, devman_handle_t handle)
     
    142280}
    143281/*----------------------------------------------------------------------------*/
     282/** Get speed associated with the address
     283 *
     284 * @param[in] instance Device keeper structure to use.
     285 * @param[in] address Address of the device.
     286 * @return USB speed.
     287 */
    144288usb_speed_t device_keeper_speed(
    145289    device_keeper_t *instance, usb_address_t address)
  • uspace/drv/uhci-hcd/utils/device_keeper.h

    r3e7b7cd r72af8da  
    2727 */
    2828
    29 /** @addtogroup drvusbuhci
     29/** @addtogroup drvusbuhcihc
    3030 * @{
    3131 */
     
    4444        usb_speed_t speed;
    4545        bool occupied;
     46        uint16_t toggle_status;
    4647        devman_handle_t handle;
    4748};
     
    5556
    5657void device_keeper_init(device_keeper_t *instance);
     58
    5759void device_keeper_reserve_default(
    5860    device_keeper_t *instance, usb_speed_t speed);
     61
    5962void device_keeper_release_default(device_keeper_t *instance);
     63
     64void device_keeper_reset_if_need(
     65    device_keeper_t *instance, usb_target_t target, const unsigned char *setup_data);
     66
     67int device_keeper_get_toggle(device_keeper_t *instance, usb_target_t target);
     68
     69int device_keeper_set_toggle(
     70    device_keeper_t *instance, usb_target_t target, bool toggle);
    6071
    6172usb_address_t device_keeper_request(
    6273    device_keeper_t *instance, usb_speed_t speed);
     74
    6375void device_keeper_bind(
    6476    device_keeper_t *instance, usb_address_t address, devman_handle_t handle);
     77
    6578void device_keeper_release(device_keeper_t *instance, usb_address_t address);
     79
    6680usb_address_t device_keeper_find(
    6781    device_keeper_t *instance, devman_handle_t handle);
  • uspace/drv/uhci-hcd/utils/malloc32.h

    r3e7b7cd r72af8da  
    3535#define DRV_UHCI_TRANSLATOR_H
    3636
    37 #include <usb/usbmem.h>
    38 
    3937#include <assert.h>
    4038#include <malloc.h>
     
    4543#define UHCI_REQUIRED_PAGE_SIZE 4096
    4644
     45/** Get physical address translation
     46 *
     47 * @param[in] addr Virtual address to translate
     48 * @return Physical address if exists, NULL otherwise.
     49 */
    4750static inline uintptr_t addr_to_phys(void *addr)
    4851{
     
    5053        int ret = as_get_physical_mapping(addr, &result);
    5154
    52         assert(ret == 0);
     55        if (ret != EOK)
     56                return 0;
    5357        return (result | ((uintptr_t)addr & 0xfff));
    5458}
    55 
     59/*----------------------------------------------------------------------------*/
     60/** Physical mallocator simulator
     61 *
     62 * @param[in] size Size of the required memory space
     63 * @return Address of the alligned and big enough memory place, NULL on failure.
     64 */
    5665static inline void * malloc32(size_t size)
    5766        { return memalign(UHCI_STRCUTURES_ALIGNMENT, size); }
    58 
    59 static inline void * get_page()
     67/*----------------------------------------------------------------------------*/
     68/** Physical mallocator simulator
     69 *
     70 * @param[in] addr Address of the place allocated by malloc32
     71 */
     72static inline void free32(void *addr)
     73        { if (addr) free(addr); }
     74/*----------------------------------------------------------------------------*/
     75/** Create 4KB page mapping
     76 *
     77 * @return Address of the mapped page, NULL on failure.
     78 */
     79static inline void * get_page(void)
    6080{
    6181        void * free_address = as_get_mappable_page(UHCI_REQUIRED_PAGE_SIZE);
    6282        assert(free_address);
    6383        if (free_address == 0)
    64                 return 0;
     84                return NULL;
    6585        void* ret =
    6686          as_area_create(free_address, UHCI_REQUIRED_PAGE_SIZE,
    6787                  AS_AREA_READ | AS_AREA_WRITE);
    6888        if (ret != free_address)
    69                 return 0;
     89                return NULL;
    7090        return ret;
    7191}
    72 
    73 static inline void free32(void *addr)
    74         { if (addr) free(addr); }
    7592
    7693#endif
Note: See TracChangeset for help on using the changeset viewer.