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


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

Legend:

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

    r0f3e68c r335382d  
    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

    r0f3e68c r335382d  
    4040#include "batch.h"
    4141#include "transfer_list.h"
    42 #include "uhci.h"
     42#include "uhci_hc.h"
    4343#include "utils/malloc32.h"
    4444
     
    100100        bzero(instance, sizeof(batch_t));
    101101
    102         instance->qh = malloc32(sizeof(queue_head_t));
     102        instance->qh = malloc32(sizeof(qh_t));
    103103        CHECK_NULL_DISPOSE_RETURN(instance->qh,
    104104            "Failed to allocate batch queue head.\n");
    105         queue_head_init(instance->qh);
     105        qh_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;
    118116
    119117        if (size > 0) {
     
    143141        instance->speed = speed;
    144142        instance->manager = manager;
    145 
    146         if (func_out)
    147                 instance->callback_out = func_out;
    148         if (func_in)
    149                 instance->callback_in = func_in;
    150 
    151         queue_head_set_element_td(instance->qh, addr_to_phys(instance->tds));
     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));
    152147
    153148        usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
     
    319314                ++packet;
    320315        }
    321         instance->tds[packet - 1].status |= TD_STATUS_IOC_FLAG;
     316        td_set_ioc(&instance->tds[packet - 1]);
    322317        device_keeper_set_toggle(instance->manager, instance->target, toggle);
    323318}
     
    371366            0, 1, false, low_speed, instance->target, status_stage, NULL, NULL);
    372367
    373 
    374         instance->tds[packet].status |= TD_STATUS_IOC_FLAG;
     368        td_set_ioc(&instance->tds[packet]);
    375369        usb_log_debug2("Control last TD status: %x.\n",
    376370            instance->tds[packet].status);
     
    456450{
    457451        assert(instance);
    458         uhci_t *hc = fun_to_uhci(instance->fun);
     452        uhci_hc_t *hc = fun_to_uhci_hc(instance->fun);
    459453        assert(hc);
    460         return uhci_schedule(hc, instance);
     454        return uhci_hc_schedule(hc, instance);
    461455}
    462456/**
  • uspace/drv/uhci-hcd/batch.h

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

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

    r0f3e68c r335382d  
    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

    r0f3e68c r335382d  
    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 /** 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  */
    68 static 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.
     57/** Initializes a new ddf driver instance for uhci hc and hub.
    7858 *
    7959 * @param[in] device DDF instance of the device to initialize.
     
    8565int uhci_add_device(ddf_dev_t *device)
    8666{
     67        usb_log_info("uhci_add_device() called\n");
    8768        assert(device);
    88         uhci_t *hcd = NULL;
    89 #define CHECK_RET_FREE_HC_RETURN(ret, message...) \
    90 if (ret != EOK) { \
    91         usb_log_error(message); \
    92         if (hcd != NULL) \
    93                 free(hcd); \
    94         return ret; \
    95 }
     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;
     73        }
    9674
    97         usb_log_info("uhci_add_device() called\n");
    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);
     75        int ret = uhci_init(uhci, device);
    11676        if (ret != EOK) {
    117                 usb_log_warning(
    118                     "Failed(%d) to enable interrupts, fall back to polling.\n",
    119                     ret);
     77                usb_log_error("Failed to initialzie UHCI driver.\n");
     78                return ret;
    12079        }
    121 #endif
    122 
    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...) \
    140 if (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 
     80        device->driver_data = uhci;
    16681        return EOK;
    167 #undef CHECK_RET_FINI_FREE_RETURN
    16882}
    16983/*----------------------------------------------------------------------------*/
  • uspace/drv/uhci-hcd/transfer_list.c

    r0f3e68c r335382d  
    4747 * @return Error code
    4848 *
    49  * Allocates memory for internat queue_head_t structure.
     49 * Allocates memory for internal qh_t structure.
    5050 */
    5151int transfer_list_init(transfer_list_t *instance, const char *name)
    5252{
    5353        assert(instance);
    54         instance->next = NULL;
    5554        instance->name = name;
    56         instance->queue_head = malloc32(sizeof(queue_head_t));
     55        instance->queue_head = malloc32(sizeof(qh_t));
    5756        if (!instance->queue_head) {
    5857                usb_log_error("Failed to allocate queue head.\n");
     
    6160        instance->queue_head_pa = addr_to_phys(instance->queue_head);
    6261
    63         queue_head_init(instance->queue_head);
     62        qh_init(instance->queue_head);
    6463        list_initialize(&instance->batch_list);
    6564        fibril_mutex_initialize(&instance->guard);
     
    7271 * @param[in] next List to append.
    7372 * @return Error code
     73 *
     74 * Does not check whether there was a next list already.
    7475 */
    7576void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next)
     
    7980        if (!instance->queue_head)
    8081                return;
    81         queue_head_append_qh(instance->queue_head, next->queue_head_pa);
    82         instance->queue_head->element = instance->queue_head->next_queue;
     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);
    8385}
    8486/*----------------------------------------------------------------------------*/
     
    9395        assert(instance);
    9496        assert(batch);
    95         usb_log_debug2(
    96             "Adding batch(%p) to queue %s.\n", batch, instance->name);
     97        usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch);
    9798
    98         uint32_t pa = (uintptr_t)addr_to_phys(batch->qh);
     99        const uint32_t pa = addr_to_phys(batch->qh);
    99100        assert((pa & LINK_POINTER_ADDRESS_MASK) == pa);
    100         pa |= LINK_POINTER_QUEUE_HEAD_FLAG;
    101101
    102         batch->qh->next_queue = instance->queue_head->next_queue;
     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);
    103105
    104106        fibril_mutex_lock(&instance->guard);
    105107
    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;
     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);
    114118        }
    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);
    122119        list_append(&batch->link, &instance->batch_list);
    123120
    124         usb_log_debug("Batch(%p) added to queue %s last, first is %p.\n",
     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",
    125124                batch, instance->name, first);
    126125        fibril_mutex_unlock(&instance->guard);
    127126}
    128127/*----------------------------------------------------------------------------*/
    129 /** Removes a transfer batch from list and queue.
     128/** Removes a transfer batch from the list and queue.
    130129 *
    131130 * @param[in] instance List to use.
    132131 * @param[in] batch Transfer batch to remove.
    133132 * @return Error code
     133 *
     134 * Does not lock the transfer list, caller is responsible for that.
    134135 */
    135136void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch)
     
    140141        assert(batch->qh);
    141142        usb_log_debug2(
    142             "Removing batch(%p) from queue %s.\n", batch, instance->name);
     143            "Queue %s: removing batch(%p).\n", instance->name, batch);
    143144
     145        const char * pos = NULL;
    144146        if (batch->link.prev == &instance->batch_list) {
    145147                /* I'm the first one here */
    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;
     148                qh_set_element_qh(instance->queue_head, batch->qh->next);
     149                pos = "FIRST";
    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);
    154151                batch_t *prev =
    155152                    list_get_instance(batch->link.prev, batch_t, link);
    156                 prev->qh->next_queue = batch->qh->next_queue;
     153                qh_set_next_qh(prev->qh, batch->qh->next);
     154                pos = "NOT FIRST";
    157155        }
    158156        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 transfers.
     161/** Checks list for finished batches.
    162162 *
    163163 * @param[in] instance List to use.
  • uspace/drv/uhci-hcd/transfer_list.h

    r0f3e68c r335382d  
    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;
  • uspace/drv/uhci-hcd/uhci.c

    r0f3e68c r335382d  
    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 /** 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  */
     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/*----------------------------------------------------------------------------*/
    7062static int usb_iface_get_address(
    7163    ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
    7264{
    7365        assert(fun);
    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);
     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);
    7969        if (addr < 0) {
    8070                return addr;
     
    8878}
    8979/*----------------------------------------------------------------------------*/
    90 static usb_iface_t hc_usb_iface = {
    91         .get_hc_handle = usb_iface_get_hc_handle_hc_impl,
     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 */
     86static 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. */
     98static usb_iface_t usb_iface = {
     99        .get_hc_handle = usb_iface_get_hc_handle,
    92100        .get_address = usb_iface_get_address
    93101};
    94102/*----------------------------------------------------------------------------*/
    95 static ddf_dev_ops_t uhci_ops = {
    96         .interfaces[USB_DEV_IFACE] = &hc_usb_iface,
    97         .interfaces[USBHC_DEV_IFACE] = &uhci_iface,
    98 };
    99 /*----------------------------------------------------------------------------*/
    100 static int uhci_init_transfer_lists(uhci_t *instance);
    101 static int uhci_init_mem_structures(uhci_t *instance);
    102 static void uhci_init_hw(uhci_t *instance);
    103 
    104 static int uhci_interrupt_emulator(void *arg);
    105 static int uhci_debug_checker(void *arg);
    106 
    107 static 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  */
    119 int 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 
     103static 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 */
     106};
     107/*----------------------------------------------------------------------------*/
     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 */
     113static 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/*----------------------------------------------------------------------------*/
     119static hw_res_ops_t hw_res_iface = {
     120        .get_resource_list = get_resource_list,
     121        .enable_interrupt = NULL
     122};
     123/*----------------------------------------------------------------------------*/
     124static 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/*----------------------------------------------------------------------------*/
     129int uhci_init(uhci_t *instance, ddf_dev_t *device)
     130{
     131        assert(instance);
     132        instance->hc_fun = NULL;
     133        instance->rh_fun = NULL;
    124134#define CHECK_RET_DEST_FUN_RETURN(ret, message...) \
    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;
     135if (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);
    135150        CHECK_RET_DEST_FUN_RETURN(ret,
    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);
     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);
    142178        CHECK_RET_DEST_FUN_RETURN(ret,
    143179            "Failed(%d) to bind UHCI device function: %s.\n",
    144180            ret, str_error(ret));
    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");
     181#undef CHECK_RET_HC_RETURN
     182
     183#define CHECK_RET_FINI_RETURN(ret, message...) \
     184if (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
    169216        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  */
    177 void 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  */
    215 int 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  */
    278 int 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  */
    342 int 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  */
    370 void 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  */
    388 int 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  */
    411 int 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  */
    479 bool 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 }
     217#undef CHECK_RET_FINI_RETURN
     218}
     219
    496220/**
    497221 * @}
  • uspace/drv/uhci-hcd/uhci.h

    r0f3e68c r335382d  
    11/*
    2  * Copyright (c) 2010 Jan Vesely
     2 * Copyright (c) 2011 Jan Vesely
    33 * All rights reserved.
    44 *
     
    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         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_struct/link_pointer.h

    r0f3e68c r335382d  
    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

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

    r0f3e68c r335382d  
    4444 * @param[in] size Size of data source.
    4545 * @param[in] toggle Value of toggle bit.
    46  * @param[in] iso True if TD is for Isochronous transfer.
     46 * @param[in] iso True if TD represents 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.
    5361 */
    5462void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso,
     
    94102        if (pid == USB_PID_SETUP) {
    95103                usb_log_debug("SETUP BUFFER: %s\n",
    96                         usb_debug_str_buffer(buffer, 8, 8));
     104                    usb_debug_str_buffer(buffer, 8, 8));
    97105        }
    98106}
     
    128136}
    129137/*----------------------------------------------------------------------------*/
     138/** Print values in status field (dw1) in a human readable way.
     139 *
     140 * @param[in] instance TD structure to use.
     141 */
    130142void td_print_status(td_t *instance)
    131143{
  • uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h

    r0f3e68c r335382d  
    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 )
     
    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         */
    9087} __attribute__((packed)) td_t;
     
    9794int td_status(td_t *instance);
    9895
     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 */
    99103static inline size_t td_act_size(td_t *instance)
    100104{
    101105        assert(instance);
    102         return
    103             ((instance->status >> TD_STATUS_ACTLEN_POS) + 1)
    104             & TD_STATUS_ACTLEN_MASK;
     106        const uint32_t s = instance->status;
     107        return ((s >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK;
    105108}
    106 
     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 */
    107116static inline bool td_is_short(td_t *instance)
    108117{
     
    114123            (instance->status | TD_STATUS_SPD_FLAG) && act_size < max_size;
    115124}
    116 
     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 */
    117131static inline int td_toggle(td_t *instance)
    118132{
    119133        assert(instance);
    120         return ((instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) != 0)
    121             ? 1 : 0;
     134        return (instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) ? 1 : 0;
    122135}
    123 
     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 */
    124142static inline bool td_is_active(td_t *instance)
    125143{
     
    127145        return (instance->status & TD_STATUS_ERROR_ACTIVE) != 0;
    128146}
    129 
    130 void td_print_status(td_t *instance);
     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/*----------------------------------------------------------------------------*/
    131158#endif
    132159/**
Note: See TracChangeset for help on using the changeset viewer.