Changeset 72af8da in mainline


Ignore:
Timestamp:
2011-03-16T18:50:17Z (13 years ago)
Author:
Matus Dekanek <smekideki@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update
Children:
42a3a57
Parents:
3e7b7cd (diff), fcf07e6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

merge from usb/development

Files:
10 added
3 deleted
78 edited
4 moved

Legend:

Unmodified
Added
Removed
  • .bzrignore

    r3e7b7cd r72af8da  
    8484./uspace/drv/test1/test1
    8585./uspace/drv/test2/test2
     86./uspace/drv/ehci-hcd/ehci-hcd
    8687./uspace/drv/uhci-hcd/uhci-hcd
    8788./uspace/drv/uhci-rhd/uhci-rhd
  • boot/arch/amd64/Makefile.inc

    r3e7b7cd r72af8da  
    4343        isa \
    4444        ns8250 \
     45        ehci-hcd \
    4546        uhci-hcd \
    4647        uhci-rhd \
  • boot/arch/mips32/src/asm.S

    r3e7b7cd r72af8da  
    4141
    4242start:
    43         /* Setup CPU map (on msim this code
    44            is executed in parallel on all CPUs,
    45            but it not an issue) */
     43        /*
     44         * Setup the CP0 configuration
     45         *  - Disable 64-bit kernel addressing mode
     46         *  - DIsable 64-bit supervisor adressing mode
     47         *  - Disable 64-bit user addressing mode
     48         */
     49        mfc0 $a0, $status
     50        la $a1, 0xffffff1f
     51        and $a0, $a1, $a0
     52        mtc0 $a0, $status
     53       
     54        /*
     55         * Setup CPU map (on msim this code
     56         * is executed in parallel on all CPUs,
     57         * but it not an issue).
     58         */
    4659        la $a0, PA2KA(CPUMAP_OFFSET)
    4760       
     
    94107        lw $k1, ($k0)
    95108       
    96         /* If we are not running on BSP
    97            then end in an infinite loop  */
     109        /*
     110         * If we are not running on BSP
     111         * then end in an infinite loop.
     112         */
    98113        beq $k1, $zero, bsp
    99114        nop
     
    127142
    128143jump_to_kernel:
    129         #
    130         # TODO:
    131         # Make sure that the I-cache, D-cache and memory are mutually coherent
    132         # before passing control to the copied code.
    133         #
     144        /*
     145         * TODO:
     146         *
     147         * Make sure that the I-cache, D-cache and memory are mutually
     148         * coherent before passing control to the copied code.
     149         */
    134150        j $a0
    135151        nop
  • dist/Makefile

    r3e7b7cd r72af8da  
    4343
    4444SUFFIX = $(suffix $(IMGFILE))
    45 DISTFILE = HelenOS-$(RELEASE)-$(PLATFORM)-$(MACHINE)-$(PROCESSOR)$(SUFFIX)
     45
     46ifdef PROFILE
     47        DISTFILE = Helenos-$(shell echo $(PROFILE) | tr '/' '-')$(SUFFIX)
     48else
     49        DISTFILE = HelenOS-$(RELEASE)-$(PLATFORM)-$(MACHINE)-$(PROCESSOR)$(SUFFIX)
     50endif
    4651
    4752.PHONY: all clean dist distfile
     
    5358        cp $< $@
    5459
     60$(IMGFILE):
     61        $(MAKE) -C ..
     62
    5563dist:
    5664        for profile in $(PROFILES); do \
  • uspace/Makefile

    r3e7b7cd r72af8da  
    117117                srv/hw/irc/apic \
    118118                srv/hw/irc/i8259 \
     119                drv/ehci-hcd \
    119120                drv/uhci-hcd \
    120121                drv/uhci-rhd \
     
    134135                srv/hw/irc/apic \
    135136                srv/hw/irc/i8259 \
     137                drv/ehci-hcd \
    136138                drv/uhci-hcd \
    137139                drv/uhci-rhd \
  • uspace/app/bdsh/cmds/modules/mkfile/mkfile.c

    r3e7b7cd r72af8da  
    125125
    126126        for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
    127                 c = getopt_long(argc, argv, "pvhVfm:", long_options, &opt_ind);
     127                c = getopt_long(argc, argv, "s:h", long_options, &opt_ind);
    128128                switch (c) {
    129129                case 'h':
  • uspace/app/usbinfo/info.c

    r3e7b7cd r72af8da  
    6565                goto leave;
    6666        }
     67        rc = usb_endpoint_pipe_probe_default_control(&ctrl_pipe);
     68        if (rc != EOK) {
     69                fprintf(stderr,
     70                    NAME ": probing default control pipe failed: %s.\n",
     71                    str_error(rc));
     72                goto leave;
     73        }
    6774        rc = usb_endpoint_pipe_start_session(&ctrl_pipe);
    6875        if (rc != EOK) {
  • uspace/app/usbinfo/main.c

    r3e7b7cd r72af8da  
    8282
    8383        if (str_cmp(path, "uhci") == 0) {
    84                 path = "/hw/pci0/00:01.2/uhci";
     84                path = "/hw/pci0/00:01.2/uhci-hc";
    8585        }
    8686
  • uspace/doc/doxygroups.h

    r3e7b7cd r72af8da  
    253253         * @defgroup drvusbuhci UHCI driver
    254254         * @ingroup usb
    255          * @brief Driver for USB host controller UHCI.
    256          */
    257 
     255         * @brief Drivers for USB UHCI host controller and root hub.
     256         */
     257
     258                /**
     259                 * @defgroup drvusbuhcirh UHCI root hub driver
     260                 * @ingroup drvusbuhci
     261                 * @brief Driver for UHCI complaint root hub.
     262                 */
     263
     264                /**
     265                 * @defgroup drvusbuhcihc UHCI host controller driver
     266                 * @ingroup drvusbuhci
     267                 * @brief Driver for UHCI complaint USB host controller.
     268                 */
     269
     270        /**
     271         * @defgroup drvusbehci EHCI driver
     272         * @ingroup usb
     273         * @brief Driver for EHCI host controller.
     274         */
     275
     276
  • uspace/drv/ehci-hcd/pci.h

    r3e7b7cd r72af8da  
    11/*
    2  * Copyright (c) 2011 Jan Vesely
     2 * Copyright (c) 2011 Vojtech Horky
    33 * All rights reserved.
    44 *
     
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28
     29/** @addtogroup drvusbehci
    2930 * @{
    3031 */
    3132/** @file
    32  * @brief UHCI driver
     33 * PCI related functions needed by EHCI driver.
    3334 */
    34 #include <assert.h>
    35 #include <stdio.h>
     35#ifndef DRV_EHCI_PCI_H
     36#define DRV_EHCI_PCI_H
    3637
    37 #include <usb/debug.h>
     38#include <ddf/driver.h>
    3839
    39 #include "port_status.h"
     40int pci_get_my_registers(ddf_dev_t *, uintptr_t *, size_t *, int *);
     41int pci_enable_interrupts(ddf_dev_t *);
     42int pci_disable_legacy(ddf_dev_t *);
    4043
    41 struct flag_name
    42 {
    43         uint16_t flag;
    44         const char *name;
    45 };
    46 
    47 static const struct flag_name flags[] =
    48 {
    49         { STATUS_SUSPEND, "suspended" },
    50         { STATUS_IN_RESET, "in reset" },
    51         { STATUS_LOW_SPEED, "low speed device" },
    52         { STATUS_ALWAYS_ONE, "always 1 bit" },
    53         { STATUS_RESUME, "resume" },
    54         { STATUS_LINE_D_MINUS, "line D- value" },
    55         { STATUS_LINE_D_PLUS, "line D+ value" },
    56         { STATUS_ENABLED_CHANGED, "enabled changed" },
    57         { STATUS_ENABLED, "enabled" },
    58         { STATUS_CONNECTED_CHANGED, "connected changed" },
    59         { STATUS_CONNECTED, "connected" }
    60 };
    61 
    62 void print_port_status(port_status_t value)
    63 {
    64         unsigned i = 0;
    65         for (;i < sizeof(flags)/sizeof(struct flag_name); ++i) {
    66                 usb_log_debug2("\t%s status: %s.\n", flags[i].name,
    67                   ((value & flags[i].flag) != 0) ? "YES" : "NO");
    68         }
    69 }
     44#endif
    7045/**
    7146 * @}
    7247 */
     48
  • uspace/drv/pciintel/pci.c

    r3e7b7cd r72af8da  
    9292        pci_fun_t *dev_data = (pci_fun_t *) fnode->driver_data;
    9393
    94   sysarg_t apic;
    95   sysarg_t i8259;
     94        sysarg_t apic;
     95        sysarg_t i8259;
    9696
    9797        int irc_phone = -1;
    98         int irc_service = 0;
    99 
    100   if ((sysinfo_get_value("apic", &apic) == EOK) && (apic)) {
    101     irc_service = SERVICE_APIC;
     98        int irc_service = -1;
     99
     100        if ((sysinfo_get_value("apic", &apic) == EOK) && (apic)) {
     101                irc_service = SERVICE_APIC;
    102102        } else if ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)) {
    103     irc_service = SERVICE_I8259;
    104         }
    105 
    106   if (irc_service == 0)
     103                irc_service = SERVICE_I8259;
     104        }
     105
     106        if (irc_service == -1) {
    107107                return false;
     108        }
    108109
    109110        irc_phone = service_connect_blocking(irc_service, 0, 0);
    110         if (irc_phone < 0)
     111        if (irc_phone < 0) {
    111112                return false;
     113        }
    112114
    113115        size_t i;
    114   for (i = 0; i < dev_data->hw_resources.count; i++) {
     116        for (i = 0; i < dev_data->hw_resources.count; i++) {
    115117                if (dev_data->hw_resources.resources[i].type == INTERRUPT) {
    116118                        int irq = dev_data->hw_resources.resources[i].res.interrupt.irq;
     
    127129}
    128130
    129 static int pci_config_space_write_16(ddf_fun_t *fun, uint32_t address, uint16_t data)
     131static int pci_config_space_write_32(
     132    ddf_fun_t *fun, uint32_t address, uint32_t data)
     133{
     134        if (address > 252)
     135                return EINVAL;
     136        pci_conf_write_32(PCI_FUN(fun), address, data);
     137        return EOK;
     138}
     139
     140static int pci_config_space_write_16(
     141    ddf_fun_t *fun, uint32_t address, uint16_t data)
    130142{
    131143        if (address > 254)
     
    135147}
    136148
     149static int pci_config_space_write_8(
     150    ddf_fun_t *fun, uint32_t address, uint8_t data)
     151{
     152        if (address > 255)
     153                return EINVAL;
     154        pci_conf_write_8(PCI_FUN(fun), address, data);
     155        return EOK;
     156}
     157
     158static int pci_config_space_read_32(
     159    ddf_fun_t *fun, uint32_t address, uint32_t *data)
     160{
     161        if (address > 252)
     162                return EINVAL;
     163        *data = pci_conf_read_32(PCI_FUN(fun), address);
     164        return EOK;
     165}
     166
     167static int pci_config_space_read_16(
     168    ddf_fun_t *fun, uint32_t address, uint16_t *data)
     169{
     170        if (address > 254)
     171                return EINVAL;
     172        *data = pci_conf_read_16(PCI_FUN(fun), address);
     173        return EOK;
     174}
     175
     176static int pci_config_space_read_8(
     177    ddf_fun_t *fun, uint32_t address, uint8_t *data)
     178{
     179        if (address > 255)
     180                return EINVAL;
     181        *data = pci_conf_read_8(PCI_FUN(fun), address);
     182        return EOK;
     183}
    137184
    138185static hw_res_ops_t pciintel_hw_res_ops = {
     
    142189
    143190static pci_dev_iface_t pci_dev_ops = {
    144         .config_space_read_8 = NULL,
    145         .config_space_read_16 = NULL,
    146         .config_space_read_32 = NULL,
    147         .config_space_write_8 = NULL,
     191        .config_space_read_8 = &pci_config_space_read_8,
     192        .config_space_read_16 = &pci_config_space_read_16,
     193        .config_space_read_32 = &pci_config_space_read_32,
     194        .config_space_write_8 = &pci_config_space_write_8,
    148195        .config_space_write_16 = &pci_config_space_write_16,
    149         .config_space_write_32 = NULL
     196        .config_space_write_32 = &pci_config_space_write_32
    150197};
    151198
  • uspace/drv/uhci-hcd/Makefile

    r3e7b7cd r72af8da  
    3535        iface.c \
    3636        main.c \
    37         root_hub.c \
    3837        transfer_list.c \
    3938        uhci.c \
     39        uhci_hc.c \
     40        uhci_rh.c \
    4041        uhci_struct/transfer_descriptor.c \
    4142        utils/device_keeper.c \
  • uspace/drv/uhci-hcd/batch.c

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcihc
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI driver
     32 * @brief UHCI driver USB transaction structure
    3333 */
    3434#include <errno.h>
     
    4040#include "batch.h"
    4141#include "transfer_list.h"
    42 #include "uhci.h"
     42#include "uhci_hc.h"
    4343#include "utils/malloc32.h"
    4444
    4545#define DEFAULT_ERROR_COUNT 3
    4646
    47 static int batch_schedule(batch_t *instance);
    48 
    49 static void batch_control(
    50     batch_t *instance, int data_stage, int status_stage);
     47static void batch_control(batch_t *instance,
     48    usb_packet_id data_stage, usb_packet_id status_stage);
     49static void batch_data(batch_t *instance, usb_packet_id pid);
    5150static void batch_call_in(batch_t *instance);
    5251static void batch_call_out(batch_t *instance);
     
    5554
    5655
     56/** Allocate memory and initialize internal data structure.
     57 *
     58 * @param[in] fun DDF function to pass to callback.
     59 * @param[in] target Device and endpoint target of the transaction.
     60 * @param[in] transfer_type Interrupt, Control or Bulk.
     61 * @param[in] max_packet_size maximum allowed size of data packets.
     62 * @param[in] speed Speed of the transaction.
     63 * @param[in] buffer Data source/destination.
     64 * @param[in] size Size of the buffer.
     65 * @param[in] setup_buffer Setup data source (if not NULL)
     66 * @param[in] setup_size Size of setup_buffer (should be always 8)
     67 * @param[in] func_in function to call on inbound transaction completion
     68 * @param[in] func_out function to call on outbound transaction completion
     69 * @param[in] arg additional parameter to func_in or func_out
     70 * @param[in] manager Pointer to toggle management structure.
     71 * @return Valid pointer if all substructures were successfully created,
     72 * NULL otherwise.
     73 *
     74 * Determines the number of needed packets (TDs). Prepares a transport buffer
     75 * (that is accessible by the hardware). Initializes parameters needed for the
     76 * transaction and callback.
     77 */
    5778batch_t * batch_get(ddf_fun_t *fun, usb_target_t target,
    5879    usb_transfer_type_t transfer_type, size_t max_packet_size,
     
    6081    char* setup_buffer, size_t setup_size,
    6182    usbhc_iface_transfer_in_callback_t func_in,
    62     usbhc_iface_transfer_out_callback_t func_out, void *arg)
     83    usbhc_iface_transfer_out_callback_t func_out, void *arg,
     84    device_keeper_t *manager
     85    )
    6386{
    6487        assert(func_in == NULL || func_out == NULL);
    6588        assert(func_in != NULL || func_out != NULL);
    6689
     90#define CHECK_NULL_DISPOSE_RETURN(ptr, message...) \
     91        if (ptr == NULL) { \
     92                usb_log_error(message); \
     93                if (instance) { \
     94                        batch_dispose(instance); \
     95                } \
     96                return NULL; \
     97        } else (void)0
     98
    6799        batch_t *instance = malloc(sizeof(batch_t));
    68         if (instance == NULL) {
    69                 usb_log_error("Failed to allocate batch instance.\n");
    70                 return NULL;
    71         }
    72 
    73         instance->qh = queue_head_get();
    74         if (instance->qh == NULL) {
    75                 usb_log_error("Failed to allocate queue head.\n");
    76                 free(instance);
    77                 return NULL;
    78         }
     100        CHECK_NULL_DISPOSE_RETURN(instance,
     101            "Failed to allocate batch instance.\n");
     102        bzero(instance, sizeof(batch_t));
     103
     104        instance->qh = malloc32(sizeof(qh_t));
     105        CHECK_NULL_DISPOSE_RETURN(instance->qh,
     106            "Failed to allocate batch queue head.\n");
     107        qh_init(instance->qh);
    79108
    80109        instance->packets = (size + max_packet_size - 1) / max_packet_size;
     
    83112        }
    84113
    85         instance->tds = malloc32(sizeof(transfer_descriptor_t) * instance->packets);
    86         if (instance->tds == NULL) {
    87                 usb_log_error("Failed to allocate transfer descriptors.\n");
    88                 queue_head_dispose(instance->qh);
    89                 free(instance);
    90                 return NULL;
    91         }
    92         bzero(instance->tds, sizeof(transfer_descriptor_t) * instance->packets);
    93 
    94         const size_t transport_size = max_packet_size * instance->packets;
    95 
    96         instance->transport_buffer =
    97            (size > 0) ? malloc32(transport_size) : NULL;
    98 
    99         if ((size > 0) && (instance->transport_buffer == NULL)) {
    100                 usb_log_error("Failed to allocate device accessible buffer.\n");
    101                 queue_head_dispose(instance->qh);
    102                 free32(instance->tds);
    103                 free(instance);
    104                 return NULL;
    105         }
    106 
    107         instance->setup_buffer = setup_buffer ? malloc32(setup_size) : NULL;
    108         if ((setup_size > 0) && (instance->setup_buffer == NULL)) {
    109                 usb_log_error("Failed to allocate device accessible setup buffer.\n");
    110                 queue_head_dispose(instance->qh);
    111                 free32(instance->tds);
    112                 free32(instance->transport_buffer);
    113                 free(instance);
    114                 return NULL;
    115         }
    116         if (instance->setup_buffer) {
     114        instance->tds = malloc32(sizeof(td_t) * instance->packets);
     115        CHECK_NULL_DISPOSE_RETURN(
     116            instance->tds, "Failed to allocate transfer descriptors.\n");
     117        bzero(instance->tds, sizeof(td_t) * instance->packets);
     118
     119        if (size > 0) {
     120                instance->transport_buffer = malloc32(size);
     121                CHECK_NULL_DISPOSE_RETURN(instance->transport_buffer,
     122                    "Failed to allocate device accessible buffer.\n");
     123        }
     124
     125        if (setup_size > 0) {
     126                instance->setup_buffer = malloc32(setup_size);
     127                CHECK_NULL_DISPOSE_RETURN(instance->setup_buffer,
     128                    "Failed to allocate device accessible setup buffer.\n");
    117129                memcpy(instance->setup_buffer, setup_buffer, setup_size);
    118130        }
    119131
     132
     133        link_initialize(&instance->link);
     134
    120135        instance->max_packet_size = max_packet_size;
    121 
    122         link_initialize(&instance->link);
    123 
    124136        instance->target = target;
    125137        instance->transfer_type = transfer_type;
    126 
    127         if (func_out)
    128                 instance->callback_out = func_out;
    129         if (func_in)
    130                 instance->callback_in = func_in;
    131 
    132138        instance->buffer = buffer;
    133139        instance->buffer_size = size;
     
    136142        instance->arg = arg;
    137143        instance->speed = speed;
    138 
    139         queue_head_element_td(instance->qh, addr_to_phys(instance->tds));
     144        instance->manager = manager;
     145        instance->callback_out = func_out;
     146        instance->callback_in = func_in;
     147
     148        qh_set_element_td(instance->qh, addr_to_phys(instance->tds));
     149
    140150        usb_log_debug("Batch(%p) %d:%d memory structures ready.\n",
    141151            instance, target.address, target.endpoint);
     
    143153}
    144154/*----------------------------------------------------------------------------*/
     155/** Check batch TDs for activity.
     156 *
     157 * @param[in] instance Batch structure to use.
     158 * @return False, if there is an active TD, true otherwise.
     159 *
     160 * Walk all TDs. Stop with false if there is an active one (it is to be
     161 * processed). Stop with true if an error is found. Return true if the last TS
     162 * is reached.
     163 */
    145164bool batch_is_complete(batch_t *instance)
    146165{
     
    151170        size_t i = 0;
    152171        for (;i < instance->packets; ++i) {
    153                 if (transfer_descriptor_is_active(&instance->tds[i])) {
     172                if (td_is_active(&instance->tds[i])) {
    154173                        return false;
    155174                }
    156                 instance->error = transfer_descriptor_status(&instance->tds[i]);
     175
     176                instance->error = td_status(&instance->tds[i]);
    157177                if (instance->error != EOK) {
     178                        usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
     179                            instance, i, instance->tds[i].status);
     180                        td_print_status(&instance->tds[i]);
     181
     182                        device_keeper_set_toggle(instance->manager,
     183                            instance->target, td_toggle(&instance->tds[i]));
    158184                        if (i > 0)
    159                                 instance->transfered_size -= instance->setup_size;
    160                         usb_log_debug("Batch(%p) found error TD(%d):%x.\n",
    161                           instance, i, instance->tds[i].status);
     185                                goto substract_ret;
    162186                        return true;
    163187                }
    164                 instance->transfered_size +=
    165                     transfer_descriptor_actual_size(&instance->tds[i]);
    166         }
     188
     189                instance->transfered_size += td_act_size(&instance->tds[i]);
     190                if (td_is_short(&instance->tds[i]))
     191                        goto substract_ret;
     192        }
     193substract_ret:
    167194        instance->transfered_size -= instance->setup_size;
    168195        return true;
    169196}
    170197/*----------------------------------------------------------------------------*/
     198/** Prepares control write transaction.
     199 *
     200 * @param[in] instance Batch structure to use.
     201 *
     202 * Uses genercir control function with pids OUT and IN.
     203 */
    171204void batch_control_write(batch_t *instance)
    172205{
    173206        assert(instance);
    174         /* we are data out, we are supposed to provide data */
    175         memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
     207        /* We are data out, we are supposed to provide data */
     208        memcpy(instance->transport_buffer, instance->buffer,
     209            instance->buffer_size);
    176210        batch_control(instance, USB_PID_OUT, USB_PID_IN);
    177211        instance->next_step = batch_call_out_and_dispose;
    178212        usb_log_debug("Batch(%p) CONTROL WRITE initialized.\n", instance);
    179         batch_schedule(instance);
    180 }
    181 /*----------------------------------------------------------------------------*/
     213}
     214/*----------------------------------------------------------------------------*/
     215/** Prepares control read transaction.
     216 *
     217 * @param[in] instance Batch structure to use.
     218 *
     219 * Uses generic control with pids IN and OUT.
     220 */
    182221void batch_control_read(batch_t *instance)
    183222{
     
    186225        instance->next_step = batch_call_in_and_dispose;
    187226        usb_log_debug("Batch(%p) CONTROL READ initialized.\n", instance);
    188         batch_schedule(instance);
    189 }
    190 /*----------------------------------------------------------------------------*/
     227}
     228/*----------------------------------------------------------------------------*/
     229/** Prepare interrupt in transaction.
     230 *
     231 * @param[in] instance Batch structure to use.
     232 *
     233 * Data transaction with PID_IN.
     234 */
    191235void batch_interrupt_in(batch_t *instance)
    192236{
    193237        assert(instance);
    194 
    195         const bool low_speed = instance->speed == USB_SPEED_LOW;
    196         int toggle = 1;
    197         size_t i = 0;
    198         for (;i < instance->packets; ++i) {
    199                 char *data =
    200                     instance->transport_buffer + (i  * instance->max_packet_size);
    201                 transfer_descriptor_t *next = (i + 1) < instance->packets ?
    202                     &instance->tds[i + 1] : NULL;
    203                 toggle = 1 - toggle;
    204 
    205                 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
    206                     instance->max_packet_size, toggle, false, low_speed,
    207                     instance->target, USB_PID_IN, data, next);
    208         }
    209 
    210         instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
    211 
     238        batch_data(instance, USB_PID_IN);
    212239        instance->next_step = batch_call_in_and_dispose;
    213240        usb_log_debug("Batch(%p) INTERRUPT IN initialized.\n", instance);
    214         batch_schedule(instance);
    215 }
    216 /*----------------------------------------------------------------------------*/
     241}
     242/*----------------------------------------------------------------------------*/
     243/** Prepare interrupt out transaction.
     244 *
     245 * @param[in] instance Batch structure to use.
     246 *
     247 * Data transaction with PID_OUT.
     248 */
    217249void batch_interrupt_out(batch_t *instance)
    218250{
    219251        assert(instance);
     252        /* We are data out, we are supposed to provide data */
    220253        memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
    221 
    222         const bool low_speed = instance->speed == USB_SPEED_LOW;
    223         int toggle = 1;
    224         size_t i = 0;
    225         for (;i < instance->packets; ++i) {
    226                 char *data =
    227                     instance->transport_buffer + (i  * instance->max_packet_size);
    228                 transfer_descriptor_t *next = (i + 1) < instance->packets ?
    229                     &instance->tds[i + 1] : NULL;
    230                 toggle = 1 - toggle;
    231 
    232                 transfer_descriptor_init(&instance->tds[i], DEFAULT_ERROR_COUNT,
    233                     instance->max_packet_size, toggle++, false, low_speed,
    234                     instance->target, USB_PID_OUT, data, next);
    235         }
    236 
    237         instance->tds[i - 1].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
    238 
     254        batch_data(instance, USB_PID_OUT);
    239255        instance->next_step = batch_call_out_and_dispose;
    240256        usb_log_debug("Batch(%p) INTERRUPT OUT initialized.\n", instance);
    241         batch_schedule(instance);
    242 }
    243 /*----------------------------------------------------------------------------*/
    244 static void batch_control(
    245     batch_t *instance, int data_stage, int status_stage)
     257}
     258/*----------------------------------------------------------------------------*/
     259/** Prepare bulk in transaction.
     260 *
     261 * @param[in] instance Batch structure to use.
     262 *
     263 * Data transaction with PID_IN.
     264 */
     265void batch_bulk_in(batch_t *instance)
     266{
     267        assert(instance);
     268        batch_data(instance, USB_PID_IN);
     269        instance->next_step = batch_call_in_and_dispose;
     270        usb_log_debug("Batch(%p) BULK IN initialized.\n", instance);
     271}
     272/*----------------------------------------------------------------------------*/
     273/** Prepare bulk out transaction.
     274 *
     275 * @param[in] instance Batch structure to use.
     276 *
     277 * Data transaction with PID_OUT.
     278 */
     279void batch_bulk_out(batch_t *instance)
     280{
     281        assert(instance);
     282        /* We are data out, we are supposed to provide data */
     283        memcpy(instance->transport_buffer, instance->buffer, instance->buffer_size);
     284        batch_data(instance, USB_PID_OUT);
     285        instance->next_step = batch_call_out_and_dispose;
     286        usb_log_debug("Batch(%p) BULK OUT initialized.\n", instance);
     287}
     288/*----------------------------------------------------------------------------*/
     289/** Prepare generic data transaction
     290 *
     291 * @param[in] instance Batch structure to use.
     292 * @param[in] pid to use for data packets.
     293 *
     294 * Packets with alternating toggle bit and supplied pid value.
     295 * The last packet is marked with IOC flag.
     296 */
     297void batch_data(batch_t *instance, usb_packet_id pid)
     298{
     299        assert(instance);
     300        const bool low_speed = instance->speed == USB_SPEED_LOW;
     301        int toggle =
     302            device_keeper_get_toggle(instance->manager, instance->target);
     303        assert(toggle == 0 || toggle == 1);
     304
     305        size_t packet = 0;
     306        size_t remain_size = instance->buffer_size;
     307        while (remain_size > 0) {
     308                char *data =
     309                    instance->transport_buffer + instance->buffer_size
     310                    - remain_size;
     311
     312                const size_t packet_size =
     313                    (instance->max_packet_size > remain_size) ?
     314                    remain_size : instance->max_packet_size;
     315
     316                td_t *next_packet = (packet + 1 < instance->packets)
     317                    ? &instance->tds[packet + 1] : NULL;
     318
     319                assert(packet < instance->packets);
     320                assert(packet_size <= remain_size);
     321
     322                td_init(
     323                    &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
     324                    toggle, false, low_speed, instance->target, pid, data,
     325                    next_packet);
     326
     327
     328                toggle = 1 - toggle;
     329                remain_size -= packet_size;
     330                ++packet;
     331        }
     332        td_set_ioc(&instance->tds[packet - 1]);
     333        device_keeper_set_toggle(instance->manager, instance->target, toggle);
     334}
     335/*----------------------------------------------------------------------------*/
     336/** Prepare generic control transaction
     337 *
     338 * @param[in] instance Batch structure to use.
     339 * @param[in] data_stage to use for data packets.
     340 * @param[in] status_stage to use for data packets.
     341 *
     342 * Setup stage with toggle 0 and USB_PID_SETUP.
     343 * Data stage with alternating toggle and pid supplied by parameter.
     344 * Status stage with toggle 1 and pid supplied by parameter.
     345 * The last packet is marked with IOC.
     346 */
     347void batch_control(batch_t *instance,
     348   usb_packet_id data_stage, usb_packet_id status_stage)
    246349{
    247350        assert(instance);
     
    250353        int toggle = 0;
    251354        /* setup stage */
    252         transfer_descriptor_init(instance->tds, DEFAULT_ERROR_COUNT,
     355        td_init(instance->tds, DEFAULT_ERROR_COUNT,
    253356            instance->setup_size, toggle, false, low_speed, instance->target,
    254357            USB_PID_SETUP, instance->setup_buffer, &instance->tds[1]);
     
    268371                    remain_size : instance->max_packet_size;
    269372
    270                 transfer_descriptor_init(&instance->tds[packet],
    271                     DEFAULT_ERROR_COUNT, packet_size, toggle, false, low_speed,
    272                     instance->target, data_stage, data,
    273                     &instance->tds[packet + 1]);
     373                td_init(
     374                    &instance->tds[packet], DEFAULT_ERROR_COUNT, packet_size,
     375                    toggle, false, low_speed, instance->target, data_stage,
     376                    data, &instance->tds[packet + 1]);
    274377
    275378                ++packet;
     
    281384        /* status stage */
    282385        assert(packet == instance->packets - 1);
    283         transfer_descriptor_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
     386        td_init(&instance->tds[packet], DEFAULT_ERROR_COUNT,
    284387            0, 1, false, low_speed, instance->target, status_stage, NULL, NULL);
    285388
    286 
    287         instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG;
     389        td_set_ioc(&instance->tds[packet]);
    288390        usb_log_debug2("Control last TD status: %x.\n",
    289391            instance->tds[packet].status);
    290392}
    291393/*----------------------------------------------------------------------------*/
     394/** Prepare data, get error status and call callback in.
     395 *
     396 * @param[in] instance Batch structure to use.
     397 * Copies data from transport buffer, and calls callback with appropriate
     398 * parameters.
     399 */
    292400void batch_call_in(batch_t *instance)
    293401{
     
    295403        assert(instance->callback_in);
    296404
    297         memcpy(instance->buffer, instance->transport_buffer, instance->buffer_size);
     405        /* We are data in, we need data */
     406        memcpy(instance->buffer, instance->transport_buffer,
     407            instance->buffer_size);
    298408
    299409        int err = instance->error;
     
    302412            instance->transfered_size);
    303413
    304         instance->callback_in(instance->fun,
    305             err, instance->transfered_size,
    306             instance->arg);
    307 }
    308 /*----------------------------------------------------------------------------*/
     414        instance->callback_in(
     415            instance->fun, err, instance->transfered_size, instance->arg);
     416}
     417/*----------------------------------------------------------------------------*/
     418/** Get error status and call callback out.
     419 *
     420 * @param[in] instance Batch structure to use.
     421 */
    309422void batch_call_out(batch_t *instance)
    310423{
     
    319432}
    320433/*----------------------------------------------------------------------------*/
     434/** Helper function calls callback and correctly disposes of batch structure.
     435 *
     436 * @param[in] instance Batch structure to use.
     437 */
    321438void batch_call_in_and_dispose(batch_t *instance)
    322439{
    323440        assert(instance);
    324441        batch_call_in(instance);
     442        batch_dispose(instance);
     443}
     444/*----------------------------------------------------------------------------*/
     445/** Helper function calls callback and correctly disposes of batch structure.
     446 *
     447 * @param[in] instance Batch structure to use.
     448 */
     449void batch_call_out_and_dispose(batch_t *instance)
     450{
     451        assert(instance);
     452        batch_call_out(instance);
     453        batch_dispose(instance);
     454}
     455/*----------------------------------------------------------------------------*/
     456/** Correctly dispose all used data structures.
     457 *
     458 * @param[in] instance Batch structure to use.
     459 */
     460void batch_dispose(batch_t *instance)
     461{
     462        assert(instance);
    325463        usb_log_debug("Batch(%p) disposing.\n", instance);
     464        /* free32 is NULL safe */
    326465        free32(instance->tds);
    327466        free32(instance->qh);
     
    330469        free(instance);
    331470}
    332 /*----------------------------------------------------------------------------*/
    333 void batch_call_out_and_dispose(batch_t *instance)
    334 {
    335         assert(instance);
    336         batch_call_out(instance);
    337         usb_log_debug("Batch(%p) disposing.\n", instance);
    338         free32(instance->tds);
    339         free32(instance->qh);
    340         free32(instance->setup_buffer);
    341         free32(instance->transport_buffer);
    342         free(instance);
    343 }
    344 /*----------------------------------------------------------------------------*/
    345 int batch_schedule(batch_t *instance)
    346 {
    347         assert(instance);
    348         uhci_t *hc = fun_to_uhci(instance->fun);
    349         assert(hc);
    350         return uhci_schedule(hc, instance);
    351 }
    352471/**
    353472 * @}
  • uspace/drv/uhci-hcd/batch.h

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcihc
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI driver
     32 * @brief UHCI driver USB transaction structure
    3333 */
    3434#ifndef DRV_UHCI_BATCH_H
     
    4242#include "uhci_struct/transfer_descriptor.h"
    4343#include "uhci_struct/queue_head.h"
     44#include "utils/device_keeper.h"
    4445
    4546typedef struct batch
     
    4950        usb_target_t target;
    5051        usb_transfer_type_t transfer_type;
    51         union {
    52                 usbhc_iface_transfer_in_callback_t callback_in;
    53                 usbhc_iface_transfer_out_callback_t callback_out;
    54         };
     52        usbhc_iface_transfer_in_callback_t callback_in;
     53        usbhc_iface_transfer_out_callback_t callback_out;
    5554        void *arg;
    5655        char *transport_buffer;
     
    6463        int error;
    6564        ddf_fun_t *fun;
    66         queue_head_t *qh;
    67         transfer_descriptor_t *tds;
     65        qh_t *qh;
     66        td_t *tds;
    6867        void (*next_step)(struct batch*);
     68        device_keeper_t *manager;
    6969} batch_t;
    7070
     
    7474                char *setup_buffer, size_t setup_size,
    7575    usbhc_iface_transfer_in_callback_t func_in,
    76     usbhc_iface_transfer_out_callback_t func_out, void *arg);
     76    usbhc_iface_transfer_out_callback_t func_out, void *arg,
     77                device_keeper_t *manager
     78                );
     79
     80void batch_dispose(batch_t *instance);
    7781
    7882bool batch_is_complete(batch_t *instance);
     
    8690void batch_interrupt_out(batch_t *instance);
    8791
    88 /* DEPRECATED FUNCTIONS NEEDED BY THE OLD API */
    89 void batch_control_setup_old(batch_t *instance);
     92void batch_bulk_in(batch_t *instance);
    9093
    91 void batch_control_write_data_old(batch_t *instance);
    92 
    93 void batch_control_read_data_old(batch_t *instance);
    94 
    95 void batch_control_write_status_old(batch_t *instance);
    96 
    97 void batch_control_read_status_old(batch_t *instance);
     94void batch_bulk_out(batch_t *instance);
    9895#endif
    9996/**
  • uspace/drv/uhci-hcd/iface.c

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

    r3e7b7cd r72af8da  
    2727 */
    2828
    29 /** @addtogroup usb
     29/** @addtogroup drvusbuhcihc
    3030 * @{
    3131 */
    3232/** @file
    33  * @brief UHCI driver
     33 * @brief UHCI driver iface
    3434 */
    3535#ifndef DRV_UHCI_IFACE_H
     
    3838#include <usbhc_iface.h>
    3939
    40 extern usbhc_iface_t uhci_iface;
     40extern usbhc_iface_t uhci_hc_iface;
    4141
    4242#endif
  • uspace/drv/uhci-hcd/main.c

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

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

    r3e7b7cd r72af8da  
    2727 */
    2828
    29 /** @addtogroup drvusbuhci
     29/** @addtogroup drvusbuhcihc
    3030 * @{
    3131 */
    3232/** @file
    33  * @brief UHCI driver
     33 * @brief UHCI driver PCI helper functions
    3434 */
    3535#ifndef DRV_UHCI_PCI_H
  • uspace/drv/uhci-hcd/transfer_list.c

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

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcihc
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI driver
     32 * @brief UHCI driver transfer list structure
    3333 */
    3434#ifndef DRV_UHCI_TRANSFER_LIST_H
     
    4444{
    4545        fibril_mutex_t guard;
    46         queue_head_t *queue_head;
     46        qh_t *queue_head;
    4747        uint32_t queue_head_pa;
    48         struct transfer_list *next;
    4948        const char *name;
    5049        link_t batch_list;
    5150} transfer_list_t;
     51
     52/** Dispose transfer list structures.
     53 *
     54 * @param[in] instance Memory place to use.
     55 *
     56 * Frees memory for internal qh_t structure.
     57 */
     58static inline void transfer_list_fini(transfer_list_t *instance)
     59{
     60        assert(instance);
     61        free32(instance->queue_head);
     62}
    5263
    5364int transfer_list_init(transfer_list_t *instance, const char *name);
     
    5566void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next);
    5667
    57 static inline void transfer_list_fini(transfer_list_t *instance)
    58 {
    59         assert(instance);
    60         queue_head_dispose(instance->queue_head);
    61 }
    6268void transfer_list_remove_finished(transfer_list_t *instance);
    6369
  • uspace/drv/uhci-hcd/uhci.c

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

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

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

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

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

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

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

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

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

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

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

    r3e7b7cd r72af8da  
    3535        main.c \
    3636        port.c \
    37         port_status.c \
    3837        root_hub.c
    3938
  • uspace/drv/uhci-rhd/main.c

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcirh
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI driver
     32 * @brief UHCI root hub initialization routines
    3333 */
    3434#include <ddf/driver.h>
    3535#include <devman.h>
    3636#include <device/hw_res.h>
     37#include <errno.h>
    3738#include <usb_iface.h>
    3839#include <usb/ddfiface.h>
    39 
    40 #include <errno.h>
    41 
    4240#include <usb/debug.h>
    4341
     
    4745static int hc_get_my_registers(ddf_dev_t *dev,
    4846    uintptr_t *io_reg_address, size_t *io_reg_size);
    49 
     47#if 0
     48/*----------------------------------------------------------------------------*/
    5049static int usb_iface_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
    5150{
     
    5857        return EOK;
    5958}
    60 
     59/*----------------------------------------------------------------------------*/
    6160static usb_iface_t uhci_rh_usb_iface = {
    6261        .get_hc_handle = usb_iface_get_hc_handle,
    6362        .get_address = usb_iface_get_address_hub_impl
    6463};
    65 
     64/*----------------------------------------------------------------------------*/
    6665static ddf_dev_ops_t uhci_rh_ops = {
    6766        .interfaces[USB_DEV_IFACE] = &uhci_rh_usb_iface,
    6867};
    69 
     68#endif
     69/*----------------------------------------------------------------------------*/
     70/** Initialize a new ddf driver instance of UHCI root hub.
     71 *
     72 * @param[in] device DDF instance of the device to initialize.
     73 * @return Error code.
     74 */
    7075static int uhci_rh_add_device(ddf_dev_t *device)
    7176{
     
    7681
    7782        //device->ops = &uhci_rh_ops;
    78         (void) uhci_rh_ops;
    79 
    80         uhci_root_hub_t *rh = malloc(sizeof(uhci_root_hub_t));
    81         if (!rh) {
    82                 usb_log_error("Failed to allocate memory for driver instance.\n");
    83                 return ENOMEM;
    84         }
    85 
    8683        uintptr_t io_regs = 0;
    8784        size_t io_size = 0;
    8885
    8986        int ret = hc_get_my_registers(device, &io_regs, &io_size);
    90         assert(ret == EOK);
     87        if (ret != EOK) {
     88                usb_log_error("Failed(%d) to get registers from parent hc.",
     89                    ret);
     90        }
     91        usb_log_info("I/O regs at %#X (size %zu).\n", io_regs, io_size);
    9192
    92         /* TODO: verify values from hc */
    93         usb_log_info("I/O regs at 0x%X (size %zu).\n", io_regs, io_size);
     93        uhci_root_hub_t *rh = malloc(sizeof(uhci_root_hub_t));
     94        if (!rh) {
     95                usb_log_error("Failed to allocate driver instance.\n");
     96                return ENOMEM;
     97        }
     98
    9499        ret = uhci_root_hub_init(rh, (void*)io_regs, io_size, device);
    95100        if (ret != EOK) {
     
    104109        return EOK;
    105110}
    106 
     111/*----------------------------------------------------------------------------*/
    107112static driver_ops_t uhci_rh_driver_ops = {
    108113        .add_device = uhci_rh_add_device,
    109114};
    110 
     115/*----------------------------------------------------------------------------*/
    111116static driver_t uhci_rh_driver = {
    112117        .name = NAME,
     
    114119};
    115120/*----------------------------------------------------------------------------*/
     121/** Initialize global driver structures (NONE).
     122 *
     123 * @param[in] argc Nmber of arguments in argv vector (ignored).
     124 * @param[in] argv Cmdline argument vector (ignored).
     125 * @return Error code.
     126 *
     127 * Driver debug level is set here.
     128 */
    116129int main(int argc, char *argv[])
    117130{
     
    120133}
    121134/*----------------------------------------------------------------------------*/
    122 int hc_get_my_registers(ddf_dev_t *dev,
    123     uintptr_t *io_reg_address, size_t *io_reg_size)
     135/** Get address of I/O registers.
     136 *
     137 * @param[in] dev Device asking for the addresses.
     138 * @param[out] io_reg_address Base address of the memory range.
     139 * @param[out] io_reg_size Size of the memory range.
     140 * @return Error code.
     141 */
     142int hc_get_my_registers(
     143    ddf_dev_t *dev, uintptr_t *io_reg_address, size_t *io_reg_size)
    124144{
    125145        assert(dev != NULL);
     
    146166        for (i = 0; i < hw_resources.count; i++) {
    147167                hw_resource_t *res = &hw_resources.resources[i];
    148                 switch (res->type) {
    149                         case IO_RANGE:
    150                                 io_address = (uintptr_t)
    151                                     res->res.io_range.address;
    152                                 io_size = res->res.io_range.size;
    153                                 io_found = true;
    154                                 break;
    155                         default:
    156                                 break;
     168                switch (res->type)
     169                {
     170                case IO_RANGE:
     171                        io_address = (uintptr_t) res->res.io_range.address;
     172                        io_size = res->res.io_range.size;
     173                        io_found = true;
     174
     175                default:
     176                        break;
    157177                }
    158178        }
     
    170190        }
    171191        rc = EOK;
     192
    172193leave:
    173194        async_hangup(parent_phone);
    174 
    175195        return rc;
    176196}
  • uspace/drv/uhci-rhd/port.c

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcirh
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI driver
    33  */
     32 * @brief UHCI root hub port routines
     33 */
     34#include <libarch/ddi.h> /* pio_read and pio_write */
    3435#include <errno.h>
    3536#include <str_error.h>
     
    3738
    3839#include <usb/usb.h>    /* usb_address_t */
    39 #include <usb/usbdevice.h>
    4040#include <usb/hub.h>
    41 #include <usb/request.h>
    4241#include <usb/debug.h>
    43 #include <usb/recognise.h>
    4442
    4543#include "port.h"
    46 #include "port_status.h"
    47 
    48 static int uhci_port_new_device(uhci_port_t *port, uint16_t status);
     44
     45static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed);
    4946static int uhci_port_remove_device(uhci_port_t *port);
    5047static int uhci_port_set_enabled(uhci_port_t *port, bool enabled);
    5148static int uhci_port_check(void *port);
    52 static int new_device_enable_port(int portno, void *arg);
    53 
    54 int uhci_port_init(
    55   uhci_port_t *port, port_status_t *address, unsigned number,
    56   unsigned usec, ddf_dev_t *rh)
    57 {
    58         assert(port);
     49static int uhci_port_reset_enable(int portno, void *arg);
     50static void uhci_port_print_status(
     51    uhci_port_t *port, const port_status_t value);
     52
     53/** Register reading helper function.
     54 *
     55 * @param[in] port Structure to use.
     56 * @return Error code. (Always EOK)
     57 */
     58static inline port_status_t uhci_port_read_status(uhci_port_t *port)
     59{
     60        assert(port);
     61        return pio_read_16(port->address);
     62}
     63/*----------------------------------------------------------------------------*/
     64/** Register writing helper function.
     65 *
     66 * @param[in] port Structure to use.
     67 * @param[in] value New register value.
     68 * @return Error code. (Always EOK)
     69 */
     70static inline void uhci_port_write_status(
     71    uhci_port_t *port, port_status_t value)
     72{
     73        assert(port);
     74        pio_write_16(port->address, value);
     75}
     76
     77/*----------------------------------------------------------------------------*/
     78/** Initialize UHCI root hub port instance.
     79 *
     80 * @param[in] port Memory structure to use.
     81 * @param[in] addr Address of I/O register.
     82 * @param[in] number Port number.
     83 * @param[in] usec Polling interval.
     84 * @param[in] rh Pointer to ddf instance fo the root hub driver.
     85 * @return Error code.
     86 *
     87 * Creates and starts the polling fibril.
     88 */
     89int uhci_port_init(uhci_port_t *port,
     90    port_status_t *address, unsigned number, unsigned usec, ddf_dev_t *rh)
     91{
     92        assert(port);
     93        asprintf(&port->id_string, "Port (%p - %d)", port, number);
     94        if (port->id_string == NULL) {
     95                return ENOMEM;
     96        }
     97
    5998        port->address = address;
    6099        port->number = number;
     
    62101        port->attached_device = 0;
    63102        port->rh = rh;
     103
    64104        int rc = usb_hc_connection_initialize_from_device(
    65105            &port->hc_connection, rh);
     
    71111        port->checker = fibril_create(uhci_port_check, port);
    72112        if (port->checker == 0) {
    73                 usb_log_error("Port(%p - %d): failed to launch root hub fibril.",
    74                     port->address, port->number);
     113                usb_log_error("%s: failed to create polling fibril.",
     114                    port->id_string);
    75115                return ENOMEM;
    76116        }
     117
    77118        fibril_add_ready(port->checker);
    78         usb_log_debug("Port(%p - %d): Added fibril. %x\n",
    79             port->address, port->number, port->checker);
    80         return EOK;
    81 }
    82 /*----------------------------------------------------------------------------*/
     119        usb_log_debug("%s: Started polling fibril(%x).\n",
     120            port->id_string, port->checker);
     121        return EOK;
     122}
     123/*----------------------------------------------------------------------------*/
     124/** Cleanup UHCI root hub port instance.
     125 *
     126 * @param[in] port Memory structure to use.
     127 *
     128 * Stops the polling fibril.
     129 */
    83130void uhci_port_fini(uhci_port_t *port)
    84131{
    85 // TODO: destroy fibril
    86 // TODO: hangup phone
    87 //      fibril_teardown(port->checker);
     132        assert(port);
     133        free(port->id_string);
     134        /* TODO: Kill fibril here */
    88135        return;
    89136}
    90137/*----------------------------------------------------------------------------*/
     138/** Periodically checks port status and reports new devices.
     139 *
     140 * @param[in] port Port structure to use.
     141 * @return Error code.
     142 */
    91143int uhci_port_check(void *port)
    92144{
    93         uhci_port_t *port_instance = port;
    94         assert(port_instance);
    95 //      port_status_write(port_instance->address, 0);
    96 
    97         unsigned count = 0;
     145        uhci_port_t *instance = port;
     146        assert(instance);
    98147
    99148        while (1) {
    100                 async_usleep(port_instance->wait_period_usec);
    101 
    102                 /* read register value */
    103                 port_status_t port_status =
    104                         port_status_read(port_instance->address);
    105 
    106                 /* debug print */
    107                 static fibril_mutex_t dbg_mtx = FIBRIL_MUTEX_INITIALIZER(dbg_mtx);
    108                 fibril_mutex_lock(&dbg_mtx);
    109                 usb_log_debug2("Port(%p - %d): Status: %#04x. === %u\n",
    110                   port_instance->address, port_instance->number, port_status, count++);
    111 //              print_port_status(port_status);
    112                 fibril_mutex_unlock(&dbg_mtx);
    113 
    114                 if ((port_status & STATUS_CONNECTED_CHANGED) != 0) {
    115                         usb_log_debug("Port(%p - %d): Connected change detected: %x.\n",
    116                             port_instance->address, port_instance->number, port_status);
    117 
    118 
    119                         int rc = usb_hc_connection_open(
    120                             &port_instance->hc_connection);
    121                         if (rc != EOK) {
    122                                 usb_log_error("Port(%p - %d): Failed to connect to HC.",
    123                                     port_instance->address, port_instance->number);
    124                                 continue;
    125                         }
    126 
    127                         /* remove any old device */
    128                         if (port_instance->attached_device) {
    129                                 usb_log_debug("Port(%p - %d): Removing device.\n",
    130                                     port_instance->address, port_instance->number);
    131                                 uhci_port_remove_device(port_instance);
    132                         }
    133 
    134                         if ((port_status & STATUS_CONNECTED) != 0) {
    135                                 /* new device */
    136                                 uhci_port_new_device(port_instance, port_status);
    137                         } else {
    138                                 /* ack changes by writing one to WC bits */
    139                                 port_status_write(port_instance->address, port_status);
    140                                 usb_log_debug("Port(%p - %d): Change status ACK.\n",
    141                                                 port_instance->address, port_instance->number);
    142                         }
    143 
    144                         rc = usb_hc_connection_close(
    145                             &port_instance->hc_connection);
    146                         if (rc != EOK) {
    147                                 usb_log_error("Port(%p - %d): Failed to disconnect from HC.",
    148                                     port_instance->address, port_instance->number);
    149                         }
     149                async_usleep(instance->wait_period_usec);
     150
     151                /* Read register value */
     152                port_status_t port_status = uhci_port_read_status(instance);
     153
     154                /* Print the value if it's interesting */
     155                if (port_status & ~STATUS_ALWAYS_ONE)
     156                        uhci_port_print_status(instance, port_status);
     157
     158                if ((port_status & STATUS_CONNECTED_CHANGED) == 0)
     159                        continue;
     160
     161                usb_log_debug("%s: Connected change detected: %x.\n",
     162                    instance->id_string, port_status);
     163
     164                int rc =
     165                    usb_hc_connection_open(&instance->hc_connection);
     166                if (rc != EOK) {
     167                        usb_log_error("%s: Failed to connect to HC.",
     168                            instance->id_string);
     169                        continue;
    150170                }
    151         }
    152         return EOK;
    153 }
    154 
     171
     172                /* Remove any old device */
     173                if (instance->attached_device) {
     174                        usb_log_debug2("%s: Removing device.\n",
     175                            instance->id_string);
     176                        uhci_port_remove_device(instance);
     177                }
     178
     179                if ((port_status & STATUS_CONNECTED) != 0) {
     180                        /* New device */
     181                        const usb_speed_t speed =
     182                            ((port_status & STATUS_LOW_SPEED) != 0) ?
     183                            USB_SPEED_LOW : USB_SPEED_FULL;
     184                        uhci_port_new_device(instance, speed);
     185                } else {
     186                        /* Write one to WC bits, to ack changes */
     187                        uhci_port_write_status(instance, port_status);
     188                        usb_log_debug("%s: status change ACK.\n",
     189                            instance->id_string);
     190                }
     191
     192                rc = usb_hc_connection_close(&instance->hc_connection);
     193                if (rc != EOK) {
     194                        usb_log_error("%s: Failed to disconnect.",
     195                            instance->id_string);
     196                }
     197        }
     198        return EOK;
     199}
     200/*----------------------------------------------------------------------------*/
    155201/** Callback for enabling port during adding a new device.
    156202 *
     
    158204 * @param arg Pointer to uhci_port_t of port with the new device.
    159205 * @return Error code.
    160  */
    161 static int new_device_enable_port(int portno, void *arg)
     206 *
     207 * Resets and enables the ub port.
     208 */
     209int uhci_port_reset_enable(int portno, void *arg)
    162210{
    163211        uhci_port_t *port = (uhci_port_t *) arg;
    164212
    165         usb_log_debug2("Port(%p - %d): new_device_enable_port.\n",
    166             port->address, port->number);
     213        usb_log_debug2("%s: new_device_enable_port.\n", port->id_string);
    167214
    168215        /*
     
    172219        async_usleep(100000);
    173220
    174 
    175         /* The hub maintains the reset signal to that port for 10 ms
    176          * (See Section 11.5.1.5)
     221        /*
     222         * Resets from root ports should be nominally 50ms
    177223         */
    178224        {
    179                 usb_log_debug("Port(%p - %d): Reset Signal start.\n",
    180                     port->address, port->number);
    181                 port_status_t port_status =
    182                         port_status_read(port->address);
     225                usb_log_debug("%s: Reset Signal start.\n", port->id_string);
     226                port_status_t port_status = uhci_port_read_status(port);
    183227                port_status |= STATUS_IN_RESET;
    184                 port_status_write(port->address, port_status);
    185                 async_usleep(10000);
    186                 port_status =
    187                         port_status_read(port->address);
     228                uhci_port_write_status(port, port_status);
     229                async_usleep(50000);
     230                port_status = uhci_port_read_status(port);
    188231                port_status &= ~STATUS_IN_RESET;
    189                 port_status_write(port->address, port_status);
    190                 usb_log_debug("Port(%p - %d): Reset Signal stop.\n",
    191                     port->address, port->number);
    192         }
     232                uhci_port_write_status(port, port_status);
     233                usb_log_debug("%s: Reset Signal stop.\n", port->id_string);
     234        }
     235
     236        /* the reset recovery time 10ms */
     237        async_usleep(10000);
    193238
    194239        /* Enable the port. */
     
    197242        return EOK;
    198243}
    199 
    200 /*----------------------------------------------------------------------------*/
    201 static int uhci_port_new_device(uhci_port_t *port, uint16_t status)
     244/*----------------------------------------------------------------------------*/
     245/** Initialize and report connected device.
     246 *
     247 * @param[in] port Port structure to use.
     248 * @param[in] speed Detected speed.
     249 * @return Error code.
     250 *
     251 * Uses libUSB function to do the actual work.
     252 */
     253int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed)
    202254{
    203255        assert(port);
    204256        assert(usb_hc_connection_is_opened(&port->hc_connection));
    205257
    206         usb_log_info("Port(%p-%d): Detected new device.\n",
    207             port->address, port->number);
     258        usb_log_info("%s: Detected new device.\n", port->id_string);
    208259
    209260        usb_address_t dev_addr;
    210261        int rc = usb_hc_new_device_wrapper(port->rh, &port->hc_connection,
    211             ((status & STATUS_LOW_SPEED) != 0) ? USB_SPEED_LOW : USB_SPEED_FULL,
    212             new_device_enable_port, port->number, port,
     262            speed, uhci_port_reset_enable, port->number, port,
    213263            &dev_addr, &port->attached_device, NULL, NULL, NULL);
    214264
    215265        if (rc != EOK) {
    216                 usb_log_error("Port(%p-%d): Failed(%d) adding new device: %s.\n",
    217                     port->address, port->number, rc, str_error(rc));
     266                usb_log_error("%s: Failed(%d) to add device: %s.\n",
     267                    port->id_string, rc, str_error(rc));
    218268                uhci_port_set_enabled(port, false);
    219269                return rc;
    220270        }
    221271
    222         usb_log_info("Port(%p-%d): New device has address %d (handle %zu).\n",
    223             port->address, port->number, dev_addr, port->attached_device);
    224 
    225         return EOK;
    226 }
    227 
    228 /*----------------------------------------------------------------------------*/
    229 static int uhci_port_remove_device(uhci_port_t *port)
    230 {
    231         usb_log_error("Port(%p-%d): Don't know how to remove device %#x.\n",
    232                 port->address, port->number, (unsigned int)port->attached_device);
    233 //      uhci_port_set_enabled(port, false);
    234         return EOK;
    235 }
    236 /*----------------------------------------------------------------------------*/
    237 static int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
    238 {
    239         assert(port);
    240 
    241         /* read register value */
    242         port_status_t port_status
    243                 = port_status_read(port->address);
    244 
    245         /* enable port: register write */
     272        usb_log_info("%s: New device has address %d (handle %zu).\n",
     273            port->id_string, dev_addr, port->attached_device);
     274
     275        return EOK;
     276}
     277/*----------------------------------------------------------------------------*/
     278/** Remove device.
     279 *
     280 * @param[in] port Memory structure to use.
     281 * @return Error code.
     282 *
     283 * Does not work, DDF does not support device removal.
     284 * Does not even free used USB address (it would be dangerous if tis driver
     285 * is still running).
     286 */
     287int uhci_port_remove_device(uhci_port_t *port)
     288{
     289        usb_log_error("%s: Don't know how to remove device %d.\n",
     290            port->id_string, (unsigned int)port->attached_device);
     291        return EOK;
     292}
     293/*----------------------------------------------------------------------------*/
     294/** Enable or disable root hub port.
     295 *
     296 * @param[in] port Port structure to use.
     297 * @param[in] enabled Port status to set.
     298 * @return Error code. (Always EOK)
     299 */
     300int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
     301{
     302        assert(port);
     303
     304        /* Read register value */
     305        port_status_t port_status = uhci_port_read_status(port);
     306
     307        /* Set enabled bit */
    246308        if (enabled) {
    247309                port_status |= STATUS_ENABLED;
     
    249311                port_status &= ~STATUS_ENABLED;
    250312        }
    251         port_status_write(port->address, port_status);
    252 
    253         usb_log_info("Port(%p-%d): %sabled port.\n",
    254                 port->address, port->number, enabled ? "En" : "Dis");
    255         return EOK;
    256 }
    257 /*----------------------------------------------------------------------------*/
     313
     314        /* Write new value. */
     315        uhci_port_write_status(port, port_status);
     316
     317        usb_log_info("%s: %sabled port.\n",
     318                port->id_string, enabled ? "En" : "Dis");
     319        return EOK;
     320}
     321/*----------------------------------------------------------------------------*/
     322/** Print the port status value in a human friendly way
     323 *
     324 * @param[in] port Port structure to use.
     325 * @param[in] value Port register value to print.
     326 * @return Error code. (Always EOK)
     327 */
     328void uhci_port_print_status(uhci_port_t *port, const port_status_t value)
     329{
     330        assert(port);
     331        usb_log_debug2("%s Port status(%#x):%s%s%s%s%s%s%s%s%s%s%s.\n",
     332            port->id_string, value,
     333            (value & STATUS_SUSPEND) ? " SUSPENDED," : "",
     334            (value & STATUS_RESUME) ? " IN RESUME," : "",
     335            (value & STATUS_IN_RESET) ? " IN RESET," : "",
     336            (value & STATUS_LINE_D_MINUS) ? " VD-," : "",
     337            (value & STATUS_LINE_D_PLUS) ? " VD+," : "",
     338            (value & STATUS_LOW_SPEED) ? " LOWSPEED," : "",
     339            (value & STATUS_ENABLED_CHANGED) ? " ENABLED-CHANGE," : "",
     340            (value & STATUS_ENABLED) ? " ENABLED," : "",
     341            (value & STATUS_CONNECTED_CHANGED) ? " CONNECTED-CHANGE," : "",
     342            (value & STATUS_CONNECTED) ? " CONNECTED," : "",
     343            (value & STATUS_ALWAYS_ONE) ? " ALWAYS ONE" : " ERROR: NO ALWAYS ONE"
     344        );
     345}
    258346/**
    259347 * @}
  • uspace/drv/uhci-rhd/port.h

    r3e7b7cd r72af8da  
    11/*
    2  * Copyright (c) 2010 Jan Vesely
     2 * Copyright (c) 2011 Jan Vesely
    33 * All rights reserved.
    44 *
     
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcirh
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI port driver
     32 * @brief UHCI root hub port routines
    3333 */
    3434#ifndef DRV_UHCI_PORT_H
    3535#define DRV_UHCI_PORT_H
    3636
    37 #include <assert.h>
     37#include <stdint.h>
     38#include <fibril.h>
    3839#include <ddf/driver.h>
    39 #include <stdint.h>
    40 #include <usb/usbdevice.h>
     40#include <usb/usbdevice.h> /* usb_hc_connection_t */
    4141
    42 #include "port_status.h"
     42typedef uint16_t port_status_t;
     43#define STATUS_CONNECTED         (1 << 0)
     44#define STATUS_CONNECTED_CHANGED (1 << 1)
     45#define STATUS_ENABLED           (1 << 2)
     46#define STATUS_ENABLED_CHANGED   (1 << 3)
     47#define STATUS_LINE_D_PLUS       (1 << 4)
     48#define STATUS_LINE_D_MINUS      (1 << 5)
     49#define STATUS_RESUME            (1 << 6)
     50#define STATUS_ALWAYS_ONE        (1 << 7)
     51
     52#define STATUS_LOW_SPEED (1 <<  8)
     53#define STATUS_IN_RESET  (1 <<  9)
     54#define STATUS_SUSPEND   (1 << 12)
    4355
    4456typedef struct uhci_port
    4557{
     58        char *id_string;
    4659        port_status_t *address;
    4760        unsigned number;
     
    5871
    5972void uhci_port_fini(uhci_port_t *port);
     73
    6074#endif
    6175/**
  • uspace/drv/uhci-rhd/root_hub.c

    r3e7b7cd r72af8da  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcirh
    2929 * @{
    3030 */
    3131/** @file
    32  * @brief UHCI driver
     32 * @brief UHCI root hub driver
    3333 */
    3434#include <errno.h>
    35 #include <stdint.h>
    3635#include <ddi.h>
    37 #include <devman.h>
    3836#include <usb/debug.h>
    3937
    4038#include "root_hub.h"
    4139
     40/** Initialize UHCI root hub instance.
     41 *
     42 * @param[in] instance Driver memory structure to use.
     43 * @param[in] addr Address of I/O registers.
     44 * @param[in] size Size of available I/O space.
     45 * @param[in] rh Pointer to ddf instance of the root hub driver.
     46 * @return Error code.
     47 */
    4248int uhci_root_hub_init(
    4349  uhci_root_hub_t *instance, void *addr, size_t size, ddf_dev_t *rh)
     
    4753        int ret;
    4854
    49         /* allow access to root hub registers */
    50         assert(sizeof(port_status_t) * UHCI_ROOT_HUB_PORT_COUNT == size);
     55        /* Allow access to root hub port registers */
     56        assert(sizeof(port_status_t) * UHCI_ROOT_HUB_PORT_COUNT <= size);
    5157        port_status_t *regs;
    5258        ret = pio_enable(addr, size, (void**)&regs);
    53 
    5459        if (ret < 0) {
    55                 usb_log_error("Failed to gain access to port registers at %p\n", regs);
     60                usb_log_error(
     61                    "Failed(%d) to gain access to port registers at %p\n",
     62                    ret, regs);
    5663                return ret;
    5764        }
    5865
    59         /* add fibrils for periodic port checks */
     66        /* Initialize root hub ports */
    6067        unsigned i = 0;
    6168        for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) {
    62                 /* mind pointer arithmetics */
     69                /* NOTE: mind pointer arithmetics here */
    6370                ret = uhci_port_init(
    64                   &instance->ports[i], regs + i, i, ROOT_HUB_WAIT_USEC, rh);
     71                    &instance->ports[i], regs + i, i, ROOT_HUB_WAIT_USEC, rh);
    6572                if (ret != EOK) {
    6673                        unsigned j = 0;
     
    7481}
    7582/*----------------------------------------------------------------------------*/
    76 int uhci_root_hub_fini( uhci_root_hub_t* instance )
     83/** Cleanup UHCI root hub instance.
     84 *
     85 * @param[in] instance Root hub structure to use.
     86 * @return Error code.
     87 */
     88int uhci_root_hub_fini(uhci_root_hub_t* instance)
    7789{
    78         assert( instance );
    79         // TODO:
    80         //destroy fibril here
    81         //disable access to registers
     90        assert(instance);
     91        unsigned i = 0;
     92        for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) {
     93                uhci_port_fini(&instance->ports[i]);
     94        }
    8295        return EOK;
    8396}
  • uspace/drv/uhci-rhd/root_hub.h

    r3e7b7cd r72af8da  
    11/*
    2  * Copyright (c) 2010 Jan Vesely
     2 * Copyright (c) 2011 Jan Vesely
    33 * All rights reserved.
    44 *
     
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 /** @addtogroup usb
     28/** @addtogroup drvusbuhcirh
    2929 * @{
    3030 */
     
    3535#define DRV_UHCI_ROOT_HUB_H
    3636
    37 #include <fibril.h>
    3837#include <ddf/driver.h>
    3938
  • uspace/drv/usbhid/Makefile

    r3e7b7cd r72af8da  
    4242        hidreq.c \
    4343        kbddev.c \
     44        kbdrepeat.c \
    4445        hiddev.c \
    4546        $(STOLEN_LAYOUT_SOURCES)
  • uspace/drv/usbhid/conv.c

    r3e7b7cd r72af8da  
    4040#include "conv.h"
    4141
     42/**
     43 * Mapping between USB HID key codes (from HID Usage Tables) and corresponding
     44 * HelenOS key codes.
     45 */
    4246static int scanmap_simple[255] = {
    4347
     
    163167};
    164168
     169/**
     170 * Translate USB HID key codes (from HID Usage Tables) to generic key codes
     171 * recognized by HelenOS.
     172 *
     173 * @param scancode USB HID key code (from HID Usage Tables).
     174 *
     175 * @retval HelenOS key code corresponding to the given USB HID key code.
     176 */
    165177unsigned int usbhid_parse_scancode(int scancode)
    166178{
  • uspace/drv/usbhid/descdump.c

    r3e7b7cd r72af8da  
    4444#define BYTES_PER_LINE 12
    4545
     46/**
     47 * Dumps the given buffer in hexadecimal format to standard output.
     48 *
     49 * @param msg Message to print before the buffer.
     50 * @param buffer Buffer to print.
     51 * @param length Size of the buffer in bytes.
     52 */
    4653static void dump_buffer(const char *msg, const uint8_t *buffer, size_t length)
    4754{
     
    6269#define INDENT "  "
    6370
     71/**
     72 * Print standard configuration descriptor to standard output.
     73 *
     74 * @param index Index of the descriptor.
     75 * @param d Standard configuration descriptor to print.
     76 */
    6477void dump_standard_configuration_descriptor(
    6578    int index, const usb_standard_configuration_descriptor_t *d)
     
    8497}
    8598
     99/**
     100 * Print standard interface descriptor to standard output.
     101 *
     102 * @param d Standard interface descriptor to print.
     103 */
    86104void dump_standard_interface_descriptor(
    87105    const usb_standard_interface_descriptor_t *d)
     
    99117}
    100118
     119/**
     120 * Print standard endpoint descriptor to standard output.
     121 *
     122 * @param d Standard endpoint descriptor to print.
     123 */
    101124void dump_standard_endpoint_descriptor(
    102125    const usb_standard_endpoint_descriptor_t *d)
     
    126149}
    127150
     151/**
     152 * Print standard HID descriptor to standard output.
     153 *
     154 * @param d Standard HID descriptor to print.
     155 */
    128156void dump_standard_hid_descriptor_header(
    129157    const usb_standard_hid_descriptor_t *d)
     
    139167}
    140168
     169/**
     170 * Print HID class-specific descriptor header (type and length) to standard
     171 * output.
     172 *
     173 * @param d HID class-specific descriptor header to print.
     174 */
    141175void dump_standard_hid_class_descriptor_info(
    142176    const usb_standard_hid_class_descriptor_info_t *d)
     
    146180}
    147181
     182/**
     183 * Print HID class-specific descriptor (without the header) to standard output.
     184 *
     185 * @param index Index of the descriptor.
     186 * @param type Type of the HID class-specific descriptor (Report or Physical).
     187 * @param d HID class descriptor to print.
     188 * @param size Size of the descriptor in bytes.
     189 */
    148190void dump_hid_class_descriptor(int index, uint8_t type,
    149191    const uint8_t *d, size_t size )
  • uspace/drv/usbhid/hiddev.c

    r3e7b7cd r72af8da  
    5353/* Non-API functions                                                          */
    5454/*----------------------------------------------------------------------------*/
    55 
     55/**
     56 * Retreives HID Report descriptor from the device.
     57 *
     58 * This function first parses the HID descriptor from the Interface descriptor
     59 * to get the size of the Report descriptor and then requests the Report
     60 * descriptor from the device.
     61 *
     62 * @param hid_dev HID device structure.
     63 * @param config_desc Full configuration descriptor (including all nested
     64 *                    descriptors).
     65 * @param config_desc_size Size of the full configuration descriptor (in bytes).
     66 * @param iface_desc Pointer to the interface descriptor inside the full
     67 *                   configuration descriptor (@a config_desc) for the interface
     68 *                   assigned with this device (@a hid_dev).
     69 *
     70 * @retval EOK if successful.
     71 * @retval ENOENT if no HID descriptor could be found.
     72 * @retval EINVAL if the HID descriptor  or HID report descriptor have different
     73 *                size than expected.
     74 * @retval ENOMEM if some allocation failed.
     75 * @return Other value inherited from function usb_request_get_descriptor().
     76 *
     77 * @sa usb_request_get_descriptor()
     78 */
    5679static int usbhid_dev_get_report_descriptor(usbhid_dev_t *hid_dev,
    5780    uint8_t *config_desc, size_t config_desc_size, uint8_t *iface_desc)
     
    141164
    142165/*----------------------------------------------------------------------------*/
    143 
     166/**
     167 * Retreives descriptors from the device, initializes pipes and stores
     168 * important information from descriptors.
     169 *
     170 * Initializes the polling pipe described by the given endpoint description
     171 * (@a poll_ep_desc).
     172 *
     173 * Information retreived from descriptors and stored in the HID device structure:
     174 *    - Assigned interface number (the interface controlled by this instance of
     175 *                                 the driver)
     176 *    - Polling interval (from the interface descriptor)
     177 *    - Report descriptor
     178 *
     179 * @param hid_dev HID device structure to be initialized.
     180 * @param poll_ep_desc Description of the polling (Interrupt In) endpoint
     181 *                     that has to be present in the device in order to
     182 *                     successfuly initialize the structure.
     183 *
     184 * @sa usb_endpoint_pipe_initialize_from_configuration(),
     185 *     usbhid_dev_get_report_descriptor()
     186 */
    144187static int usbhid_dev_process_descriptors(usbhid_dev_t *hid_dev,
    145188    usb_endpoint_description_t *poll_ep_desc)
     
    230273/* API functions                                                              */
    231274/*----------------------------------------------------------------------------*/
    232 
     275/**
     276 * Creates new uninitialized HID device structure.
     277 *
     278 * @return Pointer to the new HID device structure, or NULL if an error occured.
     279 */
    233280usbhid_dev_t *usbhid_dev_new(void)
    234281{
     
    249296
    250297/*----------------------------------------------------------------------------*/
    251 
     298/**
     299 * Properly destroys the HID device structure.
     300 *
     301 * @note Currently does not clean-up the used pipes, as there are no functions
     302 *       offering such functionality.
     303 *
     304 * @param hid_dev Pointer to the structure to be destroyed.
     305 */
    252306void usbhid_dev_free(usbhid_dev_t **hid_dev)
    253307{
     
    272326
    273327/*----------------------------------------------------------------------------*/
    274 
     328/**
     329 * Initializes HID device structure.
     330 *
     331 * @param hid_dev HID device structure to be initialized.
     332 * @param dev DDF device representing the HID device.
     333 * @param poll_ep_desc Description of the polling (Interrupt In) endpoint
     334 *                     that has to be present in the device in order to
     335 *                     successfuly initialize the structure.
     336 *
     337 * @retval EOK if successful.
     338 * @retval EINVAL if some argument is missing.
     339 * @return Other value inherited from one of functions
     340 *         usb_device_connection_initialize_from_device(),
     341 *         usb_endpoint_pipe_initialize_default_control(),
     342 *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
     343 *         usbhid_dev_process_descriptors().
     344 *
     345 * @sa usbhid_dev_process_descriptors()
     346 */
    275347int usbhid_dev_init(usbhid_dev_t *hid_dev, ddf_dev_t *dev,
    276348    usb_endpoint_description_t *poll_ep_desc)
     
    319391                return rc;
    320392        }
     393        rc = usb_endpoint_pipe_probe_default_control(&hid_dev->ctrl_pipe);
     394        if (rc != EOK) {
     395                usb_log_error("Probing default control pipe failed: %s.\n",
     396                    str_error(rc));
     397                return rc;
     398        }
    321399
    322400        /*
    323401         * Get descriptors, parse descriptors and save endpoints.
    324402         */
    325         usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
     403        rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
     404        if (rc != EOK) {
     405                usb_log_error("Failed to start session on the control pipe: %s"
     406                    ".\n", str_error(rc));
     407                return rc;
     408        }
    326409       
    327410        rc = usbhid_dev_process_descriptors(hid_dev, poll_ep_desc);
    328        
    329         usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
    330         if (rc != EOK) {
     411        if (rc != EOK) {
     412                /* TODO: end session?? */
    331413                usb_log_error("Failed to process descriptors: %s.\n",
    332414                    str_error(rc));
     
    334416        }
    335417       
     418        rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
     419        if (rc != EOK) {
     420                usb_log_warning("Failed to start session on the control pipe: "
     421                    "%s.\n", str_error(rc));
     422                return rc;
     423        }
     424       
    336425        hid_dev->initialized = 1;
    337426        usb_log_info("HID device structure initialized.\n");
  • uspace/drv/usbhid/hiddev.h

    r3e7b7cd r72af8da  
    4848
    4949/**
    50  * @brief USB/HID device type.
     50 * USB/HID device type.
     51 *
     52 * Holds a reference to DDF device structure, and HID-specific data, such
     53 * as information about used pipes (one Control pipe and one Interrupt In pipe),
     54 * polling interval, assigned interface number, Report descriptor and a
     55 * reference to the Report parser used to parse incoming reports and composing
     56 * outgoing reports.
    5157 */
    5258typedef struct {
     59        /** DDF device representing the controlled HID device. */
    5360        ddf_dev_t *device;
    5461
     62        /** Physical connection to the device. */
    5563        usb_device_connection_t wire;
     64        /** USB pipe corresponding to the default Control endpoint. */
    5665        usb_endpoint_pipe_t ctrl_pipe;
     66        /** USB pipe corresponding to the Interrupt In (polling) pipe. */
    5767        usb_endpoint_pipe_t poll_pipe;
    5868       
     69        /** Polling interval retreived from the Interface descriptor. */
    5970        short poll_interval;
    6071       
     72        /** Interface number assigned to this device. */
    6173        uint16_t iface;
    6274       
     75        /** Report descriptor. */
    6376        uint8_t *report_desc;
     77        /** HID Report parser. */
    6478        usb_hid_report_parser_t *parser;
    6579       
     80        /** State of the structure (for checking before use). */
    6681        int initialized;
    6782} usbhid_dev_t;
  • uspace/drv/usbhid/hidreq.c

    r3e7b7cd r72af8da  
    4646
    4747/*----------------------------------------------------------------------------*/
    48 
     48/**
     49 * Send Set Report request to the HID device.
     50 *
     51 * @param hid_dev HID device to send the request to.
     52 * @param type Type of the report.
     53 * @param buffer Report data.
     54 * @param buf_size Report data size (in bytes).
     55 *
     56 * @retval EOK if successful.
     57 * @retval EINVAL if no HID device is given.
     58 * @return Other value inherited from one of functions
     59 *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
     60 *         usb_control_request_set().
     61 */
    4962int usbhid_req_set_report(usbhid_dev_t *hid_dev,
    5063    usb_hid_report_type_t type, uint8_t *buffer, size_t buf_size)
     
    6982                return sess_rc;
    7083        }
     84       
     85        uint16_t value = 0;
     86        value |= (type << 8);
    7187
    7288        usb_log_debug("Sending Set_Report request to the device.\n");
     
    7490        rc = usb_control_request_set(&hid_dev->ctrl_pipe,
    7591            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
    76             USB_HIDREQ_SET_REPORT, type, hid_dev->iface, buffer, buf_size);
    77 
    78         sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
    79 
    80         if (rc != EOK) {
    81                 usb_log_warning("Error sending output report to the keyboard: "
    82                     "%s.\n", str_error(rc));
    83                 return rc;
    84         }
    85 
    86         if (sess_rc != EOK) {
    87                 usb_log_warning("Error closing session: %s.\n",
    88                     str_error(sess_rc));
    89                 return sess_rc;
    90         }
    91        
    92         return EOK;
    93 }
    94 
    95 /*----------------------------------------------------------------------------*/
    96 
     92            USB_HIDREQ_SET_REPORT, value, hid_dev->iface, buffer, buf_size);
     93
     94        sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
     95
     96        if (rc != EOK) {
     97                usb_log_warning("Error sending output report to the keyboard: "
     98                    "%s.\n", str_error(rc));
     99                return rc;
     100        }
     101
     102        if (sess_rc != EOK) {
     103                usb_log_warning("Error closing session: %s.\n",
     104                    str_error(sess_rc));
     105                return sess_rc;
     106        }
     107       
     108        return EOK;
     109}
     110
     111/*----------------------------------------------------------------------------*/
     112/**
     113 * Send Set Protocol request to the HID device.
     114 *
     115 * @param hid_dev HID device to send the request to.
     116 * @param protocol Protocol to set.
     117 *
     118 * @retval EOK if successful.
     119 * @retval EINVAL if no HID device is given.
     120 * @return Other value inherited from one of functions
     121 *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
     122 *         usb_control_request_set().
     123 */
    97124int usbhid_req_set_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t protocol)
    98125{
     
    142169
    143170/*----------------------------------------------------------------------------*/
     171/**
     172 * Send Set Idle request to the HID device.
     173 *
     174 * @param hid_dev HID device to send the request to.
     175 * @param duration Duration value (is multiplicated by 4 by the device to
     176 *                 get real duration in miliseconds).
     177 *
     178 * @retval EOK if successful.
     179 * @retval EINVAL if no HID device is given.
     180 * @return Other value inherited from one of functions
     181 *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
     182 *         usb_control_request_set().
     183 */
     184int usbhid_req_set_idle(usbhid_dev_t *hid_dev, uint8_t duration)
     185{
     186        if (hid_dev == NULL) {
     187                usb_log_error("usbhid_req_set_idle(): no HID device "
     188                    "structure given.\n");
     189                return EINVAL;
     190        }
     191       
     192        /*
     193         * No need for checking other parameters, as they are checked in
     194         * the called function (usb_control_request_set()).
     195         */
     196       
     197        int rc, sess_rc;
     198       
     199        sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
     200        if (sess_rc != EOK) {
     201                usb_log_warning("Failed to start a session: %s.\n",
     202                    str_error(sess_rc));
     203                return sess_rc;
     204        }
     205
     206        usb_log_debug("Sending Set_Idle request to the device ("
     207            "duration: %u, iface: %d).\n", duration, hid_dev->iface);
     208       
     209        uint16_t value = duration << 8;
     210       
     211        rc = usb_control_request_set(&hid_dev->ctrl_pipe,
     212            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
     213            USB_HIDREQ_SET_IDLE, value, hid_dev->iface, NULL, 0);
     214
     215        sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
     216
     217        if (rc != EOK) {
     218                usb_log_warning("Error sending output report to the keyboard: "
     219                    "%s.\n", str_error(rc));
     220                return rc;
     221        }
     222
     223        if (sess_rc != EOK) {
     224                usb_log_warning("Error closing session: %s.\n",
     225                    str_error(sess_rc));
     226                return sess_rc;
     227        }
     228       
     229        return EOK;
     230}
     231
     232/*----------------------------------------------------------------------------*/
     233/**
     234 * Send Get Report request to the HID device.
     235 *
     236 * @param[in] hid_dev HID device to send the request to.
     237 * @param[in] type Type of the report.
     238 * @param[in][out] buffer Buffer for the report data.
     239 * @param[in] buf_size Size of the buffer (in bytes).
     240 * @param[out] actual_size Actual size of report received from the device
     241 *                         (in bytes).
     242 *
     243 * @retval EOK if successful.
     244 * @retval EINVAL if no HID device is given.
     245 * @return Other value inherited from one of functions
     246 *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
     247 *         usb_control_request_set().
     248 */
     249int usbhid_req_get_report(usbhid_dev_t *hid_dev, usb_hid_report_type_t type,
     250    uint8_t *buffer, size_t buf_size, size_t *actual_size)
     251{
     252        if (hid_dev == NULL) {
     253                usb_log_error("usbhid_req_set_report(): no HID device structure"
     254                    " given.\n");
     255                return EINVAL;
     256        }
     257       
     258        /*
     259         * No need for checking other parameters, as they are checked in
     260         * the called function (usb_control_request_set()).
     261         */
     262       
     263        int rc, sess_rc;
     264       
     265        sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
     266        if (sess_rc != EOK) {
     267                usb_log_warning("Failed to start a session: %s.\n",
     268                    str_error(sess_rc));
     269                return sess_rc;
     270        }
     271
     272        uint16_t value = 0;
     273        value |= (type << 8);
     274       
     275        usb_log_debug("Sending Get_Report request to the device.\n");
     276       
     277        rc = usb_control_request_get(&hid_dev->ctrl_pipe,
     278            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
     279            USB_HIDREQ_GET_REPORT, value, hid_dev->iface, buffer, buf_size,
     280            actual_size);
     281
     282        sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
     283
     284        if (rc != EOK) {
     285                usb_log_warning("Error sending output report to the keyboard: "
     286                    "%s.\n", str_error(rc));
     287                return rc;
     288        }
     289
     290        if (sess_rc != EOK) {
     291                usb_log_warning("Error closing session: %s.\n",
     292                    str_error(sess_rc));
     293                return sess_rc;
     294        }
     295       
     296        return EOK;
     297}
     298
     299/*----------------------------------------------------------------------------*/
     300/**
     301 * Send Get Protocol request to the HID device.
     302 *
     303 * @param[in] hid_dev HID device to send the request to.
     304 * @param[out] protocol Current protocol of the device.
     305 *
     306 * @retval EOK if successful.
     307 * @retval EINVAL if no HID device is given.
     308 * @return Other value inherited from one of functions
     309 *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
     310 *         usb_control_request_set().
     311 */
     312int usbhid_req_get_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t *protocol)
     313{
     314        if (hid_dev == NULL) {
     315                usb_log_error("usbhid_req_set_protocol(): no HID device "
     316                    "structure given.\n");
     317                return EINVAL;
     318        }
     319       
     320        /*
     321         * No need for checking other parameters, as they are checked in
     322         * the called function (usb_control_request_set()).
     323         */
     324       
     325        int rc, sess_rc;
     326       
     327        sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
     328        if (sess_rc != EOK) {
     329                usb_log_warning("Failed to start a session: %s.\n",
     330                    str_error(sess_rc));
     331                return sess_rc;
     332        }
     333
     334        usb_log_debug("Sending Get_Protocol request to the device ("
     335            "iface: %d).\n", hid_dev->iface);
     336       
     337        uint8_t buffer[1];
     338        size_t actual_size = 0;
     339       
     340        rc = usb_control_request_get(&hid_dev->ctrl_pipe,
     341            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
     342            USB_HIDREQ_GET_PROTOCOL, 0, hid_dev->iface, buffer, 1, &actual_size);
     343
     344        sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
     345
     346        if (rc != EOK) {
     347                usb_log_warning("Error sending output report to the keyboard: "
     348                    "%s.\n", str_error(rc));
     349                return rc;
     350        }
     351
     352        if (sess_rc != EOK) {
     353                usb_log_warning("Error closing session: %s.\n",
     354                    str_error(sess_rc));
     355                return sess_rc;
     356        }
     357       
     358        if (actual_size != 1) {
     359                usb_log_warning("Wrong data size: %zu, expected: 1.\n",
     360                        actual_size);
     361                return ELIMIT;
     362        }
     363       
     364        *protocol = buffer[0];
     365       
     366        return EOK;
     367}
     368
     369/*----------------------------------------------------------------------------*/
     370/**
     371 * Send Get Idle request to the HID device.
     372 *
     373 * @param[in] hid_dev HID device to send the request to.
     374 * @param[out] duration Duration value (multiplicate by 4 to get real duration
     375 *                      in miliseconds).
     376 *
     377 * @retval EOK if successful.
     378 * @retval EINVAL if no HID device is given.
     379 * @return Other value inherited from one of functions
     380 *         usb_endpoint_pipe_start_session(), usb_endpoint_pipe_end_session(),
     381 *         usb_control_request_set().
     382 */
     383int usbhid_req_get_idle(usbhid_dev_t *hid_dev, uint8_t *duration)
     384{
     385        if (hid_dev == NULL) {
     386                usb_log_error("usbhid_req_set_idle(): no HID device "
     387                    "structure given.\n");
     388                return EINVAL;
     389        }
     390       
     391        /*
     392         * No need for checking other parameters, as they are checked in
     393         * the called function (usb_control_request_set()).
     394         */
     395       
     396        int rc, sess_rc;
     397       
     398        sess_rc = usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
     399        if (sess_rc != EOK) {
     400                usb_log_warning("Failed to start a session: %s.\n",
     401                    str_error(sess_rc));
     402                return sess_rc;
     403        }
     404
     405        usb_log_debug("Sending Get_Idle request to the device ("
     406            "iface: %d).\n", hid_dev->iface);
     407       
     408        uint16_t value = 0;
     409        uint8_t buffer[1];
     410        size_t actual_size = 0;
     411       
     412        rc = usb_control_request_get(&hid_dev->ctrl_pipe,
     413            USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
     414            USB_HIDREQ_GET_IDLE, value, hid_dev->iface, buffer, 1,
     415            &actual_size);
     416
     417        sess_rc = usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
     418
     419        if (rc != EOK) {
     420                usb_log_warning("Error sending output report to the keyboard: "
     421                    "%s.\n", str_error(rc));
     422                return rc;
     423        }
     424
     425        if (sess_rc != EOK) {
     426                usb_log_warning("Error closing session: %s.\n",
     427                    str_error(sess_rc));
     428                return sess_rc;
     429        }
     430       
     431        if (actual_size != 1) {
     432                usb_log_warning("Wrong data size: %zu, expected: 1.\n",
     433                        actual_size);
     434                return ELIMIT;
     435        }
     436       
     437        *duration = buffer[0];
     438       
     439        return EOK;
     440}
     441
     442/*----------------------------------------------------------------------------*/
    144443
    145444/**
  • uspace/drv/usbhid/hidreq.h

    r3e7b7cd r72af8da  
    5050int usbhid_req_set_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t protocol);
    5151
     52int usbhid_req_set_idle(usbhid_dev_t *hid_dev, uint8_t duration);
     53
     54int usbhid_req_get_report(usbhid_dev_t *hid_dev, usb_hid_report_type_t type,
     55    uint8_t *buffer, size_t buf_size, size_t *actual_size);
     56
     57int usbhid_req_get_protocol(usbhid_dev_t *hid_dev, usb_hid_protocol_t *protocol);
     58
     59int usbhid_req_get_idle(usbhid_dev_t *hid_dev, uint8_t *duration);
     60
    5261/*----------------------------------------------------------------------------*/
    5362
  • uspace/drv/usbhid/kbddev.c

    r3e7b7cd r72af8da  
    3737#include <errno.h>
    3838#include <str_error.h>
    39 #include <fibril.h>
     39#include <stdio.h>
    4040
    4141#include <io/keycode.h>
    4242#include <ipc/kbd.h>
    4343#include <async.h>
     44#include <fibril.h>
     45#include <fibril_synch.h>
    4446
    4547#include <usb/usb.h>
     
    5557#include "layout.h"
    5658#include "conv.h"
    57 
    58 /*----------------------------------------------------------------------------*/
    59 
     59#include "kbdrepeat.h"
     60
     61/*----------------------------------------------------------------------------*/
     62/** Default modifiers when the keyboard is initialized. */
    6063static const unsigned DEFAULT_ACTIVE_MODS = KM_NUM_LOCK;
     64
     65/** Boot protocol report size (key part). */
    6166static const size_t BOOTP_REPORT_SIZE = 6;
     67
     68/** Boot protocol total report size. */
    6269static const size_t BOOTP_BUFFER_SIZE = 8;
     70
     71/** Boot protocol output report size. */
    6372static const size_t BOOTP_BUFFER_OUT_SIZE = 1;
     73
     74/** Boot protocol error key code. */
     75static const uint8_t BOOTP_ERROR_ROLLOVER = 1;
     76
     77/** Default idle rate for keyboards. */
     78static const uint8_t IDLE_RATE = 0;
     79
     80/** Delay before a pressed key starts auto-repeating. */
     81static const unsigned int DEFAULT_DELAY_BEFORE_FIRST_REPEAT = 500 * 1000;
     82
     83/** Delay between two repeats of a pressed key when auto-repeating. */
     84static const unsigned int DEFAULT_REPEAT_DELAY = 50 * 1000;
    6485
    6586/** Keyboard polling endpoint description for boot protocol class. */
     
    79100#define NUM_LAYOUTS 3
    80101
     102/** Keyboard layout map. */
    81103static layout_op_t *layout[NUM_LAYOUTS] = {
    82104        &us_qwerty_op,
     
    90112/* Modifier constants                                                         */
    91113/*----------------------------------------------------------------------------*/
    92 
     114/** Mapping of USB modifier key codes to generic modifier key codes. */
    93115static const keycode_t usbhid_modifiers_keycodes[USB_HID_MOD_COUNT] = {
    94116        KC_LCTRL,         /* USB_HID_MOD_LCTRL */
     
    111133};
    112134
    113 /** Default handler for IPC methods not handled by DDF.
    114  *
    115  * @param dev Device handling the call.
     135/**
     136 * Default handler for IPC methods not handled by DDF.
     137 *
     138 * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it
     139 * assumes the caller is the console and thus it stores IPC phone to it for
     140 * later use by the driver to notify about key events.
     141 *
     142 * @param fun Device function handling the call.
    116143 * @param icallid Call id.
    117144 * @param icall Call data.
     
    144171/* Key processing functions                                                   */
    145172/*----------------------------------------------------------------------------*/
    146 
     173/**
     174 * Handles turning of LED lights on and off.
     175 *
     176 * In case of USB keyboards, the LEDs are handled in the driver, not in the
     177 * device. When there should be a change (lock key was pressed), the driver
     178 * uses a Set_Report request sent to the device to set the state of the LEDs.
     179 *
     180 * This functions sets the LED lights according to current settings of modifiers
     181 * kept in the keyboard device structure.
     182 *
     183 * @param kbd_dev Keyboard device structure.
     184 */
    147185static void usbhid_kbd_set_led(usbhid_kbd_t *kbd_dev)
    148186{
    149187        uint8_t buffer[BOOTP_BUFFER_OUT_SIZE];
    150188        int rc= 0;
    151         unsigned i;
    152189       
    153190        memset(buffer, 0, BOOTP_BUFFER_OUT_SIZE);
     
    177214        }
    178215       
    179         // TODO: REFACTOR!!!
    180        
    181         usb_log_debug("Output report buffer: ");
    182         for (i = 0; i < BOOTP_BUFFER_OUT_SIZE; ++i) {
    183                 usb_log_debug("0x%x ", buffer[i]);
    184         }
    185         usb_log_debug("\n");
    186        
    187         uint16_t value = 0;
    188         value |= (USB_HID_REPORT_TYPE_OUTPUT << 8);
    189 
     216        usb_log_debug("Output report buffer: %s\n",
     217            usb_debug_str_buffer(buffer, BOOTP_BUFFER_OUT_SIZE, 0));
     218       
    190219        assert(kbd_dev->hid_dev != NULL);
    191220        assert(kbd_dev->hid_dev->initialized);
    192         usbhid_req_set_report(kbd_dev->hid_dev, value, buffer,
    193             BOOTP_BUFFER_OUT_SIZE);
    194 }
    195 
    196 /*----------------------------------------------------------------------------*/
    197 
    198 static void usbhid_kbd_push_ev(usbhid_kbd_t *kbd_dev, int type,
    199     unsigned int key)
     221        usbhid_req_set_report(kbd_dev->hid_dev, USB_HID_REPORT_TYPE_OUTPUT,
     222            buffer, BOOTP_BUFFER_OUT_SIZE);
     223}
     224
     225/*----------------------------------------------------------------------------*/
     226/**
     227 * Processes key events.
     228 *
     229 * @note This function was copied from AT keyboard driver and modified to suit
     230 *       USB keyboard.
     231 *
     232 * @note Lock keys are not sent to the console, as they are completely handled
     233 *       in the driver. It may, however, be required later that the driver
     234 *       sends also these keys to application (otherwise it cannot use those
     235 *       keys at all).
     236 *
     237 * @param kbd_dev Keyboard device structure.
     238 * @param type Type of the event (press / release). Recognized values:
     239 *             KEY_PRESS, KEY_RELEASE
     240 * @param key Key code of the key according to HID Usage Tables.
     241 */
     242void usbhid_kbd_push_ev(usbhid_kbd_t *kbd_dev, int type, unsigned int key)
    200243{
    201244        console_event_t ev;
    202245        unsigned mod_mask;
    203246
    204         // TODO: replace by our own parsing?? or are the key codes identical??
     247        /*
     248         * These parts are copy-pasted from the AT keyboard driver.
     249         *
     250         * They definitely require some refactoring, but will keep it for later
     251         * when the console and keyboard system is changed in HelenOS.
     252         */
    205253        switch (key) {
    206254        case KC_LCTRL: mod_mask = KM_LCTRL; break;
     
    228276
    229277        if (mod_mask != 0) {
    230                 usb_log_debug2("\n\nChanging mods and lock keys\n");
    231                 usb_log_debug2("\nmods before: 0x%x\n", kbd_dev->mods);
    232                 usb_log_debug2("\nLock keys before:0x%x\n\n",
    233                     kbd_dev->lock_keys);
    234                
    235278                if (type == KEY_PRESS) {
    236                         usb_log_debug2("\nKey pressed.\n");
    237279                        /*
    238280                         * Only change lock state on transition from released
     
    240282                         * up the lock state.
    241283                         */
     284                        unsigned int locks_old = kbd_dev->lock_keys;
     285                       
    242286                        kbd_dev->mods =
    243287                            kbd_dev->mods ^ (mod_mask & ~kbd_dev->lock_keys);
     
    245289
    246290                        /* Update keyboard lock indicator lights. */
    247                         usbhid_kbd_set_led(kbd_dev);
     291                        if (kbd_dev->lock_keys != locks_old) {
     292                                usbhid_kbd_set_led(kbd_dev);
     293                        }
    248294                } else {
    249                         usb_log_debug2("\nKey released.\n");
    250295                        kbd_dev->lock_keys = kbd_dev->lock_keys & ~mod_mask;
    251296                }
    252297        }
    253298
    254         usb_log_debug2("\n\nmods after: 0x%x\n", kbd_dev->mods);
    255         usb_log_debug2("\nLock keys after: 0x%x\n\n", kbd_dev->lock_keys);
    256        
    257299        if (key == KC_CAPS_LOCK || key == KC_NUM_LOCK || key == KC_SCROLL_LOCK) {
    258300                // do not send anything to the console, this is our business
     
    281323        ev.key = key;
    282324        ev.mods = kbd_dev->mods;
    283        
    284         if (ev.mods & KM_NUM_LOCK) {
    285                 usb_log_debug("\n\nNum Lock turned on.\n\n");
    286         }
    287325
    288326        ev.c = layout[active_layout]->parse_ev(&ev);
     
    300338
    301339/*----------------------------------------------------------------------------*/
    302 
     340/**
     341 * Checks if modifiers were pressed or released and generates key events.
     342 *
     343 * @param kbd_dev Keyboard device structure.
     344 * @param modifiers Bitmap of modifiers.
     345 *
     346 * @sa usbhid_kbd_push_ev()
     347 */
    303348static void usbhid_kbd_check_modifier_changes(usbhid_kbd_t *kbd_dev,
    304349    uint8_t modifiers)
     
    336381
    337382/*----------------------------------------------------------------------------*/
    338 
     383/**
     384 * Checks if some keys were pressed or released and generates key events.
     385 *
     386 * An event is created only when key is pressed or released. Besides handling
     387 * the events (usbhid_kbd_push_ev()), the auto-repeat fibril is notified about
     388 * key presses and releases (see usbhid_kbd_repeat_start() and
     389 * usbhid_kbd_repeat_stop()).
     390 *
     391 * @param kbd_dev Keyboard device structure.
     392 * @param key_codes Parsed keyboard report - codes of currently pressed keys
     393 *                  according to HID Usage Tables.
     394 * @param count Number of key codes in report (size of the report).
     395 *
     396 * @sa usbhid_kbd_push_ev(), usbhid_kbd_repeat_start(), usbhid_kbd_repeat_stop()
     397 */
    339398static void usbhid_kbd_check_key_changes(usbhid_kbd_t *kbd_dev,
    340     const uint8_t *key_codes)
    341 {
    342         // TODO: phantom state!!
    343        
     399    const uint8_t *key_codes, size_t count)
     400{
    344401        unsigned int key;
    345402        unsigned int i, j;
    346403       
    347         // TODO: quite dummy right now, think of better implementation
     404        /*
     405         * First of all, check if the kbd have reported phantom state.
     406         */
     407        i = 0;
     408        // all fields should report Error Rollover
     409        while (i < count &&
     410            key_codes[i] == BOOTP_ERROR_ROLLOVER) {
     411                ++i;
     412        }
     413        if (i == count) {
     414                usb_log_debug("Phantom state occured.\n");
     415                // phantom state, do nothing
     416                return;
     417        }
     418       
     419        /* TODO: quite dummy right now, think of better implementation */
     420        assert(count == kbd_dev->key_count);
    348421       
    349422        /*
    350423         * 1) Key releases
    351424         */
    352         for (j = 0; j < kbd_dev->keycode_count; ++j) {
     425        for (j = 0; j < count; ++j) {
    353426                // try to find the old key in the new key list
    354427                i = 0;
    355                 while (i < kbd_dev->keycode_count
    356                     && key_codes[i] != kbd_dev->keycodes[j]) {
     428                while (i < kbd_dev->key_count
     429                    && key_codes[i] != kbd_dev->keys[j]) {
    357430                        ++i;
    358431                }
    359432               
    360                 if (i == kbd_dev->keycode_count) {
     433                if (i == count) {
    361434                        // not found, i.e. the key was released
    362                         key = usbhid_parse_scancode(kbd_dev->keycodes[j]);
     435                        key = usbhid_parse_scancode(kbd_dev->keys[j]);
     436                        usbhid_kbd_repeat_stop(kbd_dev, key);
    363437                        usbhid_kbd_push_ev(kbd_dev, KEY_RELEASE, key);
    364                         usb_log_debug2("\nKey released: %d\n", key);
     438                        usb_log_debug2("Key released: %d\n", key);
    365439                } else {
    366440                        // found, nothing happens
     
    371445         * 1) Key presses
    372446         */
    373         for (i = 0; i < kbd_dev->keycode_count; ++i) {
     447        for (i = 0; i < kbd_dev->key_count; ++i) {
    374448                // try to find the new key in the old key list
    375449                j = 0;
    376                 while (j < kbd_dev->keycode_count
    377                     && kbd_dev->keycodes[j] != key_codes[i]) {
     450                while (j < count && kbd_dev->keys[j] != key_codes[i]) {
    378451                        ++j;
    379452                }
    380453               
    381                 if (j == kbd_dev->keycode_count) {
     454                if (j == count) {
    382455                        // not found, i.e. new key pressed
    383456                        key = usbhid_parse_scancode(key_codes[i]);
    384                         usb_log_debug2("\nKey pressed: %d (keycode: %d)\n", key,
     457                        usb_log_debug2("Key pressed: %d (keycode: %d)\n", key,
    385458                            key_codes[i]);
    386459                        usbhid_kbd_push_ev(kbd_dev, KEY_PRESS, key);
     460                        usbhid_kbd_repeat_start(kbd_dev, key);
    387461                } else {
    388462                        // found, nothing happens
     
    390464        }
    391465       
    392         memcpy(kbd_dev->keycodes, key_codes, kbd_dev->keycode_count);
    393        
    394         usb_log_debug2("\nNew stored keycodes: ");
    395         for (i = 0; i < kbd_dev->keycode_count; ++i) {
    396                 usb_log_debug2("%d ", kbd_dev->keycodes[i]);
    397         }
     466        memcpy(kbd_dev->keys, key_codes, count);
     467
     468        usb_log_debug("New stored keycodes: %s\n",
     469            usb_debug_str_buffer(kbd_dev->keys, kbd_dev->key_count, 0));
    398470}
    399471
     
    401473/* Callbacks for parser                                                       */
    402474/*----------------------------------------------------------------------------*/
    403 
     475/**
     476 * Callback function for the HID report parser.
     477 *
     478 * This function is called by the HID report parser with the parsed report.
     479 * The parsed report is used to check if any events occured (key was pressed or
     480 * released, modifier was pressed or released).
     481 *
     482 * @param key_codes Parsed keyboard report - codes of currently pressed keys
     483 *                  according to HID Usage Tables.
     484 * @param count Number of key codes in report (size of the report).
     485 * @param modifiers Bitmap of modifiers (Ctrl, Alt, Shift, GUI).
     486 * @param arg User-specified argument. Expects pointer to the keyboard device
     487 *            structure representing the keyboard.
     488 *
     489 * @sa usbhid_kbd_check_key_changes(), usbhid_kbd_check_modifier_changes()
     490 */
    404491static void usbhid_kbd_process_keycodes(const uint8_t *key_codes, size_t count,
    405492    uint8_t modifiers, void *arg)
     
    410497                return;
    411498        }
    412 
    413         usb_log_debug2("Got keys from parser: ");
    414         unsigned i;
    415         for (i = 0; i < count; ++i) {
    416                 usb_log_debug2("%d ", key_codes[i]);
    417         }
    418         usb_log_debug2("\n");
    419499       
    420500        usbhid_kbd_t *kbd_dev = (usbhid_kbd_t *)arg;
    421501        assert(kbd_dev != NULL);
    422        
    423         if (count != kbd_dev->keycode_count) {
     502
     503        usb_log_debug("Got keys from parser: %s\n",
     504            usb_debug_str_buffer(key_codes, kbd_dev->key_count, 0));
     505       
     506        if (count != kbd_dev->key_count) {
    424507                usb_log_warning("Number of received keycodes (%d) differs from"
    425                     " expected number (%d).\n", count, kbd_dev->keycode_count);
     508                    " expected number (%d).\n", count, kbd_dev->key_count);
    426509                return;
    427510        }
    428511       
    429512        usbhid_kbd_check_modifier_changes(kbd_dev, modifiers);
    430         usbhid_kbd_check_key_changes(kbd_dev, key_codes);
     513        usbhid_kbd_check_key_changes(kbd_dev, key_codes, count);
    431514}
    432515
     
    434517/* General kbd functions                                                      */
    435518/*----------------------------------------------------------------------------*/
    436 
     519/**
     520 * Processes data received from the device in form of report.
     521 *
     522 * This function uses the HID report parser to translate the data received from
     523 * the device into generic USB HID key codes and into generic modifiers bitmap.
     524 * The parser then calls the given callback (usbhid_kbd_process_keycodes()).
     525 *
     526 * @note Currently, only the boot protocol is supported.
     527 *
     528 * @param kbd_dev Keyboard device structure (must be initialized).
     529 * @param buffer Data from the keyboard (i.e. the report).
     530 * @param actual_size Size of the data from keyboard (report size) in bytes.
     531 *
     532 * @sa usbhid_kbd_process_keycodes(), usb_hid_boot_keyboard_input_report().
     533 */
    437534static void usbhid_kbd_process_data(usbhid_kbd_t *kbd_dev,
    438535                                    uint8_t *buffer, size_t actual_size)
     
    444541        callbacks->keyboard = usbhid_kbd_process_keycodes;
    445542
    446         //usb_hid_parse_report(kbd_dev->parser, buffer, actual_size, callbacks,
    447         //    NULL);
    448         /*usb_log_debug2("Calling usb_hid_boot_keyboard_input_report() with size"
    449             " %zu\n", actual_size);*/
    450         //dump_buffer("bufffer: ", buffer, actual_size);
     543        usb_log_debug("Calling usb_hid_boot_keyboard_input_report() with "
     544            "buffer %s\n", usb_debug_str_buffer(buffer, actual_size, 0));
    451545       
    452546        int rc = usb_hid_boot_keyboard_input_report(buffer, actual_size,
     
    462556/* HID/KBD structure manipulation                                             */
    463557/*----------------------------------------------------------------------------*/
    464 
     558/**
     559 * Creates a new USB/HID keyboard structure.
     560 *
     561 * The structure returned by this function is not initialized. Use
     562 * usbhid_kbd_init() to initialize it prior to polling.
     563 *
     564 * @return New uninitialized structure for representing a USB/HID keyboard or
     565 *         NULL if not successful (memory error).
     566 */
    465567static usbhid_kbd_t *usbhid_kbd_new(void)
    466568{
     
    488590
    489591/*----------------------------------------------------------------------------*/
    490 
     592/**
     593 * Properly destroys the USB/HID keyboard structure.
     594 *
     595 * @param kbd_dev Pointer to the structure to be destroyed.
     596 */
    491597static void usbhid_kbd_free(usbhid_kbd_t **kbd_dev)
    492598{
     
    503609        }
    504610       
     611        if ((*kbd_dev)->repeat_mtx != NULL) {
     612                /* TODO: replace by some check and wait */
     613                assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
     614                free((*kbd_dev)->repeat_mtx);
     615        }
     616       
    505617        free(*kbd_dev);
    506618        *kbd_dev = NULL;
     
    508620
    509621/*----------------------------------------------------------------------------*/
    510 
     622/**
     623 * Initialization of the USB/HID keyboard structure.
     624 *
     625 * This functions initializes required structures from the device's descriptors.
     626 *
     627 * During initialization, the keyboard is switched into boot protocol, the idle
     628 * rate is set to 0 (infinity), resulting in the keyboard only reporting event
     629 * when a key is pressed or released. Finally, the LED lights are turned on
     630 * according to the default setup of lock keys.
     631 *
     632 * @note By default, the keyboards is initialized with Num Lock turned on and
     633 *       other locks turned off.
     634 *
     635 * @param kbd_dev Keyboard device structure to be initialized.
     636 * @param dev DDF device structure of the keyboard.
     637 *
     638 * @retval EOK if successful.
     639 * @retval EINVAL if some parameter is not given.
     640 * @return Other value inherited from function usbhid_dev_init().
     641 */
    511642static int usbhid_kbd_init(usbhid_kbd_t *kbd_dev, ddf_dev_t *dev)
    512643{
     
    543674       
    544675        // save the size of the report (boot protocol report by default)
    545         kbd_dev->keycode_count = BOOTP_REPORT_SIZE;
    546         kbd_dev->keycodes = (uint8_t *)calloc(
    547             kbd_dev->keycode_count, sizeof(uint8_t));
    548        
    549         if (kbd_dev->keycodes == NULL) {
     676        kbd_dev->key_count = BOOTP_REPORT_SIZE;
     677        kbd_dev->keys = (uint8_t *)calloc(
     678            kbd_dev->key_count, sizeof(uint8_t));
     679       
     680        if (kbd_dev->keys == NULL) {
    550681                usb_log_fatal("No memory!\n");
    551                 return rc;
     682                return ENOMEM;
    552683        }
    553684       
     
    556687        kbd_dev->lock_keys = 0;
    557688       
     689        kbd_dev->repeat.key_new = 0;
     690        kbd_dev->repeat.key_repeated = 0;
     691        kbd_dev->repeat.delay_before = DEFAULT_DELAY_BEFORE_FIRST_REPEAT;
     692        kbd_dev->repeat.delay_between = DEFAULT_REPEAT_DELAY;
     693       
     694        kbd_dev->repeat_mtx = (fibril_mutex_t *)(
     695            malloc(sizeof(fibril_mutex_t)));
     696        if (kbd_dev->repeat_mtx == NULL) {
     697                usb_log_fatal("No memory!\n");
     698                free(kbd_dev->keys);
     699                return ENOMEM;
     700        }
     701       
     702        fibril_mutex_initialize(kbd_dev->repeat_mtx);
     703       
    558704        /*
    559705         * Set boot protocol.
    560706         * Set LEDs according to initial setup.
     707         * Set Idle rate
    561708         */
    562709        assert(kbd_dev->hid_dev != NULL);
     
    566713        usbhid_kbd_set_led(kbd_dev);
    567714       
     715        usbhid_req_set_idle(kbd_dev->hid_dev, IDLE_RATE);
     716       
    568717        kbd_dev->initialized = 1;
    569718        usb_log_info("HID/KBD device structure initialized.\n");
     
    575724/* HID/KBD polling                                                            */
    576725/*----------------------------------------------------------------------------*/
    577 
     726/**
     727 * Main keyboard polling function.
     728 *
     729 * This function uses the Interrupt In pipe of the keyboard to poll for events.
     730 * The keyboard is initialized in a way that it reports only when a key is
     731 * pressed or released, so there is no actual need for any sleeping between
     732 * polls (see usbhid_kbd_try_add_device() or usbhid_kbd_init()).
     733 *
     734 * @param kbd_dev Initialized keyboard structure representing the device to
     735 *                poll.
     736 *
     737 * @sa usbhid_kbd_process_data()
     738 */
    578739static void usbhid_kbd_poll(usbhid_kbd_t *kbd_dev)
    579740{
     
    598759                        usb_log_warning("Failed to start a session: %s.\n",
    599760                            str_error(sess_rc));
    600                         continue;
     761                        break;
    601762                }
    602763
     
    610771                        usb_log_warning("Error polling the keyboard: %s.\n",
    611772                            str_error(rc));
    612                         continue;
     773                        break;
    613774                }
    614775
     
    616777                        usb_log_warning("Error closing session: %s.\n",
    617778                            str_error(sess_rc));
    618                         continue;
     779                        break;
    619780                }
    620781
     
    634795                usbhid_kbd_process_data(kbd_dev, buffer, actual_size);
    635796               
    636                 async_usleep(kbd_dev->hid_dev->poll_interval);
    637         }
    638 
    639         // not reached
    640         assert(0);
    641 }
    642 
    643 /*----------------------------------------------------------------------------*/
    644 
     797                // disabled for now, no reason to sleep
     798                //async_usleep(kbd_dev->hid_dev->poll_interval);
     799        }
     800}
     801
     802/*----------------------------------------------------------------------------*/
     803/**
     804 * Function executed by the main driver fibril.
     805 *
     806 * Just starts polling the keyboard for events.
     807 *
     808 * @param arg Initialized keyboard device structure (of type usbhid_kbd_t)
     809 *            representing the device.
     810 *
     811 * @retval EOK if the fibril finished polling the device.
     812 * @retval EINVAL if no device was given in the argument.
     813 *
     814 * @sa usbhid_kbd_poll()
     815 *
     816 * @todo Change return value - only case when the fibril finishes is in case
     817 *       of some error, so the error should probably be propagated from function
     818 *       usbhid_kbd_poll() to here and up.
     819 */
    645820static int usbhid_kbd_fibril(void *arg)
    646821{
     
    664839/* API functions                                                              */
    665840/*----------------------------------------------------------------------------*/
    666 
     841/**
     842 * Function for adding a new device of type USB/HID/keyboard.
     843 *
     844 * This functions initializes required structures from the device's descriptors
     845 * and starts new fibril for polling the keyboard for events and another one for
     846 * handling auto-repeat of keys.
     847 *
     848 * During initialization, the keyboard is switched into boot protocol, the idle
     849 * rate is set to 0 (infinity), resulting in the keyboard only reporting event
     850 * when a key is pressed or released. Finally, the LED lights are turned on
     851 * according to the default setup of lock keys.
     852 *
     853 * @note By default, the keyboards is initialized with Num Lock turned on and
     854 *       other locks turned off.
     855 * @note Currently supports only boot-protocol keyboards.
     856 *
     857 * @param dev Device to add.
     858 *
     859 * @retval EOK if successful.
     860 * @retval ENOMEM if there
     861 * @return Other error code inherited from one of functions usbhid_kbd_init(),
     862 *         ddf_fun_bind() and ddf_fun_add_to_class().
     863 *
     864 * @sa usbhid_kbd_fibril(), usbhid_kbd_repeat_fibril()
     865 */
    667866int usbhid_kbd_try_add_device(ddf_dev_t *dev)
    668867{
     
    686885                    "structure.\n");
    687886                ddf_fun_destroy(kbd_fun);
    688                 return EINVAL;  // TODO: some other code??
     887                return ENOMEM;  // TODO: some other code??
    689888        }
    690889       
     
    735934        }
    736935        fibril_add_ready(fid);
     936       
     937        /*
     938         * Create new fibril for auto-repeat
     939         */
     940        fid = fibril_create(usbhid_kbd_repeat_fibril, kbd_dev);
     941        if (fid == 0) {
     942                usb_log_error("Failed to start fibril for KBD auto-repeat");
     943                return ENOMEM;
     944        }
     945        fibril_add_ready(fid);
    737946
    738947        (void)keyboard_ops;
  • uspace/drv/usbhid/kbddev.h

    r3e7b7cd r72af8da  
    3939#include <stdint.h>
    4040
     41#include <fibril_synch.h>
     42
    4143#include <usb/classes/hid.h>
    4244#include <ddf/driver.h>
     
    4648
    4749/*----------------------------------------------------------------------------*/
     50/**
     51 * Structure for keeping information needed for auto-repeat of keys.
     52 */
     53typedef struct {
     54        /** Last pressed key. */
     55        unsigned int key_new;
     56        /** Key to be repeated. */
     57        unsigned int key_repeated;
     58        /** Delay before first repeat in microseconds. */
     59        unsigned int delay_before;
     60        /** Delay between repeats in microseconds. */
     61        unsigned int delay_between;
     62} usbhid_kbd_repeat_t;
    4863
    4964/**
    50  * @brief USB/HID keyboard device type.
     65 * USB/HID keyboard device type.
     66 *
     67 * Holds a reference to generic USB/HID device structure and keyboard-specific
     68 * data, such as currently pressed keys, modifiers and lock keys.
     69 *
     70 * Also holds a IPC phone to the console (since there is now no other way to
     71 * communicate with it).
     72 *
     73 * @note Storing active lock keys in this structure results in their setting
     74 *       being device-specific.
    5175 */
    5276typedef struct {
     77        /** Structure holding generic USB/HID device information. */
    5378        usbhid_dev_t *hid_dev;
    5479       
    55         uint8_t *keycodes;
    56         size_t keycode_count;
     80        /** Currently pressed keys (not translated to key codes). */
     81        uint8_t *keys;
     82        /** Count of stored keys (i.e. number of keys in the report). */
     83        size_t key_count;
     84        /** Currently pressed modifiers (bitmap). */
    5785        uint8_t modifiers;
    5886       
     87        /** Currently active modifiers including locks. Sent to the console. */
    5988        unsigned mods;
     89       
     90        /** Currently active lock keys. */
    6091        unsigned lock_keys;
    6192       
     93        /** IPC phone to the console device (for sending key events). */
    6294        int console_phone;
    6395       
     96        /** Information for auto-repeat of keys. */
     97        usbhid_kbd_repeat_t repeat;