Changes in / [1b0b86e6:67f54965] in mainline


Ignore:
Location:
uspace
Files:
4 added
7 deleted
25 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/ehci-hcd/pci.c

    r1b0b86e6 r67f54965  
    247247
    248248
    249         if ((value & USBLEGSUP_BIOS_CONTROL) == 0) {
     249        if ((value & USBLEGSUP_BIOS_CONTROL) != 0) {
    250250                usb_log_info("BIOS released control after %d usec.\n", wait);
    251251        } else {
    252252                /* BIOS failed to hand over control, this should not happen. */
    253                 usb_log_warning( "BIOS failed to release control after "
     253                usb_log_warning( "BIOS failed to release control after"
    254254                    "%d usecs, force it.\n", wait);
    255255                ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
     
    258258                CHECK_RET_HANGUP_RETURN(ret,
    259259                    "Failed(%d) to force OS EHCI control.\n", ret);
     260                /* TODO: This does not seem to work on my machine */
    260261        }
    261262
     
    279280        usb_log_debug2("USBLEGSUP: %x.\n", value);
    280281
    281         /*
    282          * TURN OFF EHCI FOR NOW, DRIVER WILL REINITIALIZE IT
    283         */
     282/*
     283 * TURN OFF EHCI FOR NOW, REMOVE IF THE DRIVER IS IMPLEMENTED
     284 */
    284285
    285286        /* Get size of capability registers in memory space. */
  • uspace/drv/uhci-hcd/Makefile

    r1b0b86e6 r67f54965  
    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

    r1b0b86e6 r67f54965  
    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",
     
    172177                        usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
    173178                            instance, i, instance->tds[i].status);
    174                         td_print_status(&instance->tds[i]);
    175179
    176180                        device_keeper_set_toggle(instance->manager,
     
    314318                ++packet;
    315319        }
    316         td_set_ioc(&instance->tds[packet - 1]);
    317320        device_keeper_set_toggle(instance->manager, instance->target, toggle);
    318321}
     
    366369            0, 1, false, low_speed, instance->target, status_stage, NULL, NULL);
    367370
    368         td_set_ioc(&instance->tds[packet]);
     371
     372        instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
    369373        usb_log_debug2("Control last TD status: %x.\n",
    370374            instance->tds[packet].status);
     
    450454{
    451455        assert(instance);
    452         uhci_hc_t *hc = fun_to_uhci_hc(instance->fun);
     456        uhci_t *hc = fun_to_uhci(instance->fun);
    453457        assert(hc);
    454         return uhci_hc_schedule(hc, instance);
     458        return uhci_schedule(hc, instance);
    455459}
    456460/**
  • uspace/drv/uhci-hcd/batch.h

    r1b0b86e6 r67f54965  
    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

    r1b0b86e6 r67f54965  
    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);
    280         assert(hc);
    281         usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
    282         usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n",
    283             speed, target.address, target.endpoint, size, max_packet_size);
     279        uhci_t *hc = fun_to_uhci(fun);
     280        assert(hc);
     281        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     282        usb_log_debug("Control WRITE %d:%d %zu(%zu).\n",
     283            target.address, target.endpoint, size, max_packet_size);
    284284
    285285        if (setup_size != 8)
     
    315315{
    316316        assert(fun);
    317         uhci_hc_t *hc = fun_to_uhci_hc(fun);
    318         assert(hc);
    319         usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
    320 
    321         usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n",
    322             speed, target.address, target.endpoint, size, max_packet_size);
     317        uhci_t *hc = fun_to_uhci(fun);
     318        assert(hc);
     319        usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address);
     320
     321        usb_log_debug("Control READ %d:%d %zu(%zu).\n",
     322            target.address, target.endpoint, size, max_packet_size);
    323323        batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL,
    324324            max_packet_size, speed, data, size, setup_data, setup_size, callback,
     
    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

    r1b0b86e6 r67f54965  
    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

    r1b0b86e6 r67f54965  
    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

    r1b0b86e6 r67f54965  
    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

    r1b0b86e6 r67f54965  
    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

    r1b0b86e6 r67f54965  
    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[low_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        transfer_list_remove_finished(&instance->transfers_interrupt);
     375        transfer_list_remove_finished(&instance->transfers_control_slow);
     376        transfer_list_remove_finished(&instance->transfers_control_full);
     377        transfer_list_remove_finished(&instance->transfers_bulk_full);
     378}
     379/*----------------------------------------------------------------------------*/
     380/** Polling function, emulates interrupts.
     381 *
     382 * @param[in] arg UHCI structure to use.
     383 * @return EOK
     384 */
     385int uhci_interrupt_emulator(void* arg)
     386{
     387        usb_log_debug("Started interrupt emulator.\n");
     388        uhci_t *instance = (uhci_t*)arg;
     389        assert(instance);
     390
     391        while (1) {
     392                uint16_t status = pio_read_16(&instance->registers->usbsts);
     393                if (status != 0)
     394                        usb_log_debug2("UHCI status: %x.\n", status);
     395                status |= 1;
     396                uhci_interrupt(instance, status);
     397                pio_write_16(&instance->registers->usbsts, 0x1f);
     398                async_usleep(UHCI_CLEANER_TIMEOUT);
     399        }
     400        return EOK;
     401}
     402/*---------------------------------------------------------------------------*/
     403/** Debug function, checks consistency of memory structures.
     404 *
     405 * @param[in] arg UHCI structure to use.
     406 * @return EOK
     407 */
     408int uhci_debug_checker(void *arg)
     409{
     410        uhci_t *instance = (uhci_t*)arg;
     411        assert(instance);
     412
     413#define QH(queue) \
     414        instance->transfers_##queue.queue_head
     415
     416        while (1) {
     417                const uint16_t cmd = pio_read_16(&instance->registers->usbcmd);
     418                const uint16_t sts = pio_read_16(&instance->registers->usbsts);
     419                const uint16_t intr =
     420                    pio_read_16(&instance->registers->usbintr);
     421
     422                if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) {
     423                        usb_log_debug2("Command: %X Status: %X Intr: %x\n",
     424                            cmd, sts, intr);
     425                }
     426
     427                uintptr_t frame_list =
     428                    pio_read_32(&instance->registers->flbaseadd) & ~0xfff;
     429                if (frame_list != addr_to_phys(instance->frame_list)) {
     430                        usb_log_debug("Framelist address: %p vs. %p.\n",
     431                            frame_list, addr_to_phys(instance->frame_list));
     432                }
     433
     434                int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff;
     435                usb_log_debug2("Framelist item: %d \n", frnum );
     436
     437                uintptr_t expected_pa = instance->frame_list[frnum] & (~0xf);
     438                uintptr_t real_pa = addr_to_phys(QH(interrupt));
     439                if (expected_pa != real_pa) {
     440                        usb_log_debug("Interrupt QH: %p vs. %p.\n",
     441                            expected_pa, real_pa);
     442                }
     443
     444                expected_pa = QH(interrupt)->next_queue & (~0xf);
     445                real_pa = addr_to_phys(QH(control_slow));
     446                if (expected_pa != real_pa) {
     447                        usb_log_debug("Control Slow QH: %p vs. %p.\n",
     448                            expected_pa, real_pa);
     449                }
     450
     451                expected_pa = QH(control_slow)->next_queue & (~0xf);
     452                real_pa = addr_to_phys(QH(control_full));
     453                if (expected_pa != real_pa) {
     454                        usb_log_debug("Control Full QH: %p vs. %p.\n",
     455                            expected_pa, real_pa);
     456                }
     457
     458                expected_pa = QH(control_full)->next_queue & (~0xf);
     459                real_pa = addr_to_phys(QH(bulk_full));
     460                if (expected_pa != real_pa ) {
     461                        usb_log_debug("Bulk QH: %p vs. %p.\n",
     462                            expected_pa, real_pa);
     463                }
     464                async_usleep(UHCI_DEBUGER_TIMEOUT);
     465        }
     466        return EOK;
     467#undef QH
     468}
     469/*----------------------------------------------------------------------------*/
     470/** Checks transfer packets, for USB validity
     471 *
     472 * @param[in] low_speed Transfer speed.
     473 * @param[in] transfer Transer type
     474 * @param[in] size Maximum size of used packets
     475 * @return EOK
     476 */
     477bool allowed_usb_packet(
     478    bool low_speed, usb_transfer_type_t transfer, size_t size)
     479{
     480        /* see USB specification chapter 5.5-5.8 for magic numbers used here */
     481        switch(transfer)
     482        {
     483        case USB_TRANSFER_ISOCHRONOUS:
     484                return (!low_speed && size < 1024);
     485        case USB_TRANSFER_INTERRUPT:
     486                return size <= (low_speed ? 8 : 64);
     487        case USB_TRANSFER_CONTROL: /* device specifies its own max size */
     488                return (size <= (low_speed ? 8 : 64));
     489        case USB_TRANSFER_BULK: /* device specifies its own max size */
     490                return (!low_speed && size <= 64);
     491        }
     492        return false;
     493}
    220494/**
    221495 * @}
  • uspace/drv/uhci-hcd/uhci.h

    r1b0b86e6 r67f54965  
    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

    r1b0b86e6 r67f54965  
    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

    r1b0b86e6 r67f54965  
    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

    r1b0b86e6 r67f54965  
    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,
     
    9688        }
    9789
    98         usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).\n",
    99             instance, instance->next, instance->status, instance->device,
     90        usb_log_debug2("Created TD: %X:%X:%X:%X(%p).\n",
     91            instance->next, instance->status, instance->device,
    10092            instance->buffer_ptr, buffer);
    101         td_print_status(instance);
    10293        if (pid == USB_PID_SETUP) {
    10394                usb_log_debug("SETUP BUFFER: %s\n",
    104                     usb_debug_str_buffer(buffer, 8, 8));
     95                        usb_debug_str_buffer(buffer, 8, 8));
    10596        }
    10697}
     
    135126        return EOK;
    136127}
    137 /*----------------------------------------------------------------------------*/
    138 /** Print values in status field (dw1) in a human readable way.
    139  *
    140  * @param[in] instance TD structure to use.
    141  */
    142 void td_print_status(td_t *instance)
    143 {
    144         assert(instance);
    145         const uint32_t s = instance->status;
    146         usb_log_debug2("TD(%p) status(%#x):%s %d,%s%s%s%s%s%s%s%s%s%s%s %d.\n",
    147             instance, instance->status,
    148             (s & TD_STATUS_SPD_FLAG) ? " SPD," : "",
    149             (s >> TD_STATUS_ERROR_COUNT_POS) & TD_STATUS_ERROR_COUNT_MASK,
    150             (s & TD_STATUS_LOW_SPEED_FLAG) ? " LOW SPEED," : "",
    151             (s & TD_STATUS_ISOCHRONOUS_FLAG) ? " ISOCHRONOUS," : "",
    152             (s & TD_STATUS_IOC_FLAG) ? " IOC," : "",
    153             (s & TD_STATUS_ERROR_ACTIVE) ? " ACTIVE," : "",
    154             (s & TD_STATUS_ERROR_STALLED) ? " STALLED," : "",
    155             (s & TD_STATUS_ERROR_BUFFER) ? " BUFFER," : "",
    156             (s & TD_STATUS_ERROR_BABBLE) ? " BABBLE," : "",
    157             (s & TD_STATUS_ERROR_NAK) ? " NAK," : "",
    158             (s & TD_STATUS_ERROR_CRC) ? " CRC/TIMEOUT," : "",
    159             (s & TD_STATUS_ERROR_BIT_STUFF) ? " BIT_STUFF," : "",
    160             (s & TD_STATUS_ERROR_RESERVED) ? " RESERVED," : "",
    161             (s >> TD_STATUS_ACTLEN_POS) & TD_STATUS_ACTLEN_MASK
    162         );
    163 }
    164128/**
    165129 * @}
  • uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h

    r1b0b86e6 r67f54965  
    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 )
    53 #define TD_STATUS_IOC_FLAG ( 1 << 24 )
     55#define TD_STATUS_COMPLETE_INTERRUPT_FLAG ( 1 << 24 )
    5456
    5557#define TD_STATUS_ERROR_ACTIVE ( 1 << 23 )
     
    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;
    8891
    8992
    90 void td_init(td_t *instance, int error_count, size_t size, bool toggle,
    91     bool iso, bool low_speed, usb_target_t target, usb_packet_id pid,
    92     void *buffer, td_t *next);
     93void td_init(td_t *instance, int error_count, size_t size, bool toggle, bool iso,
     94    bool low_speed, usb_target_t target, usb_packet_id pid, void *buffer,
     95    td_t *next);
    9396
    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 /*----------------------------------------------------------------------------*/
    158129#endif
    159130/**
  • uspace/drv/uhci-rhd/Makefile

    r1b0b86e6 r67f54965  
    3535        main.c \
    3636        port.c \
     37        port_status.c \
    3738        root_hub.c
    3839
  • uspace/drv/uhci-rhd/port.c

    r1b0b86e6 r67f54965  
    4444
    4545#include "port.h"
     46#include "port_status.h"
    4647
    4748static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed);
     
    6667{
    6768        assert(port);
    68         asprintf(&port->id_string, "Port (%p - %d)", port, number);
    69         if (port->id_string == NULL) {
    70                 return ENOMEM;
    71         }
    7269
    7370        port->address = address;
     
    119116        assert(instance);
    120117
     118        /* Iteration count, for debug purposes only */
     119        unsigned count = 0;
     120
    121121        while (1) {
    122122                async_usleep(instance->wait_period_usec);
    123123
    124124                /* read register value */
    125                 port_status_t port_status = uhci_port_read_status(instance);
    126 
    127                 /* print the value if it's interesting */
    128                 if (port_status & ~STATUS_ALWAYS_ONE)
    129                         uhci_port_print_status(instance, port_status);
     125                port_status_t port_status = port_status_read(instance->address);
     126
     127                /* debug print mutex */
     128                static fibril_mutex_t dbg_mtx =
     129                    FIBRIL_MUTEX_INITIALIZER(dbg_mtx);
     130                fibril_mutex_lock(&dbg_mtx);
     131                usb_log_debug2("Port(%p - %d): Status: %#04x. === %u\n",
     132                  instance->address, instance->number, port_status, count++);
     133//              print_port_status(port_status);
     134                fibril_mutex_unlock(&dbg_mtx);
    130135
    131136                if ((port_status & STATUS_CONNECTED_CHANGED) == 0)
    132137                        continue;
    133138
    134                 usb_log_debug("%s: Connected change detected: %x.\n",
    135                     instance->id_string, port_status);
     139                usb_log_debug("Port(%p - %d): Connected change detected: %x.\n",
     140                    instance->address, instance->number, port_status);
    136141
    137142                int rc =
    138143                    usb_hc_connection_open(&instance->hc_connection);
    139144                if (rc != EOK) {
    140                         usb_log_error("%s: Failed to connect to HC.",
    141                             instance->id_string);
     145                        usb_log_error("Port(%p - %d): Failed to connect to HC.",
     146                            instance->address, instance->number);
    142147                        continue;
    143148                }
     
    145150                /* Remove any old device */
    146151                if (instance->attached_device) {
    147                         usb_log_debug2("%s: Removing device.\n",
    148                             instance->id_string);
     152                        usb_log_debug2("Port(%p - %d): Removing device.\n",
     153                            instance->address, instance->number);
    149154                        uhci_port_remove_device(instance);
    150155                }
     
    158163                } else {
    159164                        /* Write one to WC bits, to ack changes */
    160                         uhci_port_write_status(instance, port_status);
    161                         usb_log_debug("%s: status change ACK.\n",
    162                             instance->id_string);
     165                        port_status_write(instance->address, port_status);
     166                        usb_log_debug("Port(%p - %d): Change status ACK.\n",
     167                            instance->address, instance->number);
    163168                }
    164169
    165170                rc = usb_hc_connection_close(&instance->hc_connection);
    166171                if (rc != EOK) {
    167                         usb_log_error("%s: Failed to disconnect.",
    168                             instance->id_string);
     172                        usb_log_error("Port(%p - %d): Failed to disconnect.",
     173                            instance->address, instance->number);
    169174                }
    170175        }
     
    182187        uhci_port_t *port = (uhci_port_t *) arg;
    183188
    184         usb_log_debug2("%s: new_device_enable_port.\n", port->id_string);
     189        usb_log_debug2("Port(%p - %d): new_device_enable_port.\n",
     190            port->address, port->number);
    185191
    186192        /*
     
    190196        async_usleep(100000);
    191197
    192         /*
    193          * Resets from root ports should be nominally 50ms
     198
     199        /* The hub maintains the reset signal to that port for 10 ms
     200         * (See Section 11.5.1.5)
    194201         */
    195202        {
    196                 usb_log_debug("%s: Reset Signal start.\n", port->id_string);
    197                 port_status_t port_status = uhci_port_read_status(port);
     203                usb_log_debug("Port(%p - %d): Reset Signal start.\n",
     204                    port->address, port->number);
     205                port_status_t port_status =
     206                        port_status_read(port->address);
    198207                port_status |= STATUS_IN_RESET;
    199                 uhci_port_write_status(port, port_status);
    200                 async_usleep(50000);
    201                 port_status = uhci_port_read_status(port);
     208                port_status_write(port->address, port_status);
     209                async_usleep(10000);
     210                port_status = port_status_read(port->address);
    202211                port_status &= ~STATUS_IN_RESET;
    203                 uhci_port_write_status(port, port_status);
    204                 usb_log_debug("%s: Reset Signal stop.\n", port->id_string);
    205         }
    206 
    207         /* the reset recovery time 10ms */
    208         async_usleep(10000);
     212                port_status_write(port->address, port_status);
     213                usb_log_debug("Port(%p - %d): Reset Signal stop.\n",
     214                    port->address, port->number);
     215        }
    209216
    210217        /* Enable the port. */
    211218        uhci_port_set_enabled(port, true);
    212 
    213219        return EOK;
    214220}
     
    227233        assert(usb_hc_connection_is_opened(&port->hc_connection));
    228234
    229         usb_log_info("%s: Detected new device.\n", port->id_string);
     235        usb_log_info("Port(%p-%d): Detected new device.\n",
     236            port->address, port->number);
    230237
    231238        usb_address_t dev_addr;
     
    235242
    236243        if (rc != EOK) {
    237                 usb_log_error("%s: Failed(%d) to add device: %s.\n",
    238                     port->id_string, rc, str_error(rc));
     244                usb_log_error("Port(%p-%d): Failed(%d) to add device: %s.\n",
     245                    port->address, port->number, rc, str_error(rc));
    239246                uhci_port_set_enabled(port, false);
    240247                return rc;
    241248        }
    242249
    243         usb_log_info("%s: New device has address %d (handle %zu).\n",
    244             port->id_string, dev_addr, port->attached_device);
     250        usb_log_info("Port(%p-%d): New device has address %d (handle %zu).\n",
     251            port->address, port->number, dev_addr, port->attached_device);
    245252
    246253        return EOK;
     
    256263int uhci_port_remove_device(uhci_port_t *port)
    257264{
    258         usb_log_error("%s: Don't know how to remove device %d.\n",
    259             port->id_string, (unsigned int)port->attached_device);
     265        usb_log_error("Port(%p-%d): Don't know how to remove device %#x.\n",
     266            port->address, port->number, (unsigned int)port->attached_device);
    260267        return EOK;
    261268}
     
    271278
    272279        /* Read register value */
    273         port_status_t port_status = uhci_port_read_status(port);
     280        port_status_t port_status = port_status_read(port->address);
    274281
    275282        /* Set enabled bit */
     
    281288
    282289        /* Write new value. */
    283         uhci_port_write_status(port, port_status);
    284 
    285         usb_log_info("%s: %sabled port.\n",
    286                 port->id_string, enabled ? "En" : "Dis");
     290        port_status_write(port->address, port_status);
     291
     292        usb_log_info("Port(%p-%d): %sabled port.\n",
     293                port->address, port->number, enabled ? "En" : "Dis");
    287294        return EOK;
    288295}
  • uspace/drv/uhci-rhd/port.h

    r1b0b86e6 r67f54965  
    3636
    3737#include <assert.h>
     38#include <ddf/driver.h>
    3839#include <stdint.h>
    39 #include <ddf/driver.h>
    40 #include <libarch/ddi.h> /* pio_read and pio_write */
    4140#include <usb/usbdevice.h>
    4241
    43 typedef uint16_t port_status_t;
    44 
    45 #define STATUS_CONNECTED         (1 << 0)
    46 #define STATUS_CONNECTED_CHANGED (1 << 1)
    47 #define STATUS_ENABLED           (1 << 2)
    48 #define STATUS_ENABLED_CHANGED   (1 << 3)
    49 #define STATUS_LINE_D_PLUS       (1 << 4)
    50 #define STATUS_LINE_D_MINUS      (1 << 5)
    51 #define STATUS_RESUME            (1 << 6)
    52 #define STATUS_ALWAYS_ONE        (1 << 7)
    53 
    54 #define STATUS_LOW_SPEED (1 <<  8)
    55 #define STATUS_IN_RESET  (1 <<  9)
    56 #define STATUS_SUSPEND   (1 << 12)
     42#include "port_status.h"
    5743
    5844typedef struct uhci_port
    5945{
    60         char *id_string;
    6146        port_status_t *address;
    6247        unsigned number;
     
    7358
    7459void uhci_port_fini(uhci_port_t *port);
    75 
    76 static inline port_status_t uhci_port_read_status(uhci_port_t *port)
    77 {
    78         assert(port);
    79         return pio_read_16(port->address);
    80 }
    81 
    82 static inline void uhci_port_write_status(
    83     uhci_port_t *port, port_status_t value)
    84 {
    85         assert(port);
    86         pio_write_16(port->address, value);
    87 }
    88 
    89 static inline void uhci_port_print_status(
    90     uhci_port_t *port, const port_status_t value)
    91 {
    92         assert(port);
    93         usb_log_debug2("%s Port status(%#x):%s%s%s%s%s%s%s%s%s%s%s.\n",
    94             port->id_string, value,
    95             (value & STATUS_SUSPEND) ? " SUSPENDED," : "",
    96             (value & STATUS_RESUME) ? " IN RESUME," : "",
    97             (value & STATUS_IN_RESET) ? " IN RESET," : "",
    98             (value & STATUS_LINE_D_MINUS) ? " VD-," : "",
    99             (value & STATUS_LINE_D_PLUS) ? " VD+," : "",
    100             (value & STATUS_LOW_SPEED) ? " LOWSPEED," : "",
    101             (value & STATUS_ENABLED_CHANGED) ? " ENABLED-CHANGE," : "",
    102             (value & STATUS_ENABLED) ? " ENABLED," : "",
    103             (value & STATUS_CONNECTED_CHANGED) ? " CONNECTED-CHANGE," : "",
    104             (value & STATUS_CONNECTED) ? " CONNECTED," : "",
    105             (value & STATUS_ALWAYS_ONE) ? " ALWAYS ONE" : " ERROR: NO ALWAYS ONE"
    106         );
    107 }
    10860#endif
    10961/**
  • uspace/drv/usbmouse/init.c

    r1b0b86e6 r67f54965  
    4242
    4343/** Mouse polling endpoint description for boot protocol subclass. */
    44 usb_endpoint_description_t poll_endpoint_description = {
     44static usb_endpoint_description_t poll_endpoint_description = {
    4545        .transfer_type = USB_TRANSFER_INTERRUPT,
    4646        .direction = USB_DIRECTION_IN,
     
    5151};
    5252
     53/** Initialize poll pipe.
     54 *
     55 * Expects that session is already started on control pipe zero.
     56 *
     57 * @param mouse Mouse device.
     58 * @param my_interface Interface number.
     59 * @return Error code.
     60 */
     61static int intialize_poll_pipe(usb_mouse_t *mouse, int my_interface)
     62{
     63        assert(usb_endpoint_pipe_is_session_started(&mouse->ctrl_pipe));
     64
     65        int rc;
     66
     67        void *config_descriptor;
     68        size_t config_descriptor_size;
     69
     70        rc = usb_request_get_full_configuration_descriptor_alloc(
     71            &mouse->ctrl_pipe, 0, &config_descriptor, &config_descriptor_size);
     72        if (rc != EOK) {
     73                return rc;
     74        }
     75
     76        usb_endpoint_mapping_t endpoint_mapping[1] = {
     77                {
     78                        .pipe = &mouse->poll_pipe,
     79                        .description = &poll_endpoint_description,
     80                        .interface_no = my_interface
     81                }
     82        };
     83
     84        rc = usb_endpoint_pipe_initialize_from_configuration(endpoint_mapping,
     85            1, config_descriptor, config_descriptor_size, &mouse->wire);
     86        if (rc != EOK) {
     87                return rc;
     88        }
     89
     90        if (!endpoint_mapping[0].present) {
     91                return ENOENT;
     92        }
     93
     94        mouse->poll_interval_us = 1000 * endpoint_mapping[0].descriptor->poll_interval;
     95
     96        usb_log_debug("prepared polling endpoint %d (interval %zu).\n",
     97            mouse->poll_pipe.endpoint_no, mouse->poll_interval_us);
     98
     99        return EOK;
     100}
     101
    53102static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *);
    54103/** Device ops for USB mouse. */
     
    94143 * @return Error code.
    95144 */
    96 int usb_mouse_create(usb_device_t *dev)
     145int usb_mouse_create(ddf_dev_t *dev)
    97146{
    98147        usb_mouse_t *mouse = malloc(sizeof(usb_mouse_t));
     
    100149                return ENOMEM;
    101150        }
    102         mouse->dev = dev;
     151        mouse->device = dev;
    103152        mouse->console_phone = -1;
    104153
    105154        int rc;
    106155
     156        /* Initialize the backing connection. */
     157        rc = usb_device_connection_initialize_from_device(&mouse->wire, dev);
     158        if (rc != EOK) {
     159                goto leave;
     160        }
     161
     162        /* Initialize the default control pipe. */
     163        rc = usb_endpoint_pipe_initialize_default_control(&mouse->ctrl_pipe,
     164            &mouse->wire);
     165        if (rc != EOK) {
     166                goto leave;
     167        }
     168
     169        rc = usb_endpoint_pipe_start_session(&mouse->ctrl_pipe);
     170        if (rc != EOK) {
     171                goto leave;
     172        }
     173
     174        rc = intialize_poll_pipe(mouse, usb_device_get_assigned_interface(dev));
     175
     176        /* We can ignore error here. */
     177        usb_endpoint_pipe_end_session(&mouse->ctrl_pipe);
     178
     179        if (rc != EOK) {
     180                goto leave;
     181        }
     182
    107183        /* Create DDF function. */
    108         mouse->mouse_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "mouse");
     184        mouse->mouse_fun = ddf_fun_create(dev, fun_exposed, "mouse");
    109185        if (mouse->mouse_fun == NULL) {
    110186                rc = ENOMEM;
  • uspace/drv/usbmouse/main.c

    r1b0b86e6 r67f54965  
    4444 * @return Error code.
    4545 */
    46 static int usbmouse_add_device(usb_device_t *dev)
     46static int usbmouse_add_device(ddf_dev_t *dev)
    4747{
    4848        int rc = usb_mouse_create(dev);
     
    5353        }
    5454
    55         usb_log_debug("Polling pipe at endpoint %d.\n", dev->pipes[0].pipe->endpoint_no);
    56 
    57         rc = usb_device_auto_poll(dev, 0,
    58             usb_mouse_polling_callback, dev->pipes[0].pipe->max_packet_size,
    59             usb_mouse_polling_ended_callback, dev->driver_data);
    60 
    61         if (rc != EOK) {
    62                 usb_log_error("Failed to start polling fibril: %s.\n",
    63                     str_error(rc));
    64                 return rc;
     55        fid_t poll_fibril = fibril_create(usb_mouse_polling_fibril, dev);
     56        if (poll_fibril == 0) {
     57                usb_log_error("Failed to initialize polling fibril.\n");
     58                /* FIXME: free allocated resources. */
     59                return ENOMEM;
    6560        }
    6661
     62        fibril_add_ready(poll_fibril);
     63
    6764        usb_log_info("controlling new mouse (handle %llu).\n",
    68             dev->ddf_dev->handle);
     65            dev->handle);
    6966
    7067        return EOK;
     
    7269
    7370/** USB mouse driver ops. */
    74 static usb_driver_ops_t mouse_driver_ops = {
     71static driver_ops_t mouse_driver_ops = {
    7572        .add_device = usbmouse_add_device,
    7673};
    7774
    78 static usb_endpoint_description_t *endpoints[] = {
    79         &poll_endpoint_description,
    80         NULL
    81 };
    82 
    8375/** USB mouse driver. */
    84 static usb_driver_t mouse_driver = {
     76static driver_t mouse_driver = {
    8577        .name = NAME,
    86         .ops = &mouse_driver_ops,
    87         .endpoints = endpoints
     78        .driver_ops = &mouse_driver_ops
    8879};
    8980
     
    9283        usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
    9384
    94         return usb_driver_main(&mouse_driver);
     85        return ddf_driver_main(&mouse_driver);
    9586}
    9687
  • uspace/drv/usbmouse/mouse.c

    r1b0b86e6 r67f54965  
    4040#include <ipc/mouse.h>
    4141
    42 /** Mouse polling callback.
     42/** Fibril function for polling the mouse device.
    4343 *
    44  * @param dev Device that is being polled.
    45  * @param buffer Data buffer.
    46  * @param buffer_size Buffer size in bytes.
    47  * @param arg Custom argument - points to usb_mouse_t.
    48  * @return Always true.
     44 * This function shall not terminate unless the device breaks and fails
     45 * to send data (e.g. stalls on data request).
     46 *
     47 * @param arg ddf_dev_t type representing the mouse device.
     48 * @return EOK Always.
    4949 */
    50 bool usb_mouse_polling_callback(usb_device_t *dev,
    51     uint8_t *buffer, size_t buffer_size, void *arg)
     50int usb_mouse_polling_fibril(void *arg)
    5251{
    53         usb_mouse_t *mouse = (usb_mouse_t *) arg;
     52        assert(arg != NULL);
     53        ddf_dev_t *dev = (ddf_dev_t *) arg;
     54        usb_mouse_t *mouse = (usb_mouse_t *) dev->driver_data;
    5455
    55         usb_log_debug2("got buffer: %s.\n",
    56             usb_debug_str_buffer(buffer, buffer_size, 0));
     56        assert(mouse);
    5757
    58         uint8_t butt = buffer[0];
    59         char str_buttons[4] = {
    60                 butt & 1 ? '#' : '.',
    61                 butt & 2 ? '#' : '.',
    62                 butt & 4 ? '#' : '.',
    63                 0
    64         };
     58        size_t buffer_size = mouse->poll_pipe.max_packet_size;
    6559
    66         int shift_x = ((int) buffer[1]) - 127;
    67         int shift_y = ((int) buffer[2]) - 127;
    68         int wheel = ((int) buffer[3]) - 127;
    69 
    70         if (buffer[1] == 0) {
    71                 shift_x = 0;
    72         }
    73         if (buffer[2] == 0) {
    74                 shift_y = 0;
    75         }
    76         if (buffer[3] == 0) {
    77                 wheel = 0;
     60        if (buffer_size < 4) {
     61                usb_log_error("Weird mouse, results will be skewed.\n");
     62                buffer_size = 4;
    7863        }
    7964
    80         if (mouse->console_phone >= 0) {
    81                 if ((shift_x != 0) || (shift_y != 0)) {
    82                         /* FIXME: guessed for QEMU */
    83                         async_req_2_0(mouse->console_phone,
    84                             MEVENT_MOVE,
    85                             - shift_x / 10,  - shift_y / 10);
    86                 }
    87                 if (butt) {
    88                         /* FIXME: proper button clicking. */
    89                         async_req_2_0(mouse->console_phone,
    90                             MEVENT_BUTTON, 1, 1);
    91                         async_req_2_0(mouse->console_phone,
    92                             MEVENT_BUTTON, 1, 0);
    93                 }
     65        uint8_t *buffer = malloc(buffer_size);
     66        if (buffer == NULL) {
     67                usb_log_error("Out of memory, poll fibril aborted.\n");
     68                return ENOMEM;
    9469        }
    9570
    96         usb_log_debug("buttons=%s  dX=%+3d  dY=%+3d  wheel=%+3d\n",
    97             str_buttons, shift_x, shift_y, wheel);
     71        while (true) {
     72                async_usleep(mouse->poll_interval_us);
    9873
    99         /* Guess. */
    100         async_usleep(1000);
     74                size_t actual_size;
     75                int rc;
    10176
    102         return true;
     77                /*
     78                 * Error checking note:
     79                 * - failure when starting a session is considered
     80                 *   temporary (e.g. out of phones, next try might succeed)
     81                 * - failure of transfer considered fatal (probably the
     82                 *   device was unplugged)
     83                 * - session closing not checked (shall not fail anyway)
     84                 */
     85
     86                rc = usb_endpoint_pipe_start_session(&mouse->poll_pipe);
     87                if (rc != EOK) {
     88                        usb_log_warning("Failed to start session, will try again: %s.\n",
     89                            str_error(rc));
     90                        continue;
     91                }
     92
     93                rc = usb_endpoint_pipe_read(&mouse->poll_pipe,
     94                    buffer, buffer_size, &actual_size);
     95
     96                usb_endpoint_pipe_end_session(&mouse->poll_pipe);
     97
     98                if (rc != EOK) {
     99                        usb_log_error("Failed reading mouse input: %s.\n",
     100                            str_error(rc));
     101                        break;
     102                }
     103
     104                usb_log_debug2("got buffer: %s.\n",
     105                    usb_debug_str_buffer(buffer, buffer_size, 0));
     106
     107                uint8_t butt = buffer[0];
     108                char str_buttons[4] = {
     109                        butt & 1 ? '#' : '.',
     110                        butt & 2 ? '#' : '.',
     111                        butt & 4 ? '#' : '.',
     112                        0
     113                };
     114
     115                int shift_x = ((int) buffer[1]) - 127;
     116                int shift_y = ((int) buffer[2]) - 127;
     117                int wheel = ((int) buffer[3]) - 127;
     118
     119                if (buffer[1] == 0) {
     120                        shift_x = 0;
     121                }
     122                if (buffer[2] == 0) {
     123                        shift_y = 0;
     124                }
     125                if (buffer[3] == 0) {
     126                        wheel = 0;
     127                }
     128
     129                if (mouse->console_phone >= 0) {
     130                        if ((shift_x != 0) || (shift_y != 0)) {
     131                                /* FIXME: guessed for QEMU */
     132                                async_req_2_0(mouse->console_phone,
     133                                    MEVENT_MOVE,
     134                                    - shift_x / 10,  - shift_y / 10);
     135                        }
     136                        if (butt) {
     137                                /* FIXME: proper button clicking. */
     138                                async_req_2_0(mouse->console_phone,
     139                                    MEVENT_BUTTON, 1, 1);
     140                                async_req_2_0(mouse->console_phone,
     141                                    MEVENT_BUTTON, 1, 0);
     142                        }
     143                }
     144
     145                usb_log_debug("buttons=%s  dX=%+3d  dY=%+3d  wheel=%+3d\n",
     146                   str_buttons, shift_x, shift_y, wheel);
     147        }
     148
     149        /*
     150         * Device was probably unplugged.
     151         * Hang-up the phone to the console.
     152         * FIXME: release allocated memory.
     153         */
     154        async_hangup(mouse->console_phone);
     155        mouse->console_phone = -1;
     156
     157        usb_log_error("Mouse polling fibril terminated.\n");
     158
     159        return EOK;
    103160}
    104161
    105 /** Callback when polling is terminated.
    106  *
    107  * @param dev Device where the polling terminated.
    108  * @param recurring_errors Whether the polling was terminated due to
    109  *      recurring errors.
    110  * @param arg Custom argument - points to usb_mouse_t.
    111  */
    112 void usb_mouse_polling_ended_callback(usb_device_t *dev,
    113     bool recurring_errors, void *arg)
    114 {
    115         usb_mouse_t *mouse = (usb_mouse_t *) arg;
    116 
    117         async_hangup(mouse->console_phone);
    118         mouse->console_phone = -1;
    119 }
    120162
    121163/**
  • uspace/drv/usbmouse/mouse.h

    r1b0b86e6 r67f54965  
    3737#define USBMOUSE_MOUSE_H_
    3838
    39 #include <usb/devdrv.h>
     39#include <ddf/driver.h>
    4040#include <usb/pipes.h>
    4141#include <time.h>
     
    4646typedef struct {
    4747        /** Generic device container. */
    48         usb_device_t *dev;
     48        ddf_dev_t *device;
    4949        /** Function representing the device. */
    5050        ddf_fun_t *mouse_fun;
     51        /** Representation of connection to the device. */
     52        usb_device_connection_t wire;
     53        /** Default (zero) control pipe. */
     54        usb_endpoint_pipe_t ctrl_pipe;
     55        /** Polling (in) pipe. */
     56        usb_endpoint_pipe_t poll_pipe;
    5157        /** Polling interval in microseconds. */
    5258        suseconds_t poll_interval_us;
     
    5561} usb_mouse_t;
    5662
    57 #define POLL_PIPE(dev) ((dev)->pipes[0].pipe)
     63int usb_mouse_create(ddf_dev_t *);
    5864
    59 extern usb_endpoint_description_t poll_endpoint_description;
    60 
    61 int usb_mouse_create(usb_device_t *);
    62 
    63 bool usb_mouse_polling_callback(usb_device_t *, uint8_t *, size_t, void *);
    64 void usb_mouse_polling_ended_callback(usb_device_t *, bool, void *);
     65int usb_mouse_polling_fibril(void *);
    6566
    6667#endif
  • uspace/lib/usb/Makefile

    r1b0b86e6 r67f54965  
    3737        src/ddfiface.c \
    3838        src/debug.c \
    39         src/devdrv.c \
    40         src/devpoll.c \
    4139        src/dp.c \
    4240        src/dump.c \
  • uspace/lib/usb/include/usb/pipes.h

    r1b0b86e6 r67f54965  
    106106        const usb_endpoint_description_t *description;
    107107        /** Interface number the endpoint must belong to (-1 for any). */
    108         int interface_no;
     108        const int interface_no;
    109109        /** Found descriptor fitting the description. */
    110110        usb_standard_endpoint_descriptor_t *descriptor;
  • uspace/lib/usb/src/pipesinit.c

    r1b0b86e6 r67f54965  
    3737#include <usb/pipes.h>
    3838#include <usb/dp.h>
    39 #include <usb/request.h>
    4039#include <errno.h>
    4140#include <assert.h>
     
    371370        int rc = usb_endpoint_pipe_initialize(pipe, connection,
    372371            0, USB_TRANSFER_CONTROL, 8, USB_DIRECTION_BOTH);
    373         if (rc != EOK) {
    374                 return rc;
    375         }
    376         rc = usb_endpoint_pipe_start_session(pipe);
    377         if (rc != EOK) {
    378                 return rc;
    379         }
    380 
    381         uint8_t first[8];
    382         size_t size = 0;
    383         rc = usb_control_request_get(pipe, USB_REQUEST_TYPE_STANDARD,
    384             USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_GET_DESCRIPTOR, 1 << 8,
    385                         0, first, 8, &size);
    386         usb_endpoint_pipe_end_session(pipe);
    387         if (rc != EOK || size  != 8) {
    388                 return rc;
    389         }
    390 
    391         pipe->max_packet_size = first[7];
     372
    392373        return rc;
    393374}
Note: See TracChangeset for help on using the changeset viewer.