Changes in / [335382d:0f3e68c] in mainline


Ignore:
Location:
uspace/drv/uhci-hcd
Files:
2 added
4 deleted
14 edited

Legend:

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

    r335382d r0f3e68c  
    3535        iface.c \
    3636        main.c \
     37        root_hub.c \
    3738        transfer_list.c \
    3839        uhci.c \
    39         uhci_hc.c \
    40         uhci_rh.c \
    4140        uhci_struct/transfer_descriptor.c \
    4241        utils/device_keeper.c \
  • uspace/drv/uhci-hcd/batch.c

    r335382d r0f3e68c  
    4040#include "batch.h"
    4141#include "transfer_list.h"
    42 #include "uhci_hc.h"
     42#include "uhci.h"
    4343#include "utils/malloc32.h"
    4444
     
    100100        bzero(instance, sizeof(batch_t));
    101101
    102         instance->qh = malloc32(sizeof(qh_t));
     102        instance->qh = malloc32(sizeof(queue_head_t));
    103103        CHECK_NULL_DISPOSE_RETURN(instance->qh,
    104104            "Failed to allocate batch queue head.\n");
    105         qh_init(instance->qh);
     105        queue_head_init(instance->qh);
    106106
    107107        instance->packets = (size + max_packet_size - 1) / max_packet_size;
     
    114114            instance->tds, "Failed to allocate transfer descriptors.\n");
    115115        bzero(instance->tds, sizeof(td_t) * instance->packets);
     116
     117//      const size_t transport_size = max_packet_size * instance->packets;
    116118
    117119        if (size > 0) {
     
    141143        instance->speed = speed;
    142144        instance->manager = manager;
    143         instance->callback_out = func_out;
    144         instance->callback_in = func_in;
    145 
    146         qh_set_element_td(instance->qh, addr_to_phys(instance->tds));
     145
     146        if (func_out)
     147                instance->callback_out = func_out;
     148        if (func_in)
     149                instance->callback_in = func_in;
     150
     151        queue_head_set_element_td(instance->qh, addr_to_phys(instance->tds));
    147152
    148153        usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
     
    314319                ++packet;
    315320        }
    316         td_set_ioc(&instance->tds[packet - 1]);
     321        instance->tds[packet - 1].status |= TD_STATUS_IOC_FLAG;
    317322        device_keeper_set_toggle(instance->manager, instance->target, toggle);
    318323}
     
    366371            0, 1, false, low_speed, instance->target, status_stage, NULL, NULL);
    367372
    368         td_set_ioc(&instance->tds[packet]);
     373
     374        instance->tds[packet].status |= TD_STATUS_IOC_FLAG;
    369375        usb_log_debug2("Control last TD status: %x.\n",
    370376            instance->tds[packet].status);
     
    450456{
    451457        assert(instance);
    452         uhci_hc_t *hc = fun_to_uhci_hc(instance->fun);
     458        uhci_t *hc = fun_to_uhci(instance->fun);
    453459        assert(hc);
    454         return uhci_hc_schedule(hc, instance);
     460        return uhci_schedule(hc, instance);
    455461}
    456462/**
  • uspace/drv/uhci-hcd/batch.h

    r335382d r0f3e68c  
    5050        usb_target_t target;
    5151        usb_transfer_type_t transfer_type;
    52         usbhc_iface_transfer_in_callback_t callback_in;
    53         usbhc_iface_transfer_out_callback_t callback_out;
     52        union {
     53                usbhc_iface_transfer_in_callback_t callback_in;
     54                usbhc_iface_transfer_out_callback_t callback_out;
     55        };
    5456        void *arg;
    5557        char *transport_buffer;
     
    6365        int error;
    6466        ddf_fun_t *fun;
    65         qh_t *qh;
     67        queue_head_t *qh;
    6668        td_t *tds;
    6769        void (*next_step)(struct batch*);
  • uspace/drv/uhci-hcd/iface.c

    r335382d r0f3e68c  
    4040
    4141#include "iface.h"
    42 #include "uhci_hc.h"
     42#include "uhci.h"
    4343#include "utils/device_keeper.h"
    4444
     
    5353{
    5454        assert(fun);
    55         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     55        uhci_t *hc = fun_to_uhci(fun);
    5656        assert(hc);
    5757        usb_log_debug("Default address request with speed %d.\n", speed);
     
    6868{
    6969        assert(fun);
    70         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     70        uhci_t *hc = fun_to_uhci(fun);
    7171        assert(hc);
    7272        usb_log_debug("Default address release.\n");
     
    8686{
    8787        assert(fun);
    88         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     88        uhci_t *hc = fun_to_uhci(fun);
    8989        assert(hc);
    9090        assert(address);
     
    109109{
    110110        assert(fun);
    111         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     111        uhci_t *hc = fun_to_uhci(fun);
    112112        assert(hc);
    113113        usb_log_debug("Address bind %d-%d.\n", address, handle);
     
    125125{
    126126        assert(fun);
    127         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     127        uhci_t *hc = fun_to_uhci(fun);
    128128        assert(hc);
    129129        usb_log_debug("Address release %d.\n", address);
     
    148148{
    149149        assert(fun);
    150         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     150        uhci_t *hc = fun_to_uhci(fun);
    151151        assert(hc);
    152152        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     
    180180{
    181181        assert(fun);
    182         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     182        uhci_t *hc = fun_to_uhci(fun);
    183183        assert(hc);
    184184        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     
    211211{
    212212        assert(fun);
    213         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     213        uhci_t *hc = fun_to_uhci(fun);
    214214        assert(hc);
    215215        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     
    243243{
    244244        assert(fun);
    245         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     245        uhci_t *hc = fun_to_uhci(fun);
    246246        assert(hc);
    247247        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     
    277277{
    278278        assert(fun);
    279         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     279        uhci_t *hc = fun_to_uhci(fun);
    280280        assert(hc);
    281281        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     
    315315{
    316316        assert(fun);
    317         uhci_hc_t *hc = fun_to_uhci_hc(fun);
     317        uhci_t *hc = fun_to_uhci(fun);
    318318        assert(hc);
    319319        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     
    330330}
    331331/*----------------------------------------------------------------------------*/
    332 usbhc_iface_t uhci_hc_iface = {
     332usbhc_iface_t uhci_iface = {
    333333        .reserve_default_address = reserve_default_address,
    334334        .release_default_address = release_default_address,
  • uspace/drv/uhci-hcd/iface.h

    r335382d r0f3e68c  
    3838#include <usbhc_iface.h>
    3939
    40 extern usbhc_iface_t uhci_hc_iface;
     40extern usbhc_iface_t uhci_iface;
    4141
    4242#endif
  • uspace/drv/uhci-hcd/main.c

    r335382d r0f3e68c  
    3333 */
    3434#include <ddf/driver.h>
     35#include <ddf/interrupt.h>
     36#include <device/hw_res.h>
    3537#include <errno.h>
    3638#include <str_error.h>
    3739
     40#include <usb_iface.h>
    3841#include <usb/ddfiface.h>
    3942#include <usb/debug.h>
    4043
    4144#include "iface.h"
     45#include "pci.h"
     46#include "root_hub.h"
    4247#include "uhci.h"
    4348
     
    5560};
    5661/*----------------------------------------------------------------------------*/
    57 /** Initializes a new ddf driver instance for uhci hc and hub.
     62/** IRQ handling callback, identifies devic
     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 void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
     69{
     70        assert(dev);
     71        uhci_t *hc = dev_to_uhci(dev);
     72        uint16_t status = IPC_GET_ARG1(*call);
     73        assert(hc);
     74        uhci_interrupt(hc, status);
     75}
     76/*----------------------------------------------------------------------------*/
     77/** Initializes a new ddf driver instance of UHCI hcd.
    5878 *
    5979 * @param[in] device DDF instance of the device to initialize.
     
    6585int uhci_add_device(ddf_dev_t *device)
    6686{
     87        assert(device);
     88        uhci_t *hcd = NULL;
     89#define CHECK_RET_FREE_HC_RETURN(ret, message...) \
     90if (ret != EOK) { \
     91        usb_log_error(message); \
     92        if (hcd != NULL) \
     93                free(hcd); \
     94        return ret; \
     95}
     96
    6797        usb_log_info("uhci_add_device() called\n");
    68         assert(device);
    69         uhci_t *uhci = malloc(sizeof(uhci_t));
    70         if (uhci == NULL) {
    71                 usb_log_error("Failed to allocate UHCI driver.\n");
    72                 return ENOMEM;
     98
     99        uintptr_t io_reg_base = 0;
     100        size_t io_reg_size = 0;
     101        int irq = 0;
     102
     103        int ret =
     104            pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq);
     105        CHECK_RET_FREE_HC_RETURN(ret,
     106            "Failed(%d) to get I/O addresses:.\n", ret, device->handle);
     107        usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n",
     108            io_reg_base, io_reg_size, irq);
     109
     110        ret = pci_disable_legacy(device);
     111        CHECK_RET_FREE_HC_RETURN(ret,
     112            "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret));
     113
     114#if 0
     115        ret = pci_enable_interrupts(device);
     116        if (ret != EOK) {
     117                usb_log_warning(
     118                    "Failed(%d) to enable interrupts, fall back to polling.\n",
     119                    ret);
    73120        }
     121#endif
    74122
    75         int ret = uhci_init(uhci, device);
    76         if (ret != EOK) {
    77                 usb_log_error("Failed to initialzie UHCI driver.\n");
    78                 return ret;
    79         }
    80         device->driver_data = uhci;
     123        hcd = malloc(sizeof(uhci_t));
     124        ret = (hcd != NULL) ? EOK : ENOMEM;
     125        CHECK_RET_FREE_HC_RETURN(ret,
     126            "Failed(%d) to allocate memory for uhci hcd.\n", ret);
     127
     128        ret = uhci_init(hcd, device, (void*)io_reg_base, io_reg_size);
     129        CHECK_RET_FREE_HC_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret);
     130#undef CHECK_RET_FREE_HC_RETURN
     131
     132        /*
     133         * We might free hcd, but that does not matter since no one
     134         * else would access driver_data anyway.
     135         */
     136        device->driver_data = hcd;
     137
     138        ddf_fun_t *rh = NULL;
     139#define CHECK_RET_FINI_FREE_RETURN(ret, message...) \
     140if (ret != EOK) { \
     141        usb_log_error(message); \
     142        if (hcd != NULL) {\
     143                uhci_fini(hcd); \
     144                free(hcd); \
     145        } \
     146        if (rh != NULL) \
     147                free(rh); \
     148        return ret; \
     149}
     150
     151        /* It does no harm if we register this on polling */
     152        ret = register_interrupt_handler(device, irq, irq_handler,
     153            &hcd->interrupt_code);
     154        CHECK_RET_FINI_FREE_RETURN(ret,
     155            "Failed(%d) to register interrupt handler.\n", ret);
     156
     157        ret = setup_root_hub(&rh, device);
     158        CHECK_RET_FINI_FREE_RETURN(ret,
     159            "Failed(%d) to setup UHCI root hub.\n", ret);
     160        rh->driver_data = hcd->ddf_instance;
     161
     162        ret = ddf_fun_bind(rh);
     163        CHECK_RET_FINI_FREE_RETURN(ret,
     164            "Failed(%d) to register UHCI root hub.\n", ret);
     165
    81166        return EOK;
     167#undef CHECK_RET_FINI_FREE_RETURN
    82168}
    83169/*----------------------------------------------------------------------------*/
  • uspace/drv/uhci-hcd/transfer_list.c

    r335382d r0f3e68c  
    4747 * @return Error code
    4848 *
    49  * Allocates memory for internal qh_t structure.
     49 * Allocates memory for internat queue_head_t structure.
    5050 */
    5151int transfer_list_init(transfer_list_t *instance, const char *name)
    5252{
    5353        assert(instance);
     54        instance->next = NULL;
    5455        instance->name = name;
    55         instance->queue_head = malloc32(sizeof(qh_t));
     56        instance->queue_head = malloc32(sizeof(queue_head_t));
    5657        if (!instance->queue_head) {
    5758                usb_log_error("Failed to allocate queue head.\n");
     
    6061        instance->queue_head_pa = addr_to_phys(instance->queue_head);
    6162
    62         qh_init(instance->queue_head);
     63        queue_head_init(instance->queue_head);
    6364        list_initialize(&instance->batch_list);
    6465        fibril_mutex_initialize(&instance->guard);
     
    7172 * @param[in] next List to append.
    7273 * @return Error code
    73  *
    74  * Does not check whether there was a next list already.
    7574 */
    7675void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next)
     
    8079        if (!instance->queue_head)
    8180                return;
    82         /* set both next and element to point to the same QH */
    83         qh_set_next_qh(instance->queue_head, next->queue_head_pa);
    84         qh_set_element_qh(instance->queue_head, next->queue_head_pa);
     81        queue_head_append_qh(instance->queue_head, next->queue_head_pa);
     82        instance->queue_head->element = instance->queue_head->next_queue;
    8583}
    8684/*----------------------------------------------------------------------------*/
     
    9593        assert(instance);
    9694        assert(batch);
    97         usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch);
     95        usb_log_debug2(
     96            "Adding batch(%p) to queue %s.\n", batch, instance->name);
    9897
    99         const uint32_t pa = addr_to_phys(batch->qh);
     98        uint32_t pa = (uintptr_t)addr_to_phys(batch->qh);
    10099        assert((pa & LINK_POINTER_ADDRESS_MASK) == pa);
     100        pa |= LINK_POINTER_QUEUE_HEAD_FLAG;
    101101
    102         /* New batch will be added to the end of the current list
    103          * so set the link accordingly */
    104         qh_set_next_qh(batch->qh, instance->queue_head->next);
     102        batch->qh->next_queue = instance->queue_head->next_queue;
    105103
    106104        fibril_mutex_lock(&instance->guard);
    107105
    108         if (list_empty(&instance->batch_list)) {
    109                 /* There is nothing scheduled */
    110                 qh_t *qh = instance->queue_head;
    111                 assert(qh->element == qh->next);
    112                 qh_set_element_qh(qh, pa);
    113         } else {
    114                 /* There is something scheduled */
    115                 batch_t *last = list_get_instance(
    116                     instance->batch_list.prev, batch_t, link);
    117                 qh_set_next_qh(last->qh, pa);
     106        if (instance->queue_head->element == instance->queue_head->next_queue) {
     107                /* there is nothing scheduled */
     108                list_append(&batch->link, &instance->batch_list);
     109                instance->queue_head->element = pa;
     110                usb_log_debug("Batch(%p) added to queue %s first.\n",
     111                        batch, instance->name);
     112                fibril_mutex_unlock(&instance->guard);
     113                return;
    118114        }
     115        /* now we can be sure that there is someting scheduled */
     116        assert(!list_empty(&instance->batch_list));
     117        batch_t *first = list_get_instance(
     118                  instance->batch_list.next, batch_t, link);
     119        batch_t *last = list_get_instance(
     120            instance->batch_list.prev, batch_t, link);
     121        queue_head_append_qh(last->qh, pa);
    119122        list_append(&batch->link, &instance->batch_list);
    120123
    121         batch_t *first = list_get_instance(
    122             instance->batch_list.next, batch_t, link);
    123         usb_log_debug("Batch(%p) added to queue %s, first is %p.\n",
     124        usb_log_debug("Batch(%p) added to queue %s last, first is %p.\n",
    124125                batch, instance->name, first);
    125126        fibril_mutex_unlock(&instance->guard);
    126127}
    127128/*----------------------------------------------------------------------------*/
    128 /** Removes a transfer batch from the list and queue.
     129/** Removes a transfer batch from list and queue.
    129130 *
    130131 * @param[in] instance List to use.
    131132 * @param[in] batch Transfer batch to remove.
    132133 * @return Error code
    133  *
    134  * Does not lock the transfer list, caller is responsible for that.
    135134 */
    136135void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch)
     
    141140        assert(batch->qh);
    142141        usb_log_debug2(
    143             "Queue %s: removing batch(%p).\n", instance->name, batch);
     142            "Removing batch(%p) from queue %s.\n", batch, instance->name);
    144143
    145         const char * pos = NULL;
    146144        if (batch->link.prev == &instance->batch_list) {
    147145                /* I'm the first one here */
    148                 qh_set_element_qh(instance->queue_head, batch->qh->next);
    149                 pos = "FIRST";
     146                usb_log_debug(
     147                    "Batch(%p) removed (FIRST) from %s, next element %x.\n",
     148                    batch, instance->name, batch->qh->next_queue);
     149                instance->queue_head->element = batch->qh->next_queue;
    150150        } else {
     151                usb_log_debug(
     152                    "Batch(%p) removed (FIRST:NO) from %s, next element %x.\n",
     153                    batch, instance->name, batch->qh->next_queue);
    151154                batch_t *prev =
    152155                    list_get_instance(batch->link.prev, batch_t, link);
    153                 qh_set_next_qh(prev->qh, batch->qh->next);
    154                 pos = "NOT FIRST";
     156                prev->qh->next_queue = batch->qh->next_queue;
    155157        }
    156158        list_remove(&batch->link);
    157         usb_log_debug("Batch(%p) removed (%s) from %s, next element %x.\n",
    158             batch, pos, instance->name, batch->qh->next);
    159159}
    160160/*----------------------------------------------------------------------------*/
    161 /** Checks list for finished batches.
     161/** Checks list for finished transfers.
    162162 *
    163163 * @param[in] instance List to use.
  • uspace/drv/uhci-hcd/transfer_list.h

    r335382d r0f3e68c  
    4444{
    4545        fibril_mutex_t guard;
    46         qh_t *queue_head;
     46        queue_head_t *queue_head;
    4747        uint32_t queue_head_pa;
     48        struct transfer_list *next;
    4849        const char *name;
    4950        link_t batch_list;
  • uspace/drv/uhci-hcd/uhci.c

    r335382d r0f3e68c  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 
    29 /** @addtogroup drvusbuhci
     28/** @addtogroup usb
    3029 * @{
    3130 */
     
    3534#include <errno.h>
    3635#include <str_error.h>
    37 #include <ddf/interrupt.h>
     36#include <adt/list.h>
     37#include <libarch/ddi.h>
     38
     39#include <usb/debug.h>
     40#include <usb/usb.h>
     41#include <usb/ddfiface.h>
    3842#include <usb_iface.h>
    39 #include <usb/ddfiface.h>
    40 #include <usb/debug.h>
    4143
    4244#include "uhci.h"
    4345#include "iface.h"
    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  */
    53 static 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 /*----------------------------------------------------------------------------*/
     46
     47static 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/** Gets USB address of the calling device.
     64 *
     65 * @param[in] fun UHCI hc function.
     66 * @param[in] handle Handle of the device seeking address.
     67 * @param[out] address Place to store found address.
     68 * @return Error code.
     69 */
    6270static int usb_iface_get_address(
    6371    ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
    6472{
    6573        assert(fun);
    66         device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.device_manager;
    67 
    68         usb_address_t addr = device_keeper_find(manager, handle);
     74        uhci_t *hc = fun_to_uhci(fun);
     75        assert(hc);
     76
     77        usb_address_t addr = device_keeper_find(&hc->device_manager,
     78            handle);
    6979        if (addr < 0) {
    7080                return addr;
     
    7888}
    7989/*----------------------------------------------------------------------------*/
    80 /** Gets handle of the respective hc (this or parent device).
    81  *
    82  * @param[in] root_hub_fun Root hub function seeking hc handle.
    83  * @param[out] handle Place to write the handle.
    84  * @return Error code.
    85  */
    86 static int usb_iface_get_hc_handle(
    87     ddf_fun_t *fun, devman_handle_t *handle)
    88 {
    89         assert(handle);
    90         ddf_fun_t *hc_fun = ((uhci_t*)fun->dev->driver_data)->hc_fun;
    91         assert(hc_fun != NULL);
    92 
    93         *handle = hc_fun->handle;
    94         return EOK;
    95 }
    96 /*----------------------------------------------------------------------------*/
    97 /** This iface is generic for both RH and HC. */
    98 static usb_iface_t usb_iface = {
    99         .get_hc_handle = usb_iface_get_hc_handle,
     90static usb_iface_t hc_usb_iface = {
     91        .get_hc_handle = usb_iface_get_hc_handle_hc_impl,
    10092        .get_address = usb_iface_get_address
    10193};
    10294/*----------------------------------------------------------------------------*/
    103 static ddf_dev_ops_t uhci_hc_ops = {
    104         .interfaces[USB_DEV_IFACE] = &usb_iface,
    105         .interfaces[USBHC_DEV_IFACE] = &uhci_hc_iface, /* see iface.h/c */
     95static ddf_dev_ops_t uhci_ops = {
     96        .interfaces[USB_DEV_IFACE] = &hc_usb_iface,
     97        .interfaces[USBHC_DEV_IFACE] = &uhci_iface,
    10698};
    10799/*----------------------------------------------------------------------------*/
    108 /** Gets root hub hw resources.
    109  *
    110  * @param[in] fun Root hub function.
    111  * @return Pointer to the resource list used by the root hub.
    112  */
    113 static hw_resource_list_t *get_resource_list(ddf_fun_t *fun)
    114 {
    115         assert(fun);
    116         return &((uhci_rh_t*)fun->driver_data)->resource_list;
    117 }
    118 /*----------------------------------------------------------------------------*/
    119 static hw_res_ops_t hw_res_iface = {
    120         .get_resource_list = get_resource_list,
    121         .enable_interrupt = NULL
    122 };
    123 /*----------------------------------------------------------------------------*/
    124 static ddf_dev_ops_t uhci_rh_ops = {
    125         .interfaces[USB_DEV_IFACE] = &usb_iface,
    126         .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface
    127 };
    128 /*----------------------------------------------------------------------------*/
    129 int uhci_init(uhci_t *instance, ddf_dev_t *device)
    130 {
    131         assert(instance);
    132         instance->hc_fun = NULL;
    133         instance->rh_fun = NULL;
     100static int uhci_init_transfer_lists(uhci_t *instance);
     101static int uhci_init_mem_structures(uhci_t *instance);
     102static void uhci_init_hw(uhci_t *instance);
     103
     104static int uhci_interrupt_emulator(void *arg);
     105static int uhci_debug_checker(void *arg);
     106
     107static bool allowed_usb_packet(
     108    bool low_speed, usb_transfer_type_t transfer, size_t size);
     109/*----------------------------------------------------------------------------*/
     110/** Initializes UHCI hcd driver structure
     111 *
     112 * @param[in] instance Memory place to initialize.
     113 * @param[in] dev DDF device.
     114 * @param[in] regs Address of I/O control registers.
     115 * @param[in] size Size of I/O control registers.
     116 * @return Error code.
     117 * @note Should be called only once on any structure.
     118 */
     119int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size)
     120{
     121        assert(reg_size >= sizeof(regs_t));
     122        int ret;
     123
    134124#define CHECK_RET_DEST_FUN_RETURN(ret, message...) \
    135 if (ret != EOK) { \
    136         usb_log_error(message); \
    137         if (instance->hc_fun) \
    138                 ddf_fun_destroy(instance->hc_fun); \
    139         if (instance->rh_fun) \
    140                 ddf_fun_destroy(instance->rh_fun); \
    141         return ret; \
    142 }
    143 
    144         uintptr_t io_reg_base = 0;
    145         size_t io_reg_size = 0;
    146         int irq = 0;
    147 
    148         int ret =
    149             pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq);
     125        if (ret != EOK) { \
     126                usb_log_error(message); \
     127                if (instance->ddf_instance) \
     128                        ddf_fun_destroy(instance->ddf_instance); \
     129                return ret; \
     130        } else (void) 0
     131
     132        /* Create UHCI function. */
     133        instance->ddf_instance = ddf_fun_create(dev, fun_exposed, "uhci");
     134        ret = (instance->ddf_instance == NULL) ? ENOMEM : EOK;
    150135        CHECK_RET_DEST_FUN_RETURN(ret,
    151             "Failed(%d) to get I/O addresses:.\n", ret, device->handle);
    152         usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n",
    153             io_reg_base, io_reg_size, irq);
    154 
    155         ret = pci_disable_legacy(device);
    156         CHECK_RET_DEST_FUN_RETURN(ret,
    157             "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret));
    158 
    159 #if 0
    160         ret = pci_enable_interrupts(device);
    161         if (ret != EOK) {
    162                 usb_log_warning(
    163                     "Failed(%d) to enable interrupts, fall back to polling.\n",
    164                     ret);
    165         }
    166 #endif
    167 
    168         instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci-hc");
    169         ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
    170         CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to create HC function.\n", ret);
    171 
    172         ret = uhci_hc_init(
    173             &instance->hc, instance->hc_fun, (void*)io_reg_base, io_reg_size);
    174         CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret);
    175         instance->hc_fun->ops = &uhci_hc_ops;
    176         instance->hc_fun->driver_data = &instance->hc;
    177         ret = ddf_fun_bind(instance->hc_fun);
     136            "Failed to create UHCI device function.\n");
     137
     138        instance->ddf_instance->ops = &uhci_ops;
     139        instance->ddf_instance->driver_data = instance;
     140
     141        ret = ddf_fun_bind(instance->ddf_instance);
    178142        CHECK_RET_DEST_FUN_RETURN(ret,
    179143            "Failed(%d) to bind UHCI device function: %s.\n",
    180144            ret, str_error(ret));
    181 #undef CHECK_RET_HC_RETURN
    182 
    183 #define CHECK_RET_FINI_RETURN(ret, message...) \
    184 if (ret != EOK) { \
    185         usb_log_error(message); \
    186         if (instance->hc_fun) \
    187                 ddf_fun_destroy(instance->hc_fun); \
    188         if (instance->rh_fun) \
    189                 ddf_fun_destroy(instance->rh_fun); \
    190         uhci_hc_fini(&instance->hc); \
    191         return ret; \
    192 }
    193 
    194         /* It does no harm if we register this on polling */
    195         ret = register_interrupt_handler(device, irq, irq_handler,
    196             &instance->hc.interrupt_code);
    197         CHECK_RET_FINI_RETURN(ret,
    198             "Failed(%d) to register interrupt handler.\n", ret);
    199 
    200         instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh");
    201         ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
    202         CHECK_RET_FINI_RETURN(ret,
    203             "Failed(%d) to create root hub function.\n", ret);
    204 
    205         ret = uhci_rh_init(&instance->rh, instance->rh_fun,
    206             (uintptr_t)instance->hc.registers + 0x10, 4);
    207         CHECK_RET_FINI_RETURN(ret,
    208             "Failed(%d) to setup UHCI root hub.\n", ret);
    209 
    210         instance->rh_fun->ops = &uhci_rh_ops;
    211         instance->rh_fun->driver_data = &instance->rh;
    212         ret = ddf_fun_bind(instance->rh_fun);
    213         CHECK_RET_FINI_RETURN(ret,
    214             "Failed(%d) to register UHCI root hub.\n", ret);
    215 
    216         return EOK;
    217 #undef CHECK_RET_FINI_RETURN
    218 }
    219 
     145
     146        /* allow access to hc control registers */
     147        regs_t *io;
     148        ret = pio_enable(regs, reg_size, (void**)&io);
     149        CHECK_RET_DEST_FUN_RETURN(ret,
     150            "Failed(%d) to gain access to registers at %p: %s.\n",
     151            ret, str_error(ret), io);
     152        instance->registers = io;
     153        usb_log_debug("Device registers at %p(%u) accessible.\n",
     154            io, reg_size);
     155
     156        ret = uhci_init_mem_structures(instance);
     157        CHECK_RET_DEST_FUN_RETURN(ret,
     158            "Failed to initialize UHCI memory structures.\n");
     159
     160        uhci_init_hw(instance);
     161        instance->cleaner =
     162            fibril_create(uhci_interrupt_emulator, instance);
     163        fibril_add_ready(instance->cleaner);
     164
     165        instance->debug_checker = fibril_create(uhci_debug_checker, instance);
     166        fibril_add_ready(instance->debug_checker);
     167
     168        usb_log_info("Started UHCI driver.\n");
     169        return EOK;
     170#undef CHECK_RET_DEST_FUN_RETURN
     171}
     172/*----------------------------------------------------------------------------*/
     173/** Initializes UHCI hcd hw resources.
     174 *
     175 * @param[in] instance UHCI structure to use.
     176 */
     177void uhci_init_hw(uhci_t *instance)
     178{
     179        assert(instance);
     180        regs_t *registers = instance->registers;
     181
     182        /* Reset everything, who knows what touched it before us */
     183        pio_write_16(&registers->usbcmd, UHCI_CMD_GLOBAL_RESET);
     184        async_usleep(10000); /* 10ms according to USB spec */
     185        pio_write_16(&registers->usbcmd, 0);
     186
     187        /* Reset hc, all states and counters */
     188        pio_write_16(&registers->usbcmd, UHCI_CMD_HCRESET);
     189        do { async_usleep(10); }
     190        while ((pio_read_16(&registers->usbcmd) & UHCI_CMD_HCRESET) != 0);
     191
     192        /* Set framelist pointer */
     193        const uint32_t pa = addr_to_phys(instance->frame_list);
     194        pio_write_32(&registers->flbaseadd, pa);
     195
     196        /* Enable all interrupts, but resume interrupt */
     197//      pio_write_16(&instance->registers->usbintr,
     198//          UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET);
     199
     200        uint16_t status = pio_read_16(&registers->usbcmd);
     201        if (status != 0)
     202                usb_log_warning("Previous command value: %x.\n", status);
     203
     204        /* Start the hc with large(64B) packet FSBR */
     205        pio_write_16(&registers->usbcmd,
     206            UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET | UHCI_CMD_CONFIGURE);
     207}
     208/*----------------------------------------------------------------------------*/
     209/** Initializes UHCI hcd memory structures.
     210 *
     211 * @param[in] instance UHCI structure to use.
     212 * @return Error code
     213 * @note Should be called only once on any structure.
     214 */
     215int uhci_init_mem_structures(uhci_t *instance)
     216{
     217        assert(instance);
     218#define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \
     219        if (ret != EOK) { \
     220                usb_log_error(message); \
     221                if (instance->interrupt_code.cmds != NULL) \
     222                        free(instance->interrupt_code.cmds); \
     223                return ret; \
     224        } else (void) 0
     225
     226        /* Init interrupt code */
     227        instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds));
     228        int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK;
     229        CHECK_RET_DEST_CMDS_RETURN(ret,
     230            "Failed to allocate interrupt cmds space.\n");
     231
     232        {
     233                irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds;
     234                memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds));
     235                interrupt_commands[0].addr =
     236                    (void*)&instance->registers->usbsts;
     237                interrupt_commands[1].addr =
     238                    (void*)&instance->registers->usbsts;
     239                instance->interrupt_code.cmdcount =
     240                    sizeof(uhci_cmds) / sizeof(irq_cmd_t);
     241        }
     242
     243        /* Init transfer lists */
     244        ret = uhci_init_transfer_lists(instance);
     245        CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to init transfer lists.\n");
     246        usb_log_debug("Initialized transfer lists.\n");
     247
     248        /* Init USB frame list page*/
     249        instance->frame_list = get_page();
     250        ret = instance ? EOK : ENOMEM;
     251        CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n");
     252        usb_log_debug("Initialized frame list.\n");
     253
     254        /* Set all frames to point to the first queue head */
     255        const uint32_t queue =
     256          instance->transfers_interrupt.queue_head_pa
     257          | LINK_POINTER_QUEUE_HEAD_FLAG;
     258
     259        unsigned i = 0;
     260        for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
     261                instance->frame_list[i] = queue;
     262        }
     263
     264        /* Init device keeper*/
     265        device_keeper_init(&instance->device_manager);
     266        usb_log_debug("Initialized device manager.\n");
     267
     268        return EOK;
     269#undef CHECK_RET_DEST_CMDS_RETURN
     270}
     271/*----------------------------------------------------------------------------*/
     272/** Initializes UHCI hcd transfer lists.
     273 *
     274 * @param[in] instance UHCI structure to use.
     275 * @return Error code
     276 * @note Should be called only once on any structure.
     277 */
     278int uhci_init_transfer_lists(uhci_t *instance)
     279{
     280        assert(instance);
     281#define CHECK_RET_CLEAR_RETURN(ret, message...) \
     282        if (ret != EOK) { \
     283                usb_log_error(message); \
     284                transfer_list_fini(&instance->transfers_bulk_full); \
     285                transfer_list_fini(&instance->transfers_control_full); \
     286                transfer_list_fini(&instance->transfers_control_slow); \
     287                transfer_list_fini(&instance->transfers_interrupt); \
     288                return ret; \
     289        } else (void) 0
     290
     291        /* initialize TODO: check errors */
     292        int ret;
     293        ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL");
     294        CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list.");
     295
     296        ret = transfer_list_init(
     297            &instance->transfers_control_full, "CONTROL_FULL");
     298        CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list.");
     299
     300        ret = transfer_list_init(
     301            &instance->transfers_control_slow, "CONTROL_SLOW");
     302        CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list.");
     303
     304        ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT");
     305        CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list.");
     306
     307        transfer_list_set_next(&instance->transfers_control_full,
     308                &instance->transfers_bulk_full);
     309        transfer_list_set_next(&instance->transfers_control_slow,
     310                &instance->transfers_control_full);
     311        transfer_list_set_next(&instance->transfers_interrupt,
     312                &instance->transfers_control_slow);
     313
     314        /*FSBR*/
     315#ifdef FSBR
     316        transfer_list_set_next(&instance->transfers_bulk_full,
     317                &instance->transfers_control_full);
     318#endif
     319
     320        /* Assign pointers to be used during scheduling */
     321        instance->transfers[USB_SPEED_FULL][USB_TRANSFER_INTERRUPT] =
     322          &instance->transfers_interrupt;
     323        instance->transfers[USB_SPEED_LOW][USB_TRANSFER_INTERRUPT] =
     324          &instance->transfers_interrupt;
     325        instance->transfers[USB_SPEED_FULL][USB_TRANSFER_CONTROL] =
     326          &instance->transfers_control_full;
     327        instance->transfers[USB_SPEED_LOW][USB_TRANSFER_CONTROL] =
     328          &instance->transfers_control_slow;
     329        instance->transfers[USB_SPEED_FULL][USB_TRANSFER_BULK] =
     330          &instance->transfers_bulk_full;
     331
     332        return EOK;
     333#undef CHECK_RET_CLEAR_RETURN
     334}
     335/*----------------------------------------------------------------------------*/
     336/** Schedules batch for execution.
     337 *
     338 * @param[in] instance UHCI structure to use.
     339 * @param[in] batch Transfer batch to schedule.
     340 * @return Error code
     341 */
     342int uhci_schedule(uhci_t *instance, batch_t *batch)
     343{
     344        assert(instance);
     345        assert(batch);
     346        const int low_speed = (batch->speed == USB_SPEED_LOW);
     347        if (!allowed_usb_packet(
     348            low_speed, batch->transfer_type, batch->max_packet_size)) {
     349                usb_log_warning(
     350                    "Invalid USB packet specified %s SPEED %d %zu.\n",
     351                    low_speed ? "LOW" : "FULL" , batch->transfer_type,
     352                    batch->max_packet_size);
     353                return ENOTSUP;
     354        }
     355        /* TODO: check available bandwith here */
     356
     357        transfer_list_t *list =
     358            instance->transfers[batch->speed][batch->transfer_type];
     359        assert(list);
     360        transfer_list_add_batch(list, batch);
     361
     362        return EOK;
     363}
     364/*----------------------------------------------------------------------------*/
     365/** Takes action based on the interrupt cause.
     366 *
     367 * @param[in] instance UHCI structure to use.
     368 * @param[in] status Value of the stsatus regiser at the time of interrupt.
     369 */
     370void uhci_interrupt(uhci_t *instance, uint16_t status)
     371{
     372        assert(instance);
     373        /* TODO: Check interrupt cause here */
     374        /* Lower 2 bits are transaction error and transaction complete */
     375        if (status & 0x3) {
     376                transfer_list_remove_finished(&instance->transfers_interrupt);
     377                transfer_list_remove_finished(&instance->transfers_control_slow);
     378                transfer_list_remove_finished(&instance->transfers_control_full);
     379                transfer_list_remove_finished(&instance->transfers_bulk_full);
     380        }
     381}
     382/*----------------------------------------------------------------------------*/
     383/** Polling function, emulates interrupts.
     384 *
     385 * @param[in] arg UHCI structure to use.
     386 * @return EOK
     387 */
     388int uhci_interrupt_emulator(void* arg)
     389{
     390        usb_log_debug("Started interrupt emulator.\n");
     391        uhci_t *instance = (uhci_t*)arg;
     392        assert(instance);
     393
     394        while (1) {
     395                /* read and ack interrupts */
     396                uint16_t status = pio_read_16(&instance->registers->usbsts);
     397                pio_write_16(&instance->registers->usbsts, 0x1f);
     398                if (status != 0)
     399                        usb_log_debug2("UHCI status: %x.\n", status);
     400                uhci_interrupt(instance, status);
     401                async_usleep(UHCI_CLEANER_TIMEOUT);
     402        }
     403        return EOK;
     404}
     405/*---------------------------------------------------------------------------*/
     406/** Debug function, checks consistency of memory structures.
     407 *
     408 * @param[in] arg UHCI structure to use.
     409 * @return EOK
     410 */
     411int uhci_debug_checker(void *arg)
     412{
     413        uhci_t *instance = (uhci_t*)arg;
     414        assert(instance);
     415
     416#define QH(queue) \
     417        instance->transfers_##queue.queue_head
     418
     419        while (1) {
     420                const uint16_t cmd = pio_read_16(&instance->registers->usbcmd);
     421                const uint16_t sts = pio_read_16(&instance->registers->usbsts);
     422                const uint16_t intr =
     423                    pio_read_16(&instance->registers->usbintr);
     424
     425                if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
     426                        usb_log_debug2("Command: %X Status: %X Intr: %x\n",
     427                            cmd, sts, intr);
     428                }
     429
     430                uintptr_t frame_list =
     431                    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
     432                if (frame_list != addr_to_phys(instance->frame_list)) {
     433                        usb_log_debug("Framelist address: %p vs. %p.\n",
     434                            frame_list, addr_to_phys(instance->frame_list));
     435                }
     436
     437                int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff;
     438
     439                uintptr_t expected_pa = instance->frame_list[frnum] & (~0xf);
     440                uintptr_t real_pa = addr_to_phys(QH(interrupt));
     441                if (expected_pa != real_pa) {
     442                        usb_log_debug("Interrupt QH: %p(frame: %d) vs. %p.\n",
     443                            expected_pa, frnum, real_pa);
     444                }
     445
     446                expected_pa = QH(interrupt)->next_queue & (~0xf);
     447                real_pa = addr_to_phys(QH(control_slow));
     448                if (expected_pa != real_pa) {
     449                        usb_log_debug("Control Slow QH: %p vs. %p.\n",
     450                            expected_pa, real_pa);
     451                }
     452
     453                expected_pa = QH(control_slow)->next_queue & (~0xf);
     454                real_pa = addr_to_phys(QH(control_full));
     455                if (expected_pa != real_pa) {
     456                        usb_log_debug("Control Full QH: %p vs. %p.\n",
     457                            expected_pa, real_pa);
     458                }
     459
     460                expected_pa = QH(control_full)->next_queue & (~0xf);
     461                real_pa = addr_to_phys(QH(bulk_full));
     462                if (expected_pa != real_pa ) {
     463                        usb_log_debug("Bulk QH: %p vs. %p.\n",
     464                            expected_pa, real_pa);
     465                }
     466                async_usleep(UHCI_DEBUGER_TIMEOUT);
     467        }
     468        return EOK;
     469#undef QH
     470}
     471/*----------------------------------------------------------------------------*/
     472/** Checks transfer packets, for USB validity
     473 *
     474 * @param[in] low_speed Transfer speed.
     475 * @param[in] transfer Transer type
     476 * @param[in] size Maximum size of used packets
     477 * @return EOK
     478 */
     479bool allowed_usb_packet(
     480    bool low_speed, usb_transfer_type_t transfer, size_t size)
     481{
     482        /* see USB specification chapter 5.5-5.8 for magic numbers used here */
     483        switch(transfer)
     484        {
     485        case USB_TRANSFER_ISOCHRONOUS:
     486                return (!low_speed && size < 1024);
     487        case USB_TRANSFER_INTERRUPT:
     488                return size <= (low_speed ? 8 : 64);
     489        case USB_TRANSFER_CONTROL: /* device specifies its own max size */
     490                return (size <= (low_speed ? 8 : 64));
     491        case USB_TRANSFER_BULK: /* device specifies its own max size */
     492                return (!low_speed && size <= 64);
     493        }
     494        return false;
     495}
    220496/**
    221497 * @}
  • uspace/drv/uhci-hcd/uhci.h

    r335382d r0f3e68c  
    11/*
    2  * Copyright (c) 2011 Jan Vesely
     2 * Copyright (c) 2010 Jan Vesely
    33 * All rights reserved.
    44 *
     
    3535#ifndef DRV_UHCI_UHCI_H
    3636#define DRV_UHCI_UHCI_H
     37
     38#include <fibril.h>
     39#include <fibril_synch.h>
     40#include <adt/list.h>
    3741#include <ddi.h>
    38 #include <ddf/driver.h>
    3942
    40 #include "uhci_hc.h"
    41 #include "uhci_rh.h"
     43#include <usbhc_iface.h>
     44
     45#include "batch.h"
     46#include "transfer_list.h"
     47#include "utils/device_keeper.h"
     48
     49typedef 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
    4282
    4383typedef struct uhci {
    44         ddf_fun_t *hc_fun;
    45         ddf_fun_t *rh_fun;
     84        device_keeper_t device_manager;
    4685
    47         uhci_hc_t hc;
    48         uhci_rh_t rh;
     86        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;
    49103} uhci_t;
    50104
    51 int uhci_init(uhci_t *instance, ddf_dev_t *device);
     105/* init uhci specifics in device.driver_data */
     106int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size);
     107
     108static inline void uhci_fini(uhci_t *instance) {};
     109
     110int uhci_schedule(uhci_t *instance, batch_t *batch);
     111
     112void uhci_interrupt(uhci_t *instance, uint16_t status);
     113
     114static inline uhci_t * dev_to_uhci(ddf_dev_t *dev)
     115        { return (uhci_t*)dev->driver_data; }
     116
     117static inline uhci_t * fun_to_uhci(ddf_fun_t *fun)
     118        { return (uhci_t*)fun->driver_data; }
     119
    52120
    53121#endif
  • uspace/drv/uhci-hcd/uhci_struct/link_pointer.h

    r335382d r0f3e68c  
    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 
    5148#endif
    5249/**
  • uspace/drv/uhci-hcd/uhci_struct/queue_head.h

    r335382d r0f3e68c  
    4343
    4444typedef struct queue_head {
    45         volatile link_pointer_t next;
     45        volatile link_pointer_t next_queue;
    4646        volatile link_pointer_t element;
    47 } __attribute__((packed)) qh_t;
    48 /*----------------------------------------------------------------------------*/
    49 static inline void qh_init(qh_t *instance)
     47} __attribute__((packed)) queue_head_t;
     48
     49static inline void queue_head_init(queue_head_t *instance)
    5050{
    5151        assert(instance);
    5252
    5353        instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
    54         instance->next = 0 | LINK_POINTER_TERMINATE_FLAG;
     54        instance->next_queue = 0 | LINK_POINTER_TERMINATE_FLAG;
    5555}
    56 /*----------------------------------------------------------------------------*/
    57 static inline void qh_set_next_qh(qh_t *instance, uint32_t pa)
     56
     57static inline void queue_head_append_qh(queue_head_t *instance, uint32_t pa)
    5858{
    59         /* address is valid and not terminal */
    60         if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
    61                 instance->next = (pa & LINK_POINTER_ADDRESS_MASK)
     59        if (pa) {
     60                instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK)
    6261                    | LINK_POINTER_QUEUE_HEAD_FLAG;
    63         } else {
    64                 instance->next = 0 | LINK_POINTER_TERMINATE_FLAG;
    6562        }
    6663}
    67 /*----------------------------------------------------------------------------*/
    68 static inline void qh_set_element_qh(qh_t *instance, uint32_t pa)
     64
     65static inline void queue_head_element_qh(queue_head_t *instance, uint32_t pa)
    6966{
    70         /* address is valid and not terminal */
    71         if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
    72                 instance->element = (pa & LINK_POINTER_ADDRESS_MASK)
     67        if (pa) {
     68                instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK)
    7369                    | LINK_POINTER_QUEUE_HEAD_FLAG;
    74         } else {
    75                 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
    7670        }
    7771}
    78 /*----------------------------------------------------------------------------*/
    79 static inline void qh_set_element_td(qh_t *instance, uint32_t pa)
     72
     73static inline void queue_head_set_element_td(queue_head_t *instance, uint32_t pa)
    8074{
    81         if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {
     75        if (pa) {
    8276                instance->element = (pa & LINK_POINTER_ADDRESS_MASK);
    83         } else {
    84                 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;
    8577        }
    8678}
  • uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c

    r335382d r0f3e68c  
    4444 * @param[in] size Size of data source.
    4545 * @param[in] toggle Value of toggle bit.
    46  * @param[in] iso True if TD represents Isochronous transfer.
     46 * @param[in] iso True if TD is for Isochronous transfer.
    4747 * @param[in] low_speed Target device's speed.
    4848 * @param[in] target Address and endpoint receiving the transfer.
     
    5151 * @param[in] next Net TD in transaction.
    5252 * @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.
    6153 */
    6254void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso,
     
    10294        if (pid == USB_PID_SETUP) {
    10395                usb_log_debug("SETUP BUFFER: %s\n",
    104                     usb_debug_str_buffer(buffer, 8, 8));
     96                        usb_debug_str_buffer(buffer, 8, 8));
    10597        }
    10698}
     
    136128}
    137129/*----------------------------------------------------------------------------*/
    138 /** Print values in status field (dw1) in a human readable way.
    139  *
    140  * @param[in] instance TD structure to use.
    141  */
    142130void td_print_status(td_t *instance)
    143131{
  • uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h

    r335382d r0f3e68c  
    4545
    4646        volatile uint32_t status;
     47
    4748#define TD_STATUS_RESERVED_MASK 0xc000f800
    4849#define TD_STATUS_SPD_FLAG ( 1 << 29 )
    4950#define TD_STATUS_ERROR_COUNT_POS ( 27 )
    5051#define TD_STATUS_ERROR_COUNT_MASK ( 0x3 )
     52#define TD_STATUS_ERROR_COUNT_DEFAULT 3
    5153#define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26 )
    5254#define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25 )
     
    6870
    6971        volatile uint32_t device;
     72
    7073#define TD_DEVICE_MAXLEN_POS 21
    7174#define TD_DEVICE_MAXLEN_MASK ( 0x7ff )
     
    8285
    8386        /* there is 16 bytes of data available here, according to UHCI
    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
     87         * Design guide, according to linux kernel the hardware does not care
     88         * we don't use it anyway
    8689         */
    8790} __attribute__((packed)) td_t;
     
    9497int td_status(td_t *instance);
    9598
    96 void 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  */
    10399static inline size_t td_act_size(td_t *instance)
    104100{
    105101        assert(instance);
    106         const uint32_t s = instance->status;
    107         return ((s >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;
     102        return
     103            ((instance->status >> TD_STATUS_ACTLEN_POS) + 1)
     104            & TD_STATUS_ACTLEN_MASK;
    108105}
    109 /*----------------------------------------------------------------------------*/
    110 /** Checks 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  */
     106
    116107static inline bool td_is_short(td_t *instance)
    117108{
     
    123114            (instance->status | TD_STATUS_SPD_FLAG) && act_size < max_size;
    124115}
    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  */
     116
    131117static inline int td_toggle(td_t *instance)
    132118{
    133119        assert(instance);
    134         return (instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) ? 1 : 0;
     120        return ((instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) != 0)
     121            ? 1 : 0;
    135122}
    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  */
     123
    142124static inline bool td_is_active(td_t *instance)
    143125{
     
    145127        return (instance->status & TD_STATUS_ERROR_ACTIVE) != 0;
    146128}
    147 /*----------------------------------------------------------------------------*/
    148 /** Helper function for setting IOC bit.
    149  *
    150  * @param[in] instance TD structure to use.
    151  */
    152 static inline void td_set_ioc(td_t *instance)
    153 {
    154         assert(instance);
    155         instance->status |= TD_STATUS_IOC_FLAG;
    156 }
    157 /*----------------------------------------------------------------------------*/
     129
     130void td_print_status(td_t *instance);
    158131#endif
    159132/**
Note: See TracChangeset for help on using the changeset viewer.