Changeset 159100a in mainline


Ignore:
Timestamp:
2011-07-13T22:19:26Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ef9460b
Parents:
3e5c48c9 (diff), 5d36062 (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 OHCI improvements and fixes.

Files:
22 edited

Legend:

Unmodified
Added
Removed
  • HelenOS.config

    r3e5c48c9 r159100a  
    573573! CONFIG_RUN_VIRTUAL_USB_HC (n/y)
    574574
    575 % Polling UHCI & OHCI (no interrupts)
    576 ! [PLATFORM=ia32|PLATFORM=amd64] CONFIG_USBHC_NO_INTERRUPTS (n/y)
    577 
     575% OHCI root hub port power switching
     576@ "no" All root hub ports are always powered.
     577@ "ganged" Root hub ports are all powered or all off.
     578@ "per_port" Powered status of every root hub port is independent.
     579![PLATFORM=ia32|PLATFORM=amd64] OHCI_POWER_SWITCH (choice)
  • defaults/amd64/Makefile.config

    r3e5c48c9 r159100a  
    6565CONFIG_MOUNT_DATA = n
    6666
     67# OHCI root hub power switch, ganged is enough
     68OHCI_POWER_SWITCH = ganged
  • defaults/ia32/Makefile.config

    r3e5c48c9 r159100a  
    7171CONFIG_MOUNT_DATA = n
    7272
     73# OHCI root hub power switch, ganged is enough
     74OHCI_POWER_SWITCH = ganged
  • uspace/drv/bus/usb/ohci/hc.c

    r3e5c48c9 r159100a  
    4646#define OHCI_USED_INTERRUPTS \
    4747    (I_SO | I_WDH | I_UE | I_RHSC)
    48 static int interrupt_emulator(hc_t *instance);
     48
     49static const irq_cmd_t ohci_irq_commands[] =
     50{
     51        { .cmd = CMD_MEM_READ_32, .dstarg = 1, .addr = NULL /*filled later*/ },
     52        { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS },
     53        { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 },
     54        { .cmd = CMD_MEM_WRITE_A_32, .srcarg = 1, .addr = NULL /*filled later*/ },
     55        { .cmd = CMD_ACCEPT },
     56};
     57
    4958static void hc_gain_control(hc_t *instance);
     59static void hc_start(hc_t *instance);
    5060static int hc_init_transfer_lists(hc_t *instance);
    5161static int hc_init_memory(hc_t *instance);
     62static int interrupt_emulator(hc_t *instance);
     63
     64/*----------------------------------------------------------------------------*/
     65/** Get number of commands used in IRQ code.
     66 * @return Number of commands.
     67 */
     68size_t hc_irq_cmd_count(void)
     69{
     70        return sizeof(ohci_irq_commands) / sizeof(irq_cmd_t);
     71}
     72/*----------------------------------------------------------------------------*/
     73/** Generate IRQ code commands.
     74 * @param[out] cmds Place to store the commands.
     75 * @param[in] cmd_size Size of the place (bytes).
     76 * @param[in] regs Physical address of device's registers.
     77 * @param[in] reg_size Size of the register area (bytes).
     78 *
     79 * @return Error code.
     80 */
     81int hc_get_irq_commands(
     82    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size)
     83{
     84        if (cmd_size < sizeof(ohci_irq_commands)
     85            || reg_size < sizeof(ohci_regs_t))
     86                return EOVERFLOW;
     87
     88        /* Create register mapping to use in IRQ handler.
     89         * This mapping should be present in kernel only.
     90         * Remove it from here when kernel knows how to create mappings
     91         * and accepts physical addresses in IRQ code.
     92         * TODO: remove */
     93        ohci_regs_t *registers;
     94        const int ret = pio_enable((void*)regs, reg_size, (void**)&registers);
     95        if (ret != EOK)
     96                return ret;
     97
     98        /* Some bogus access to force create mapping. DO NOT remove,
     99         * unless whole virtual addresses in irq is replaced
     100         * NOTE: Compiler won't remove this as ohci_regs_t members
     101         * are declared volatile.
     102         *
     103         * Introducing CMD_MEM set of IRQ code commands broke
     104         * assumption that IRQ code does not cause page faults.
     105         * If this happens during idling (THREAD == NULL)
     106         * it causes kernel panic.
     107         */
     108        registers->revision;
     109
     110        memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
     111
     112        void *address = (void*)&registers->interrupt_status;
     113        cmds[0].addr = address;
     114        cmds[3].addr = address;
     115        return EOK;
     116}
    52117/*----------------------------------------------------------------------------*/
    53118/** Announce OHCI root hub to the DDF
     
    83148        int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
    84149            USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
    85         CHECK_RET_RELEASE(ret, "Failed(%d) to add OHCI rh endpoint 0.\n", ret);
     150        CHECK_RET_RELEASE(ret,
     151            "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret));
    86152
    87153        char *match_str = NULL;
    88         /* DDF needs heap allocated string */
     154        /* DDF needs heap allocated string. */
    89155        ret = asprintf(&match_str, "usb&class=hub");
    90156        ret = ret > 0 ? 0 : ret;
    91         CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret);
     157        CHECK_RET_RELEASE(ret,
     158            "Failed to create match-id string: %s.\n", str_error(ret));
    92159
    93160        ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
    94         CHECK_RET_RELEASE(ret, "Failed(%d) add root hub match-id.\n", ret);
     161        CHECK_RET_RELEASE(ret,
     162            "Failed to add root hub match-id: %s.\n", str_error(ret));
    95163
    96164        ret = ddf_fun_bind(hub_fun);
    97         CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret);
     165        CHECK_RET_RELEASE(ret,
     166            "Failed to bind root hub function: %s.\n", str_error(ret));
    98167
    99168        return EOK;
     
    112181{
    113182        assert(instance);
    114         int ret = EOK;
     183
    115184#define CHECK_RET_RETURN(ret, message...) \
    116185if (ret != EOK) { \
     
    119188} else (void)0
    120189
    121         ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers);
     190        int ret =
     191            pio_enable((void*)regs, reg_size, (void**)&instance->registers);
    122192        CHECK_RET_RETURN(ret,
    123             "Failed(%d) to gain access to device registers: %s.\n",
    124             ret, str_error(ret));
     193            "Failed to gain access to device registers: %s.\n", str_error(ret));
    125194
    126195        list_initialize(&instance->pending_batches);
    127196        usb_device_keeper_init(&instance->manager);
     197
    128198        ret = usb_endpoint_manager_init(&instance->ep_manager,
    129199            BANDWIDTH_AVAILABLE_USB11);
     
    137207
    138208        fibril_mutex_initialize(&instance->guard);
     209
    139210        hc_gain_control(instance);
    140 
    141         rh_init(&instance->rh, instance->registers);
    142211
    143212        if (!interrupts) {
     
    147216        }
    148217
    149         return EOK;
    150 }
    151 /*----------------------------------------------------------------------------*/
    152 /** Create end register endpoint structures
     218        rh_init(&instance->rh, instance->registers);
     219        hc_start(instance);
     220
     221        return EOK;
     222}
     223/*----------------------------------------------------------------------------*/
     224/** Create and register endpoint structures.
    153225 *
    154226 * @param[in] instance OHCI driver structure.
     
    168240    size_t mps, size_t size, unsigned interval)
    169241{
    170         endpoint_t *ep = malloc(sizeof(endpoint_t));
     242        endpoint_t *ep =
     243            endpoint_get(address, endpoint, direction, type, speed, mps);
    171244        if (ep == NULL)
    172245                return ENOMEM;
    173         int ret =
    174             endpoint_init(ep, address, endpoint, direction, type, speed, mps);
    175         if (ret != EOK) {
    176                 free(ep);
    177                 return ret;
    178         }
    179246
    180247        hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
     
    184251        }
    185252
    186         ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
     253        int ret =
     254            usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
    187255        if (ret != EOK) {
    188256                hcd_endpoint_clear(ep);
     
    212280                    &instance->lists[ep->transfer_type], hcd_ep);
    213281                instance->registers->control |= C_PLE | C_IE;
    214                 break;
    215         default:
    216282                break;
    217283        }
     
    312378        /* Check for root hub communication */
    313379        if (batch->ep->address == instance->rh.address) {
    314                 return rh_request(&instance->rh, batch);
     380                rh_request(&instance->rh, batch);
     381                return EOK;
    315382        }
    316383
     
    374441
    375442        if (status & I_UE) {
    376                 hc_start_hw(instance);
     443                hc_start(instance);
    377444        }
    378445
     
    399466/** Turn off any (BIOS)driver that might be in control of the device.
    400467 *
     468 * This function implements routines described in chapter 5.1.1.3 of the OHCI
     469 * specification (page 40, pdf page 54).
     470 *
    401471 * @param[in] instance OHCI hc driver structure.
    402472 */
     
    404474{
    405475        assert(instance);
     476
    406477        usb_log_debug("Requesting OHCI control.\n");
    407         /* Turn off legacy emulation */
    408         volatile uint32_t *ohci_emulation_reg =
    409             (uint32_t*)((char*)instance->registers + 0x100);
    410         usb_log_debug("OHCI legacy register %p: %x.\n",
    411             ohci_emulation_reg, *ohci_emulation_reg);
    412         /* Do not change A20 state */
    413         *ohci_emulation_reg &= 0x100;
    414         usb_log_debug("OHCI legacy register %p: %x.\n",
    415             ohci_emulation_reg, *ohci_emulation_reg);
     478        if (instance->registers->revision & R_LEGACY_FLAG) {
     479                /* Turn off legacy emulation, it should be enough to zero
     480                 * the lowest bit, but it caused problems. Thus clear all
     481                 * except GateA20 (causes restart on some hw).
     482                 * See page 145 of the specs for details.
     483                 */
     484                volatile uint32_t *ohci_emulation_reg =
     485                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
     486                usb_log_debug("OHCI legacy register %p: %x.\n",
     487                    ohci_emulation_reg, *ohci_emulation_reg);
     488                /* Zero everything but A20State */
     489                *ohci_emulation_reg &= 0x100;
     490                usb_log_debug(
     491                    "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
     492                    ohci_emulation_reg, *ohci_emulation_reg);
     493        }
    416494
    417495        /* Interrupt routing enabled => smm driver is active */
     
    419497                usb_log_debug("SMM driver: request ownership change.\n");
    420498                instance->registers->command_status |= CS_OCR;
     499                /* Hope that SMM actually knows its stuff or we can hang here */
    421500                while (instance->registers->control & C_IR) {
    422501                        async_usleep(1000);
    423502                }
    424503                usb_log_info("SMM driver: Ownership taken.\n");
    425                 instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
     504                C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
    426505                async_usleep(50000);
    427506                return;
    428507        }
    429508
    430         const unsigned hc_status =
    431             (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
     509        const unsigned hc_status = C_HCFS_GET(instance->registers->control);
    432510        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    433511        if (hc_status != C_HCFS_RESET) {
     
    437515                        return;
    438516                }
    439                 /* HC is suspended assert resume for 20ms */
    440                 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
     517                /* HC is suspended assert resume for 20ms, */
     518                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    441519                async_usleep(20000);
    442520                usb_log_info("BIOS driver: HC resumed.\n");
     
    454532 * @param[in] instance OHCI hc driver structure.
    455533 */
    456 void hc_start_hw(hc_t *instance)
     534void hc_start(hc_t *instance)
    457535{
    458536        /* OHCI guide page 42 */
     
    516594            instance->registers->periodic_start, frame_length);
    517595
    518         instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
     596        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    519597        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
    520598            instance->registers->control);
     
    534612        int ret = endpoint_list_init(&instance->lists[type], name); \
    535613        if (ret != EOK) { \
    536                 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
    537                     ret, name); \
     614                usb_log_error("Failed to setup %s endpoint list: %s.\n", \
     615                    name, str_error(ret)); \
    538616                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
    539617                endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
     
    587665            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    588666
    589         /* Init interrupt code */
    590         instance->interrupt_code.cmds = instance->interrupt_commands;
    591         instance->interrupt_code.cmdcount = OHCI_NEEDED_IRQ_COMMANDS;
    592         {
    593                 /* Read status register */
    594                 instance->interrupt_commands[0].cmd = CMD_MEM_READ_32;
    595                 instance->interrupt_commands[0].dstarg = 1;
    596                 instance->interrupt_commands[0].addr =
    597                     (void*)&instance->registers->interrupt_status;
    598 
    599                 /* Test whether we are the interrupt cause */
    600                 instance->interrupt_commands[1].cmd = CMD_BTEST;
    601                 instance->interrupt_commands[1].value =
    602                     OHCI_USED_INTERRUPTS;
    603                 instance->interrupt_commands[1].srcarg = 1;
    604                 instance->interrupt_commands[1].dstarg = 2;
    605 
    606                 /* Predicate cleaning and accepting */
    607                 instance->interrupt_commands[2].cmd = CMD_PREDICATE;
    608                 instance->interrupt_commands[2].value = 2;
    609                 instance->interrupt_commands[2].srcarg = 2;
    610 
    611                 /* Write-clean status register */
    612                 instance->interrupt_commands[3].cmd = CMD_MEM_WRITE_A_32;
    613                 instance->interrupt_commands[3].srcarg = 1;
    614                 instance->interrupt_commands[3].addr =
    615                     (void*)&instance->registers->interrupt_status;
    616 
    617                 /* Accept interrupt */
    618                 instance->interrupt_commands[4].cmd = CMD_ACCEPT;
    619         }
    620 
    621         return EOK;
    622 }
     667        return EOK;
     668}
     669
    623670/**
    624671 * @}
  • uspace/drv/bus/usb/ohci/hc.h

    r3e5c48c9 r159100a  
    5151#include "hw_struct/hcca.h"
    5252
    53 #define OHCI_NEEDED_IRQ_COMMANDS 5
    54 
    55 /** Main OHCI drier structure */
     53/** Main OHCI driver structure */
    5654typedef struct hc {
    5755        /** USB bus driver, devices and addresses */
     
    7674        fibril_mutex_t guard;
    7775
    78         /** Code to be executed in kernel interrupt handler */
    79         irq_code_t interrupt_code;
    80 
    81         /** Commands that form interrupt code */
    82         irq_cmd_t interrupt_commands[OHCI_NEEDED_IRQ_COMMANDS];
    83 
    8476        /** USB hub emulation structure */
    8577        rh_t rh;
    8678} hc_t;
    8779
     80size_t hc_irq_cmd_count(void);
     81int hc_get_irq_commands(
     82    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size);
     83int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts);
    8884int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun);
    89 int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts);
    90 void hc_start_hw(hc_t *instance);
    9185
    9286/** Safely dispose host controller internal structures
  • uspace/drv/bus/usb/ohci/ohci.c

    r3e5c48c9 r159100a  
    5858{
    5959        assert(dev);
    60         assert(dev->driver_data);
    6160        return dev->driver_data;
    6261}
    63 
    6462/** IRQ handling callback, identifies device
    6563 *
     
    7068static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
    7169{
    72         hc_t *hc = &dev_to_ohci(dev)->hc;
    73         assert(hc);
     70        assert(dev);
     71
     72        ohci_t *ohci = dev_to_ohci(dev);
     73        if (!ohci) {
     74                usb_log_warning("Interrupt on device that is not ready.\n");
     75                return;
     76        }
    7477        const uint16_t status = IPC_GET_ARG1(*call);
    75         hc_interrupt(hc, status);
     78        hc_interrupt(&ohci->hc, status);
    7679}
    7780/*----------------------------------------------------------------------------*/
     
    166169        } \
    167170        free(instance); \
     171        device->driver_data = NULL; \
    168172        usb_log_error(message); \
    169173        return ret; \
     
    173177        instance->hc_fun = ddf_fun_create(device, fun_exposed, "ohci_hc");
    174178        int ret = instance->hc_fun ? EOK : ENOMEM;
    175         CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create OHCI HC function.\n");
     179        CHECK_RET_DEST_FREE_RETURN(ret,
     180            "Failed to create OHCI HC function: %s.\n", str_error(ret));
    176181        instance->hc_fun->ops = &hc_ops;
    177182        instance->hc_fun->driver_data = &instance->hc;
     
    179184        instance->rh_fun = ddf_fun_create(device, fun_inner, "ohci_rh");
    180185        ret = instance->rh_fun ? EOK : ENOMEM;
    181         CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create OHCI RH function.\n");
     186        CHECK_RET_DEST_FREE_RETURN(ret,
     187            "Failed to create OHCI RH function: %s.\n", str_error(ret));
    182188        instance->rh_fun->ops = &rh_ops;
    183189
     
    193199            (void *) reg_base, reg_size, irq);
    194200
     201        const size_t cmd_count = hc_irq_cmd_count();
     202        irq_cmd_t irq_cmds[cmd_count];
     203        ret =
     204            hc_get_irq_commands(irq_cmds, sizeof(irq_cmds), reg_base, reg_size);
     205        CHECK_RET_DEST_FREE_RETURN(ret,
     206            "Failed to generate IRQ commands: %s.\n", str_error(ret));
     207
     208        irq_code_t irq_code = { .cmdcount = cmd_count, .cmds = irq_cmds };
     209
     210        /* Register handler to avoid interrupt lockup */
     211        ret = register_interrupt_handler(device, irq, irq_handler, &irq_code);
     212        CHECK_RET_DEST_FREE_RETURN(ret,
     213            "Failed to register interrupt handler: %s.\n", str_error(ret));
     214
     215        /* Try to enable interrupts */
    195216        bool interrupts = false;
    196 #ifdef CONFIG_USBHC_NO_INTERRUPTS
    197         usb_log_warning("Interrupts disabled in OS config, "
    198             "falling back to polling.\n");
    199 #else
    200217        ret = pci_enable_interrupts(device);
    201218        if (ret != EOK) {
    202                 usb_log_warning("Failed to enable interrupts: %s.\n",
    203                     str_error(ret));
    204                 usb_log_info("HW interrupts not available, "
    205                     "falling back to polling.\n");
     219                usb_log_warning("Failed to enable interrupts: %s."
     220                    " Falling back to polling\n", str_error(ret));
     221                /* We don't need that handler */
     222                unregister_interrupt_handler(device, irq);
    206223        } else {
    207224                usb_log_debug("Hw interrupts enabled.\n");
    208225                interrupts = true;
    209226        }
    210 #endif
    211227
    212228        ret = hc_init(&instance->hc, reg_base, reg_size, interrupts);
    213         CHECK_RET_DEST_FREE_RETURN(ret, "Failed(%d) to init ohci_hcd.\n", ret);
     229        CHECK_RET_DEST_FREE_RETURN(ret,
     230            "Failed to init ohci_hcd: %s.\n", str_error(ret));
     231
     232        device->driver_data = instance;
    214233
    215234#define CHECK_RET_FINI_RETURN(ret, message...) \
    216235if (ret != EOK) { \
     236        unregister_interrupt_handler(device, irq); \
    217237        hc_fini(&instance->hc); \
    218238        CHECK_RET_DEST_FREE_RETURN(ret, message); \
    219239} else (void)0
    220240
    221         /* It does no harm if we register this on polling */
    222         ret = register_interrupt_handler(device, irq, irq_handler,
    223             &instance->hc.interrupt_code);
    224         CHECK_RET_FINI_RETURN(ret,
    225             "Failed(%d) to register interrupt handler.\n", ret);
    226241
    227242        ret = ddf_fun_bind(instance->hc_fun);
    228243        CHECK_RET_FINI_RETURN(ret,
    229             "Failed(%d) to bind OHCI device function: %s.\n",
    230             ret, str_error(ret));
     244            "Failed to bind OHCI device function: %s.\n", str_error(ret));
    231245
    232246        ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
     
    234248            "Failed to add OHCI to HC class: %s.\n", str_error(ret));
    235249
    236         device->driver_data = instance;
    237 
    238         hc_start_hw(&instance->hc);
    239250        hc_register_hub(&instance->hc, instance->rh_fun);
    240251        return EOK;
  • uspace/drv/bus/usb/ohci/ohci_regs.h

    r3e5c48c9 r159100a  
    3434#ifndef DRV_OHCI_OHCI_REGS_H
    3535#define DRV_OHCI_OHCI_REGS_H
    36 #include <stdint.h>
     36#include <sys/types.h>
     37
     38#define LEGACY_REGS_OFFSET 0x100
    3739
    3840/** OHCI memory mapped registers structure */
    3941typedef struct ohci_regs {
    40         const volatile uint32_t revision;
    41         volatile uint32_t control;
    42 #define C_CSBR_MASK (0x3) /* Control-bulk service ratio */
    43 #define C_CSBR_1_1  (0x0)
    44 #define C_CSBR_1_2  (0x1)
    45 #define C_CSBR_1_3  (0x2)
    46 #define C_CSBR_1_4  (0x3)
    47 #define C_CSBR_SHIFT (0)
     42        const ioport32_t revision;
     43#define R_REVISION_MASK (0x3f)
     44#define R_REVISION_SHIFT (0)
     45#define R_LEGACY_FLAG   (0x80)
     46
     47        ioport32_t control;
     48#define C_CBSR_MASK (0x3) /* Control-bulk service ratio */
     49#define C_CBSR_1_1  (0x0)
     50#define C_CBSR_1_2  (0x1)
     51#define C_CBSR_1_3  (0x2)
     52#define C_CBSR_1_4  (0x3)
     53#define C_CBSR_SHIFT (0)
    4854
    4955#define C_PLE (1 << 2)   /* Periodic list enable */
     
    5965#define C_HCFS_SHIFT       (6)
    6066
     67#define C_HCFS_GET(reg) \
     68        ((reg >> C_HCFS_SHIFT) & C_HCFS_MASK)
     69#define C_HCFS_SET(reg, hcfs_state) \
     70do { \
     71        reg = (reg & ~(C_HCFS_MASK << C_HCFS_SHIFT)) \
     72            | ((hcfs_state & C_HCFS_MASK) << C_HCFS_SHIFT); \
     73} while (0)
     74
     75
    6176#define C_IR  (1 << 8)   /* Interrupt routing, make sure it's 0 */
    6277#define C_RWC (1 << 9)   /* Remote wakeup connected, host specific */
    6378#define C_RWE (1 << 10)  /* Remote wakeup enable */
    6479
    65         volatile uint32_t command_status;
     80        ioport32_t command_status;
    6681#define CS_HCR (1 << 0)   /* Host controller reset */
    6782#define CS_CLF (1 << 1)   /* Control list filled */
     
    7590         * writing causes enable/disable,
    7691         * status is write-clean (writing 1 clears the bit*/
    77         volatile uint32_t interrupt_status;
    78         volatile uint32_t interrupt_enable;
    79         volatile uint32_t interrupt_disable;
     92        ioport32_t interrupt_status;
     93        ioport32_t interrupt_enable;
     94        ioport32_t interrupt_disable;
    8095#define I_SO   (1 << 0)   /* Scheduling overrun */
    8196#define I_WDH  (1 << 1)   /* Done head write-back */
     
    89104
    90105        /** HCCA pointer (see hw_struct hcca.h) */
    91         volatile uint32_t hcca;
     106        ioport32_t hcca;
    92107#define HCCA_PTR_MASK 0xffffff00 /* HCCA is 256B aligned */
    93108
    94109        /** Currently executed periodic endpoint */
    95         const volatile uint32_t periodic_current;
     110        const ioport32_t periodic_current;
    96111
    97112        /** The first control endpoint */
    98         volatile uint32_t control_head;
     113        ioport32_t control_head;
    99114
    100115        /** Currently executed control endpoint */
    101         volatile uint32_t control_current;
     116        ioport32_t control_current;
    102117
    103118        /** The first bulk endpoint */
    104         volatile uint32_t bulk_head;
     119        ioport32_t bulk_head;
    105120
    106121        /** Currently executed bulk endpoint */
    107         volatile uint32_t bulk_current;
     122        ioport32_t bulk_current;
    108123
    109124        /** Done TD list, this value is periodically written to HCCA */
    110         const volatile uint32_t done_head;
     125        const ioport32_t done_head;
    111126
    112127        /** Frame time and max packet size for all transfers */
    113         volatile uint32_t fm_interval;
     128        ioport32_t fm_interval;
    114129#define FMI_FI_MASK (0x3fff) /* Frame interval in bit times (should be 11999)*/
    115130#define FMI_FI_SHIFT (0)
     
    119134
    120135        /** Bit times remaining in current frame */
    121         const volatile uint32_t fm_remaining;
     136        const ioport32_t fm_remaining;
    122137#define FMR_FR_MASK FMI_FI_MASK
    123138#define FMR_FR_SHIFT FMI_FI_SHIFT
     
    125140
    126141        /** Frame number */
    127         const volatile uint32_t fm_number;
     142        const ioport32_t fm_number;
    128143#define FMN_NUMBER_MASK (0xffff)
    129144
    130145        /** Remaining bit time in frame to start periodic transfers */
    131         volatile uint32_t periodic_start;
     146        ioport32_t periodic_start;
    132147#define PS_PS_MASK (0x3fff) /* bit time when periodic get priority (0x3e67) */
    133148
    134149        /** Threshold for starting LS transaction */
    135         volatile uint32_t ls_threshold;
     150        ioport32_t ls_threshold;
    136151#define LST_LST_MASK (0x7fff)
    137152
    138153        /** The first root hub control register */
    139         volatile uint32_t rh_desc_a;
     154        ioport32_t rh_desc_a;
    140155#define RHDA_NDS_MASK (0xff) /* Number of downstream ports, max 15 */
    141156#define RHDA_NDS_SHIFT (0)
     
    144159#define RHDA_DT_FLAG   (1 << 10) /* 1-Compound device, must be 0 */
    145160#define RHDA_OCPM_FLAG (1 << 11) /* Over-current mode: 0-global, 1-per port */
    146 #define RHDA_NOCP      (1 << 12) /* OC control: 0-use OCPM, 1-OC off */
     161#define RHDA_NOCP_FLAG (1 << 12) /* OC control: 0-use OCPM, 1-OC off */
    147162#define RHDA_POTPGT_MASK (0xff)  /* Power on to power good time */
    148163#define RHDA_POTPGT_SHIFT (24)
    149164
    150165        /** The other root hub control register */
    151         volatile uint32_t rh_desc_b;
     166        ioport32_t rh_desc_b;
    152167#define RHDB_DR_MASK (0xffff) /* Device removable mask */
    153168#define RHDB_DR_SHIFT (0)
     
    161176
    162177        /** Root hub status register */
    163         volatile uint32_t rh_status;
     178        ioport32_t rh_status;
    164179#define RHS_LPS_FLAG  (1 <<  0)/* read: 0,
    165180                                * write: 0-no effect,
     
    167182                                *        specified in PPCM(RHDB), or all ports,
    168183                                *        if power is set globally */
    169 #define RHS_CLEAR_PORT_POWER RHS_LPS_FLAG /* synonym for the above */
     184#define RHS_CLEAR_GLOBAL_POWER RHS_LPS_FLAG /* synonym for the above */
    170185#define RHS_OCI_FLAG  (1 <<  1)/* Over-current indicator, if per-port: 0 */
    171186#define RHS_DRWE_FLAG (1 << 15)/* read: 0-connect status change does not wake HC
     
    178193                                *        specified in PPCM(RHDB), or all ports,
    179194                                *        if power is set globally */
    180 #define RHS_SET_PORT_POWER RHS_LPSC_FLAG /* synonym for the above */
     195#define RHS_SET_GLOBAL_POWER RHS_LPSC_FLAG /* synonym for the above */
    181196#define RHS_OCIC_FLAG (1 << 17)/* Over-current indicator change   */
    182197#define RHS_CLEAR_DRWE (1 << 31)
    183198
    184199        /** Root hub per port status */
    185         volatile uint32_t rh_port_status[];
     200        ioport32_t rh_port_status[];
    186201#define RHPS_CCS_FLAG (1 << 0) /* r: current connect status,
    187202                                * w: 1-clear port enable, 0-nothing */
  • uspace/drv/bus/usb/ohci/root_hub.c

    r3e5c48c9 r159100a  
    4040#include "root_hub.h"
    4141#include <usb/classes/classes.h>
     42#include <usb/classes/hub.h>
    4243#include <usb/dev/driver.h>
    4344#include "ohci_regs.h"
     
    5657        .device_subclass = 0,
    5758        .device_version = 0,
    58         .length = sizeof (usb_standard_device_descriptor_t),
    59         .max_packet_size = 8,
    60         .vendor_id = 0x16db,
     59        .length = sizeof(usb_standard_device_descriptor_t),
     60        .max_packet_size = 64,
     61        .vendor_id = 0x16db, /* HelenOS does not have USB vendor ID assigned.*/
    6162        .product_id = 0x0001,
    6263        .str_serial_number = 0,
     
    7374        .descriptor_type = USB_DESCTYPE_CONFIGURATION,
    7475        .interface_count = 1,
    75         .length = sizeof (usb_standard_configuration_descriptor_t),
    76         .max_power = 100,
     76        .length = sizeof(usb_standard_configuration_descriptor_t),
     77        .max_power = 0, /* root hubs don't need no power */
    7778        .str_configuration = 0,
    7879};
     
    8990        .interface_protocol = 0,
    9091        .interface_subclass = 0,
    91         .length = sizeof (usb_standard_interface_descriptor_t),
     92        .length = sizeof(usb_standard_interface_descriptor_t),
    9293        .str_interface = 0,
    9394};
     
    100101        .descriptor_type = USB_DESCTYPE_ENDPOINT,
    101102        .endpoint_address = 1 + (1 << 7),
    102         .length = sizeof (usb_standard_endpoint_descriptor_t),
    103         .max_packet_size = 8,
     103        .length = sizeof(usb_standard_endpoint_descriptor_t),
     104        .max_packet_size = 2,
    104105        .poll_interval = 255,
    105106};
    106107
    107 /**
    108  * bitmask of hub features that are valid to be cleared
    109  */
    110 static const uint32_t hub_clear_feature_valid_mask =
    111     RHS_OCIC_FLAG |
    112     RHS_CLEAR_PORT_POWER;
    113 
    114 /**
    115  * bitmask of hub features that are cleared by writing 1 (and not 0)
    116  */
    117 static const uint32_t hub_clear_feature_by_writing_one_mask =
    118     RHS_CLEAR_PORT_POWER;
    119 
    120 /**
    121  * bitmask of hub features that are valid to be set
    122  */
    123 static const uint32_t hub_set_feature_valid_mask =
    124     RHS_LPSC_FLAG |
    125     RHS_OCIC_FLAG;
    126 
    127 /**
    128  * bitmask of hub features that are set by writing 1 and cleared by writing 0
    129  */
    130 static const uint32_t hub_set_feature_direct_mask =
    131     RHS_SET_PORT_POWER;
    132 
    133 /**
    134  * bitmask of port features that are valid to be set
    135  */
    136 static const uint32_t port_set_feature_valid_mask =
    137     RHPS_SET_PORT_ENABLE |
    138     RHPS_SET_PORT_SUSPEND |
    139     RHPS_SET_PORT_RESET |
    140     RHPS_SET_PORT_POWER;
    141 
    142 /**
    143  * bitmask of port features that can be cleared
    144  */
    145 static const uint32_t port_clear_feature_valid_mask =
    146     RHPS_CCS_FLAG |
    147     RHPS_SET_PORT_SUSPEND |
    148     RHPS_POCI_FLAG |
    149     RHPS_SET_PORT_POWER |
    150     RHPS_CSC_FLAG |
    151     RHPS_PESC_FLAG |
    152     RHPS_PSSC_FLAG |
    153     RHPS_OCIC_FLAG |
    154     RHPS_PRSC_FLAG;
    155 
    156 //note that USB_HUB_FEATURE_PORT_POWER bit is translated into
    157 //USB_HUB_FEATURE_PORT_LOW_SPEED for port set feature request
    158 
    159 /**
    160  * bitmask with port status changes
    161  */
    162 static const uint32_t port_status_change_mask = RHPS_CHANGE_WC_MASK;
    163 
    164 static int create_serialized_hub_descriptor(rh_t *instance);
    165 
    166 static int rh_init_descriptors(rh_t *instance);
    167 
    168 static int process_get_port_status_request(rh_t *instance, uint16_t port,
    169     usb_transfer_batch_t * request);
    170 
    171 static int process_get_hub_status_request(rh_t *instance,
    172     usb_transfer_batch_t * request);
    173 
    174 static int process_get_status_request(rh_t *instance,
    175     usb_transfer_batch_t * request);
    176 
    177 static void create_interrupt_mask_in_instance(rh_t *instance);
    178 
    179 static int process_get_descriptor_request(rh_t *instance,
    180     usb_transfer_batch_t *request);
    181 
    182 static int process_get_configuration_request(rh_t *instance,
    183     usb_transfer_batch_t *request);
    184 
    185 static int process_hub_feature_set_request(rh_t *instance, uint16_t feature);
    186 
    187 static int process_hub_feature_clear_request(rh_t *instance,
    188     uint16_t feature);
    189 
    190 static int process_port_feature_set_request(rh_t *instance,
    191     uint16_t feature, uint16_t port);
    192 
    193 static int process_port_feature_clear_request(rh_t *instance,
    194     uint16_t feature, uint16_t port);
    195 
    196 static int process_address_set_request(rh_t *instance,
    197     uint16_t address);
    198 
    199 static int process_request_with_output(rh_t *instance,
    200     usb_transfer_batch_t *request);
    201 
    202 static int process_request_with_input(rh_t *instance,
    203     usb_transfer_batch_t *request);
    204 
    205 static int process_request_without_data(rh_t *instance,
    206     usb_transfer_batch_t *request);
    207 
    208 static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request);
    209 
    210 static int process_interrupt_mask_in_instance(rh_t *instance, usb_transfer_batch_t * request);
    211 
    212 static bool is_zeros(void * buffer, size_t size);
    213 
    214 /** Root hub initialization
    215  * @return Error code.
    216  */
    217 int rh_init(rh_t *instance, ohci_regs_t *regs) {
    218         assert(instance);
     108static void create_serialized_hub_descriptor(rh_t *instance);
     109static void rh_init_descriptors(rh_t *instance);
     110static uint16_t create_interrupt_mask(rh_t *instance);
     111static int get_status(rh_t *instance, usb_transfer_batch_t *request);
     112static int get_descriptor(rh_t *instance, usb_transfer_batch_t *request);
     113static int set_feature(rh_t *instance, usb_transfer_batch_t *request);
     114static int clear_feature(rh_t *instance, usb_transfer_batch_t *request);
     115static int set_feature_port(rh_t *instance, uint16_t feature, uint16_t port);
     116static int clear_feature_port(rh_t *instance, uint16_t feature, uint16_t port);
     117static int control_request(rh_t *instance, usb_transfer_batch_t *request);
     118static inline void interrupt_request(
     119    usb_transfer_batch_t *request, uint16_t mask, size_t size)
     120{
     121        assert(request);
     122
     123        memcpy(request->data_buffer, &mask, size);
     124        request->transfered_size = size;
     125        usb_transfer_batch_finish_error(request, EOK);
     126}
     127
     128#define TRANSFER_OK(bytes) \
     129do { \
     130        request->transfered_size = bytes; \
     131        return EOK; \
     132} while (0)
     133
     134/** Root Hub driver structure initialization.
     135 *
     136 * Reads info registers and prepares descriptors. Sets power mode.
     137 */
     138void rh_init(rh_t *instance, ohci_regs_t *regs)
     139{
     140        assert(instance);
     141        assert(regs);
     142
    219143        instance->registers = regs;
    220144        instance->port_count =
    221145            (instance->registers->rh_desc_a >> RHDA_NDS_SHIFT) & RHDA_NDS_MASK;
    222         int opResult = rh_init_descriptors(instance);
    223         if (opResult != EOK) {
    224                 return opResult;
    225         }
    226         // set port power mode to no-power-switching
     146        if (instance->port_count > 15) {
     147                usb_log_warning("OHCI specification does not allow more than 15"
     148                    " ports. Max 15 ports will be used");
     149                instance->port_count = 15;
     150        }
     151
     152        /* Don't forget the hub status bit and round up */
     153        instance->interrupt_mask_size = 1 + (instance->port_count / 8);
     154        instance->unfinished_interrupt_transfer = NULL;
     155
     156#ifdef OHCI_POWER_SWITCH_no
     157        /* Set port power mode to no power-switching. (always on) */
    227158        instance->registers->rh_desc_a |= RHDA_NPS_FLAG;
    228         instance->unfinished_interrupt_transfer = NULL;
    229         instance->interrupt_mask_size = (instance->port_count + 8) / 8;
    230         instance->interrupt_buffer = malloc(instance->interrupt_mask_size);
    231         if (!instance->interrupt_buffer)
    232                 return ENOMEM;
     159        /* Set to no over-current reporting */
     160        instance->registers->rh_desc_a |= RHDA_NOCP_FLAG;
     161#elif defined OHCI_POWER_SWITCH_ganged
     162        /* Set port power mode to no ganged power-switching. */
     163        instance->registers->rh_desc_a &= ~RHDA_NPS_FLAG;
     164        instance->registers->rh_desc_a &= ~RHDA_PSM_FLAG;
     165        instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
     166        /* Set to global over-current */
     167        instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;
     168        instance->registers->rh_desc_a &= ~RHDA_OCPM_FLAG;
     169#else
     170        /* Set port power mode to no per port power-switching. */
     171        instance->registers->rh_desc_a &= ~RHDA_NPS_FLAG;
     172        instance->registers->rh_desc_a |= RHDA_PSM_FLAG;
     173
     174        /* Control all ports by global switch and turn them off */
     175        instance->registers->rh_desc_b &= (RHDB_PCC_MASK << RHDB_PCC_SHIFT);
     176        instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
     177        /* Return control to per port state */
     178        instance->registers->rh_desc_b |=
     179                ((1 << (instance->port_count + 1)) - 1) << RHDB_PCC_SHIFT;
     180        /* Set per port over-current */
     181        instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;
     182        instance->registers->rh_desc_a |= RHDA_OCPM_FLAG;
     183#endif
     184
     185        rh_init_descriptors(instance);
    233186
    234187        usb_log_info("Root hub (%zu ports) initialized.\n",
    235188            instance->port_count);
    236 
    237         return EOK;
    238 }
    239 /*----------------------------------------------------------------------------*/
    240 
    241 /**
    242  * process root hub request
    243  *
    244  * @param instance root hub instance
    245  * @param request structure containing both request and response information
    246  * @return error code
    247  */
    248 int rh_request(rh_t *instance, usb_transfer_batch_t *request) {
     189}
     190/*----------------------------------------------------------------------------*/
     191/**
     192 * Process root hub request.
     193 *
     194 * @param instance Root hub instance
     195 * @param request Structure containing both request and response information
     196 * @return Error code
     197 */
     198void rh_request(rh_t *instance, usb_transfer_batch_t *request)
     199{
    249200        assert(instance);
    250201        assert(request);
    251         int opResult;
    252         if (request->ep->transfer_type == USB_TRANSFER_CONTROL) {
     202
     203        switch (request->ep->transfer_type)
     204        {
     205        case USB_TRANSFER_CONTROL:
    253206                usb_log_debug("Root hub got CONTROL packet\n");
    254                 opResult = process_ctrl_request(instance, request);
    255                 usb_transfer_batch_finish_error(request, opResult);
    256         } else if (request->ep->transfer_type == USB_TRANSFER_INTERRUPT) {
     207                const int ret = control_request(instance, request);
     208                usb_transfer_batch_finish_error(request, ret);
     209                break;
     210        case USB_TRANSFER_INTERRUPT:
    257211                usb_log_debug("Root hub got INTERRUPT packet\n");
    258                 create_interrupt_mask_in_instance(instance);
    259                 if (is_zeros(instance->interrupt_buffer,
    260                     instance->interrupt_mask_size)) {
     212                const uint16_t mask = create_interrupt_mask(instance);
     213                if (mask == 0) {
    261214                        usb_log_debug("No changes..\n");
     215                        assert(instance->unfinished_interrupt_transfer == NULL);
    262216                        instance->unfinished_interrupt_transfer = request;
    263                         //will be finished later
    264                 } else {
    265                         usb_log_debug("Processing changes..\n");
    266                         process_interrupt_mask_in_instance(instance, request);
     217                        break;
    267218                }
    268                 opResult = EOK;
    269         } else {
    270 
    271                 opResult = EINVAL;
    272                 usb_transfer_batch_finish_error(request, opResult);
    273         }
    274         return EOK;
    275 }
    276 
    277 /*----------------------------------------------------------------------------*/
    278 
    279 /**
    280  * process interrupt on a hub
     219                usb_log_debug("Processing changes...\n");
     220                interrupt_request(request, mask, instance->interrupt_mask_size);
     221                break;
     222
     223        default:
     224                usb_log_error("Root hub got unsupported request.\n");
     225                usb_transfer_batch_finish_error(request, EINVAL);
     226        }
     227}
     228/*----------------------------------------------------------------------------*/
     229/**
     230 * Process interrupt on a hub device.
    281231 *
    282232 * If there is no pending interrupt transfer, nothing happens.
    283233 * @param instance
    284234 */
    285 void rh_interrupt(rh_t *instance) {
    286         if (!instance->unfinished_interrupt_transfer) {
     235void rh_interrupt(rh_t *instance)
     236{
     237        assert(instance);
     238
     239        if (!instance->unfinished_interrupt_transfer)
    287240                return;
    288         }
     241
    289242        usb_log_debug("Finalizing interrupt transfer\n");
    290         create_interrupt_mask_in_instance(instance);
    291         process_interrupt_mask_in_instance(instance,
    292             instance->unfinished_interrupt_transfer);
    293 }
    294 /*----------------------------------------------------------------------------*/
    295 
    296 /**
    297  * Create hub descriptor used in hub-driver <-> hub communication
    298  *
    299  * This means creating byt array from data in root hub registers. For more
    300  * info see usb hub specification.
    301  *
     243        const uint16_t mask = create_interrupt_mask(instance);
     244        interrupt_request(instance->unfinished_interrupt_transfer,
     245            mask, instance->interrupt_mask_size);
     246
     247        instance->unfinished_interrupt_transfer = NULL;
     248}
     249/*----------------------------------------------------------------------------*/
     250/**
     251 * Create hub descriptor.
     252 *
     253 * For descriptor format see USB hub specification (chapter 11.15.2.1, pg. 263)
     254 *
     255 * @param instance Root hub instance
     256 * @return Error code
     257 */
     258void create_serialized_hub_descriptor(rh_t *instance)
     259{
     260        assert(instance);
     261
     262        /* 7 bytes + 2 port bit fields (port count + global bit) */
     263        const size_t size = 7 + (instance->interrupt_mask_size * 2);
     264        assert(size <= HUB_DESCRIPTOR_MAX_SIZE);
     265        instance->hub_descriptor_size = size;
     266
     267        const uint32_t hub_desc = instance->registers->rh_desc_a;
     268        const uint32_t port_desc = instance->registers->rh_desc_b;
     269
     270        /* bDescLength */
     271        instance->descriptors.hub[0] = size;
     272        /* bDescriptorType */
     273        instance->descriptors.hub[1] = USB_DESCTYPE_HUB;
     274        /* bNmbrPorts */
     275        instance->descriptors.hub[2] = instance->port_count;
     276        /* wHubCharacteristics */
     277        instance->descriptors.hub[3] = 0 |
     278            /* The lowest 2 bits indicate power switching mode */
     279            (((hub_desc & RHDA_PSM_FLAG)  ? 1 : 0) << 0) |
     280            (((hub_desc & RHDA_NPS_FLAG)  ? 1 : 0) << 1) |
     281            /* Bit 3 indicates device type (compound device) */
     282            (((hub_desc & RHDA_DT_FLAG)   ? 1 : 0) << 2) |
     283            /* Bits 4,5 indicate over-current protection mode */
     284            (((hub_desc & RHDA_OCPM_FLAG) ? 1 : 0) << 3) |
     285            (((hub_desc & RHDA_NOCP_FLAG) ? 1 : 0) << 4);
     286
     287        /* Reserved */
     288        instance->descriptors.hub[4] = 0;
     289        /* bPwrOn2PwrGood */
     290        instance->descriptors.hub[5] =
     291            (hub_desc >> RHDA_POTPGT_SHIFT) & RHDA_POTPGT_MASK;
     292        /* bHubContrCurrent, root hubs don't need no power. */
     293        instance->descriptors.hub[6] = 0;
     294
     295        /* Device Removable and some legacy 1.0 stuff*/
     296        instance->descriptors.hub[7] =
     297            (port_desc >> RHDB_DR_SHIFT) & RHDB_DR_MASK & 0xff;
     298        instance->descriptors.hub[8] = 0xff;
     299        if (instance->interrupt_mask_size == 2) {
     300                instance->descriptors.hub[8] =
     301                    (port_desc >> RHDB_DR_SHIFT) & RHDB_DR_MASK >> 8;
     302                instance->descriptors.hub[9]  = 0xff;
     303                instance->descriptors.hub[10] = 0xff;
     304        }
     305}
     306/*----------------------------------------------------------------------------*/
     307/** Initialize hub descriptors.
     308 *
     309 * A full configuration descriptor is assembled. The configuration and endpoint
     310 * descriptors have local modifications.
     311 * @param instance Root hub instance
     312 * @return Error code
     313 */
     314void rh_init_descriptors(rh_t *instance)
     315{
     316        assert(instance);
     317
     318        instance->descriptors.configuration = ohci_rh_conf_descriptor;
     319        instance->descriptors.interface = ohci_rh_iface_descriptor;
     320        instance->descriptors.endpoint = ohci_rh_ep_descriptor;
     321        create_serialized_hub_descriptor(instance);
     322
     323        instance->descriptors.endpoint.max_packet_size =
     324            instance->interrupt_mask_size;
     325
     326        instance->descriptors.configuration.total_length =
     327            sizeof(usb_standard_configuration_descriptor_t) +
     328            sizeof(usb_standard_endpoint_descriptor_t) +
     329            sizeof(usb_standard_interface_descriptor_t) +
     330            instance->hub_descriptor_size;
     331}
     332/*----------------------------------------------------------------------------*/
     333/**
     334 * Create bitmap of changes to answer status interrupt.
     335 *
     336 * Result contains bitmap where bit 0 indicates change on hub and
     337 * bit i indicates change on i`th port (i>0). For more info see
     338 * Hub and Port status bitmap specification in USB specification
     339 * (chapter 11.13.4).
    302340 * @param instance root hub instance
    303  * @return error code
    304  */
    305 static int create_serialized_hub_descriptor(rh_t *instance) {
    306         size_t size = 7 +
    307             ((instance->port_count + 7) / 8) * 2;
    308         size_t var_size = (instance->port_count + 7) / 8;
    309         uint8_t * result = (uint8_t*) malloc(size);
    310         if (!result) return ENOMEM;
    311 
    312         bzero(result, size);
    313         //size
    314         result[0] = size;
    315         //descriptor type
    316         result[1] = USB_DESCTYPE_HUB;
    317         result[2] = instance->port_count;
    318         uint32_t hub_desc_reg = instance->registers->rh_desc_a;
    319         result[3] =
    320             ((hub_desc_reg >> 8) % 2) +
    321             (((hub_desc_reg >> 9) % 2) << 1) +
    322             (((hub_desc_reg >> 10) % 2) << 2) +
    323             (((hub_desc_reg >> 11) % 2) << 3) +
    324             (((hub_desc_reg >> 12) % 2) << 4);
    325         result[4] = 0;
    326         result[5] = /*descriptor->pwr_on_2_good_time*/ 50;
    327         result[6] = 50;
    328 
    329         size_t port;
    330         for (port = 1; port <= instance->port_count; ++port) {
    331                 uint8_t is_non_removable =
    332                     instance->registers->rh_desc_b >> port % 2;
    333                 result[7 + port / 8] +=
    334                     is_non_removable << (port % 8);
    335         }
    336         size_t i;
    337         for (i = 0; i < var_size; ++i) {
    338                 result[7 + var_size + i] = 255;
    339         }
    340         instance->hub_descriptor = result;
    341         instance->descriptor_size = size;
    342 
    343         return EOK;
    344 }
    345 /*----------------------------------------------------------------------------*/
    346 
    347 /** initialize hub descriptors
    348  *
    349  * Initialized are device and full configuration descriptor. These need to
    350  * be initialized only once per hub.
    351  * @instance root hub instance
    352  * @return error code
    353  */
    354 static int rh_init_descriptors(rh_t *instance) {
    355         memcpy(&instance->descriptors.device, &ohci_rh_device_descriptor,
    356             sizeof (ohci_rh_device_descriptor)
    357             );
    358         usb_standard_configuration_descriptor_t descriptor;
    359         memcpy(&descriptor, &ohci_rh_conf_descriptor,
    360             sizeof (ohci_rh_conf_descriptor));
    361 
    362         int opResult = create_serialized_hub_descriptor(instance);
    363         if (opResult != EOK) {
    364                 return opResult;
    365         }
    366         descriptor.total_length =
    367             sizeof (usb_standard_configuration_descriptor_t) +
    368             sizeof (usb_standard_endpoint_descriptor_t) +
    369             sizeof (usb_standard_interface_descriptor_t) +
    370             instance->descriptor_size;
    371 
    372         uint8_t * full_config_descriptor =
    373             (uint8_t*) malloc(descriptor.total_length);
    374         if (!full_config_descriptor) {
    375                 return ENOMEM;
    376         }
    377         memcpy(full_config_descriptor, &descriptor, sizeof (descriptor));
    378         memcpy(full_config_descriptor + sizeof (descriptor),
    379             &ohci_rh_iface_descriptor, sizeof (ohci_rh_iface_descriptor));
    380         memcpy(full_config_descriptor + sizeof (descriptor) +
    381             sizeof (ohci_rh_iface_descriptor),
    382             &ohci_rh_ep_descriptor, sizeof (ohci_rh_ep_descriptor));
    383         memcpy(full_config_descriptor + sizeof (descriptor) +
    384             sizeof (ohci_rh_iface_descriptor) +
    385             sizeof (ohci_rh_ep_descriptor),
    386             instance->hub_descriptor, instance->descriptor_size);
    387 
    388         instance->descriptors.configuration = full_config_descriptor;
    389         instance->descriptors.configuration_size = descriptor.total_length;
    390 
    391         return EOK;
    392 }
    393 /*----------------------------------------------------------------------------*/
    394 
    395 /**
    396  * create answer to port status_request
    397  *
    398  * Copy content of corresponding port status register to answer buffer. The
    399  * format of the port status register and port status data is the same (
    400  * see OHCI root hub and USB hub documentation).
    401  *
    402  * @param instance root hub instance
    403  * @param port port number, counted from 1
    404  * @param request structure containing both request and response information
    405  * @return error code
    406  */
    407 static int process_get_port_status_request(rh_t *instance, uint16_t port,
    408     usb_transfer_batch_t * request) {
    409         if (port < 1 || port > instance->port_count)
    410                 return EINVAL;
    411         request->transfered_size = 4;
    412         uint32_t data = instance->registers->rh_port_status[port - 1];
    413         memcpy(request->data_buffer, &data, 4);
    414         return EOK;
    415 }
    416 /*----------------------------------------------------------------------------*/
    417 
    418 /**
    419  * create answer to port status_request
    420  *
    421  * This copies flags in hub status register into the buffer. The format of the
    422  * status register and status message is the same, according to USB hub
    423  * specification and OHCI root hub specification.
    424  *
    425  * @param instance root hub instance
    426  * @param request structure containing both request and response information
    427  * @return error code
    428  */
    429 static int process_get_hub_status_request(rh_t *instance,
    430     usb_transfer_batch_t * request) {
    431         request->transfered_size = 4;
    432         //bits, 0,1,16,17
    433         uint32_t mask = 1 | (1 << 1) | (1 << 16) | (1 << 17);
    434         uint32_t data = mask & instance->registers->rh_status;
    435         memcpy(request->data_buffer, &data, 4);
    436 
    437         return EOK;
    438 }
    439 /*----------------------------------------------------------------------------*/
    440 
    441 /**
    442  * create answer to status request
     341 * @return Mask of changes.
     342 */
     343uint16_t create_interrupt_mask(rh_t *instance)
     344{
     345        assert(instance);
     346        uint16_t mask = 0;
     347
     348        /* Only local power source change and over-current change can happen */
     349        if (instance->registers->rh_status & (RHS_LPSC_FLAG | RHS_OCIC_FLAG)) {
     350                mask |= 1;
     351        }
     352        size_t port = 1;
     353        for (; port <= instance->port_count; ++port) {
     354                /* Write-clean bits are those that indicate change */
     355                if (RHPS_CHANGE_WC_MASK
     356                    & instance->registers->rh_port_status[port - 1]) {
     357
     358                        mask |= (1 << port);
     359                }
     360        }
     361        /* USB is little endian */
     362        return host2uint32_t_le(mask);
     363}
     364/*----------------------------------------------------------------------------*/
     365/**
     366 * Create answer to status request.
    443367 *
    444368 * This might be either hub status or port status request. If neither,
     
    448372 * @return error code
    449373 */
    450 static int process_get_status_request(rh_t *instance,
    451     usb_transfer_batch_t * request) {
    452         size_t buffer_size = request->buffer_size;
    453         usb_device_request_setup_packet_t * request_packet =
    454             (usb_device_request_setup_packet_t*)
    455             request->setup_buffer;
    456 
    457         usb_hub_bm_request_type_t request_type = request_packet->request_type;
    458         if (buffer_size < 4) {
    459                 usb_log_warning("Requested more data than buffer size\n");
    460                 return EINVAL;
    461         }
    462 
    463         if (request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)
    464                 return process_get_hub_status_request(instance, request);
    465         if (request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS)
    466                 return process_get_port_status_request(instance,
    467             request_packet->index,
    468             request);
     374int get_status(rh_t *instance, usb_transfer_batch_t *request)
     375{
     376        assert(instance);
     377        assert(request);
     378
     379        const usb_device_request_setup_packet_t *request_packet =
     380            (usb_device_request_setup_packet_t*)request->setup_buffer;
     381
     382        if (request->buffer_size < 4) {
     383                usb_log_error("Buffer too small for get status request.\n");
     384                return EOVERFLOW;
     385        }
     386
     387        /* Hub status: just filter relevant info from rh_status reg */
     388        if (request_packet->request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS) {
     389                const uint32_t data = instance->registers->rh_status &
     390                    (RHS_LPS_FLAG | RHS_LPSC_FLAG | RHS_OCI_FLAG | RHS_OCIC_FLAG);
     391                memcpy(request->data_buffer, &data, 4);
     392                TRANSFER_OK(4);
     393        }
     394
     395        /* Copy appropriate rh_port_status register, OHCI designers were
     396         * kind enough to make those bit values match USB specification */
     397        if (request_packet->request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS) {
     398                const unsigned port = request_packet->index;
     399                if (port < 1 || port > instance->port_count)
     400                        return EINVAL;
     401
     402                const uint32_t data =
     403                    instance->registers->rh_port_status[port - 1];
     404                memcpy(request->data_buffer, &data, 4);
     405                TRANSFER_OK(4);
     406        }
    469407
    470408        return ENOTSUP;
    471409}
    472410/*----------------------------------------------------------------------------*/
    473 
    474 /**
    475  * create answer to status interrupt consisting of change bitmap
    476  *
    477  * Result contains bitmap where bit 0 indicates change on hub and
    478  * bit i indicates change on i`th port (i>0). For more info see
    479  * Hub and Port status bitmap specification in USB specification
    480  * (chapter 11.13.4).
    481  * Uses instance`s interrupt buffer to store the interrupt information.
    482  * @param instance root hub instance
    483  */
    484 static void create_interrupt_mask_in_instance(rh_t * instance) {
    485         uint8_t * bitmap = (uint8_t*) (instance->interrupt_buffer);
    486         uint32_t mask = (1 << (USB_HUB_FEATURE_C_HUB_LOCAL_POWER + 16))
    487             | (1 << (USB_HUB_FEATURE_C_HUB_OVER_CURRENT + 16));
    488         bzero(bitmap, instance->interrupt_mask_size);
    489         if ((instance->registers->rh_status & mask) != 0) {
    490                 bitmap[0] = 1;
    491         }
    492         size_t port;
    493         mask = port_status_change_mask;
    494         for (port = 1; port <= instance->port_count; ++port) {
    495                 if ((mask & instance->registers->rh_port_status[port - 1]) != 0) {
    496 
    497                         bitmap[(port) / 8] += 1 << (port % 8);
    498                 }
    499         }
    500 }
    501 /*----------------------------------------------------------------------------*/
    502 
    503 /**
    504  * create answer to a descriptor request
     411/**
     412 * Create answer to a descriptor request.
    505413 *
    506414 * This might be a request for standard (configuration, device, endpoint or
    507415 * interface) or device specific (hub) descriptor.
    508  * @param instance root hub instance
    509  * @param request structure containing both request and response information
    510  * @return error code
    511  */
    512 static int process_get_descriptor_request(rh_t *instance,
    513     usb_transfer_batch_t *request) {
    514         usb_device_request_setup_packet_t * setup_request =
    515             (usb_device_request_setup_packet_t*) request->setup_buffer;
     416 * @param instance Root hub instance
     417 * @param request Structure containing both request and response information
     418 * @return Error code
     419 */
     420int get_descriptor(rh_t *instance, usb_transfer_batch_t *request)
     421{
     422        assert(instance);
     423        assert(request);
     424
     425        const usb_device_request_setup_packet_t *setup_request =
     426            (usb_device_request_setup_packet_t *) request->setup_buffer;
    516427        size_t size;
    517         const void * result_descriptor = NULL;
     428        const void *descriptor = NULL;
    518429        const uint16_t setup_request_value = setup_request->value_high;
    519430        //(setup_request->value_low << 8);
    520         switch (setup_request_value) {
    521                 case USB_DESCTYPE_HUB:
    522                 {
    523                         usb_log_debug2("USB_DESCTYPE_HUB\n");
    524                         result_descriptor = instance->hub_descriptor;
    525                         size = instance->descriptor_size;
    526                         break;
    527                 }
    528                 case USB_DESCTYPE_DEVICE:
    529                 {
    530                         usb_log_debug2("USB_DESCTYPE_DEVICE\n");
    531                         result_descriptor = &ohci_rh_device_descriptor;
    532                         size = sizeof (ohci_rh_device_descriptor);
    533                         break;
    534                 }
    535                 case USB_DESCTYPE_CONFIGURATION:
    536                 {
    537                         usb_log_debug2("USB_DESCTYPE_CONFIGURATION\n");
    538                         result_descriptor = instance->descriptors.configuration;
    539                         size = instance->descriptors.configuration_size;
    540                         break;
    541                 }
    542                 case USB_DESCTYPE_INTERFACE:
    543                 {
    544                         usb_log_debug2("USB_DESCTYPE_INTERFACE\n");
    545                         result_descriptor = &ohci_rh_iface_descriptor;
    546                         size = sizeof (ohci_rh_iface_descriptor);
    547                         break;
    548                 }
    549                 case USB_DESCTYPE_ENDPOINT:
    550                 {
    551                         usb_log_debug2("USB_DESCTYPE_ENDPOINT\n");
    552                         result_descriptor = &ohci_rh_ep_descriptor;
    553                         size = sizeof (ohci_rh_ep_descriptor);
    554                         break;
    555                 }
    556                 default:
    557                 {
    558                         usb_log_debug2("USB_DESCTYPE_EINVAL %d \n",
    559                             setup_request->value);
    560                         usb_log_debug2("\ttype %d\n\trequest %d\n\tvalue "
    561                             "%d\n\tindex %d\n\tlen %d\n ",
    562                             setup_request->request_type,
    563                             setup_request->request,
    564                             setup_request_value,
    565                             setup_request->index,
    566                             setup_request->length
    567                             );
    568                         return EINVAL;
    569                 }
     431        switch (setup_request_value)
     432        {
     433        case USB_DESCTYPE_HUB:
     434                usb_log_debug2("USB_DESCTYPE_HUB\n");
     435                /* Hub descriptor was generated locally */
     436                descriptor = instance->descriptors.hub;
     437                size = instance->hub_descriptor_size;
     438                break;
     439
     440        case USB_DESCTYPE_DEVICE:
     441                usb_log_debug2("USB_DESCTYPE_DEVICE\n");
     442                /* Device descriptor is shared (No one should ask for it)*/
     443                descriptor = &ohci_rh_device_descriptor;
     444                size = sizeof(ohci_rh_device_descriptor);
     445                break;
     446
     447        case USB_DESCTYPE_CONFIGURATION:
     448                usb_log_debug2("USB_DESCTYPE_CONFIGURATION\n");
     449                /* Start with configuration and add others depending on
     450                 * request size */
     451                descriptor = &instance->descriptors;
     452                size = instance->descriptors.configuration.total_length;
     453                break;
     454
     455        case USB_DESCTYPE_INTERFACE:
     456                usb_log_debug2("USB_DESCTYPE_INTERFACE\n");
     457                /* Use local interface descriptor. There is one and it
     458                 * might be modified */
     459                descriptor = &instance->descriptors.interface;
     460                size = sizeof(instance->descriptors.interface);
     461                break;
     462
     463        case USB_DESCTYPE_ENDPOINT:
     464                /* Use local endpoint descriptor. There is one
     465                 * it might have max_packet_size field modified*/
     466                usb_log_debug2("USB_DESCTYPE_ENDPOINT\n");
     467                descriptor = &instance->descriptors.endpoint;
     468                size = sizeof(instance->descriptors.endpoint);
     469                break;
     470
     471        default:
     472                usb_log_debug2("USB_DESCTYPE_EINVAL %d \n"
     473                    "\ttype %d\n\trequest %d\n\tvalue "
     474                    "%d\n\tindex %d\n\tlen %d\n ",
     475                    setup_request->value,
     476                    setup_request->request_type, setup_request->request,
     477                    setup_request_value, setup_request->index,
     478                    setup_request->length);
     479                return EINVAL;
    570480        }
    571481        if (request->buffer_size < size) {
    572482                size = request->buffer_size;
    573483        }
    574         request->transfered_size = size;
    575         memcpy(request->data_buffer, result_descriptor, size);
    576 
    577         return EOK;
    578 }
    579 /*----------------------------------------------------------------------------*/
    580 
    581 /**
    582  * answer to get configuration request
    583  *
    584  * Root hub works independently on the configuration.
    585  * @param instance root hub instance
    586  * @param request structure containing both request and response information
    587  * @return error code
    588  */
    589 static int process_get_configuration_request(rh_t *instance,
    590     usb_transfer_batch_t *request) {
    591         //set and get configuration requests do not have any meaning, only dummy
    592         //values are returned
    593         if (request->buffer_size != 1)
    594                 return EINVAL;
    595         request->data_buffer[0] = 1;
    596         request->transfered_size = 1;
    597 
    598         return EOK;
    599 }
    600 /*----------------------------------------------------------------------------*/
    601 
    602 /**
    603  * process feature-enabling request on hub
    604  *
    605  * @param instance root hub instance
    606  * @param feature feature selector
    607  * @return error code
    608  */
    609 static int process_hub_feature_set_request(rh_t *instance,
    610     uint16_t feature) {
    611         if (!((1 << feature) & hub_set_feature_valid_mask))
    612                 return EINVAL;
    613         if (feature == USB_HUB_FEATURE_C_HUB_LOCAL_POWER)
    614                 feature = USB_HUB_FEATURE_C_HUB_LOCAL_POWER << 16;
    615         instance->registers->rh_status =
    616             (instance->registers->rh_status | (1 << feature))
    617             & (~hub_clear_feature_by_writing_one_mask);
    618 
    619         return EOK;
    620 }
    621 /*----------------------------------------------------------------------------*/
    622 
    623 /**
    624  * process feature-disabling request on hub
    625  *
    626  * @param instance root hub instance
    627  * @param feature feature selector
    628  * @return error code
    629  */
    630 static int process_hub_feature_clear_request(rh_t *instance,
    631     uint16_t feature) {
    632         if (!((1 << feature) & hub_clear_feature_valid_mask))
    633                 return EINVAL;
    634         //is the feature cleared directly?
    635         if ((1 << feature) & hub_set_feature_direct_mask) {
    636                 instance->registers->rh_status =
    637                     (instance->registers->rh_status & (~(1 << feature)))
    638                     & (~hub_clear_feature_by_writing_one_mask);
    639         } else {//the feature is cleared by writing '1'
    640 
    641                 instance->registers->rh_status =
    642                     (instance->registers->rh_status
    643                     & (~hub_clear_feature_by_writing_one_mask))
    644                     | (1 << feature);
    645         }
    646         return EOK;
    647 }
    648 /*----------------------------------------------------------------------------*/
    649 
     484
     485        memcpy(request->data_buffer, descriptor, size);
     486        TRANSFER_OK(size);
     487}
     488/*----------------------------------------------------------------------------*/
    650489/**
    651490 * process feature-enabling request on hub
     
    657496 * @return error code
    658497 */
    659 static int process_port_feature_set_request(rh_t *instance,
    660     uint16_t feature, uint16_t port) {
    661         if (!((1 << feature) & port_set_feature_valid_mask))
    662                 return EINVAL;
     498int set_feature_port(rh_t *instance, uint16_t feature, uint16_t port)
     499{
     500        assert(instance);
     501
    663502        if (port < 1 || port > instance->port_count)
    664503                return EINVAL;
    665         instance->registers->rh_port_status[port - 1] =
    666             (instance->registers->rh_port_status[port - 1] | (1 << feature))
    667             & (~port_clear_feature_valid_mask);
    668         return EOK;
    669 }
    670 /*----------------------------------------------------------------------------*/
    671 
    672 /**
    673  * process feature-disabling request on hub
     504
     505        switch (feature)
     506        {
     507        case USB_HUB_FEATURE_PORT_POWER:   //8
     508                /* No power switching */
     509                if (instance->registers->rh_desc_a & RHDA_NPS_FLAG)
     510                        return EOK;
     511                /* Ganged power switching */
     512                if (!(instance->registers->rh_desc_a & RHDA_PSM_FLAG)) {
     513                        instance->registers->rh_status = RHS_SET_GLOBAL_POWER;
     514                        return EOK;
     515                }
     516        case USB_HUB_FEATURE_PORT_ENABLE:  //1
     517        case USB_HUB_FEATURE_PORT_SUSPEND: //2
     518        case USB_HUB_FEATURE_PORT_RESET:   //4
     519                /* Nice thing is that these shifts correspond to the position
     520                 * of control bits in register */
     521                instance->registers->rh_port_status[port - 1] = (1 << feature);
     522                return EOK;
     523        default:
     524                return ENOTSUP;
     525        }
     526}
     527/*----------------------------------------------------------------------------*/
     528/**
     529 * Process feature clear request.
    674530 *
    675531 * @param instance root hub instance
     
    679535 * @return error code
    680536 */
    681 static int process_port_feature_clear_request(rh_t *instance,
    682     uint16_t feature, uint16_t port) {
    683         if (!((1 << feature) & port_clear_feature_valid_mask))
    684                 return EINVAL;
     537int clear_feature_port(rh_t *instance, uint16_t feature, uint16_t port)
     538{
     539        assert(instance);
     540
    685541        if (port < 1 || port > instance->port_count)
    686542                return EINVAL;
    687         if (feature == USB_HUB_FEATURE_PORT_POWER)
    688                 feature = USB_HUB_FEATURE_PORT_LOW_SPEED;
    689         if (feature == USB_HUB_FEATURE_PORT_SUSPEND)
    690                 feature = USB_HUB_FEATURE_PORT_OVER_CURRENT;
    691         instance->registers->rh_port_status[port - 1] =
    692             (instance->registers->rh_port_status[port - 1]
    693             & (~port_clear_feature_valid_mask))
    694             | (1 << feature);
    695 
    696         return EOK;
    697 }
    698 /*----------------------------------------------------------------------------*/
    699 
    700 /**
    701  * register address to this device
    702  *
    703  * @param instance root hub instance
    704  * @param address new address
    705  * @return error code
    706  */
    707 static int process_address_set_request(rh_t *instance,
    708     uint16_t address) {
    709         return ENOTSUP;
    710 }
    711 /*----------------------------------------------------------------------------*/
    712 
    713 /**
    714  * process one of requests that requere output data
    715  *
    716  * Request can be one of USB_DEVREQ_GET_STATUS, USB_DEVREQ_GET_DESCRIPTOR or
    717  * USB_DEVREQ_GET_CONFIGURATION.
    718  * @param instance root hub instance
    719  * @param request structure containing both request and response information
    720  * @return error code
    721  */
    722 static int process_request_with_output(rh_t *instance,
    723     usb_transfer_batch_t *request) {
    724         usb_device_request_setup_packet_t * setup_request =
    725             (usb_device_request_setup_packet_t*) request->setup_buffer;
    726         if (setup_request->request == USB_DEVREQ_GET_STATUS) {
    727                 usb_log_debug("USB_DEVREQ_GET_STATUS\n");
    728                 return process_get_status_request(instance, request);
    729         }
    730         if (setup_request->request == USB_DEVREQ_GET_DESCRIPTOR) {
    731                 usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
    732                 return process_get_descriptor_request(instance, request);
    733         }
    734         if (setup_request->request == USB_DEVREQ_GET_CONFIGURATION) {
    735                 usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
    736 
    737                 return process_get_configuration_request(instance, request);
    738         }
    739         return ENOTSUP;
    740 }
    741 /*----------------------------------------------------------------------------*/
    742 
    743 /**
    744  * process one of requests that carry input data
    745  *
    746  * Request can be one of USB_DEVREQ_SET_DESCRIPTOR or
    747  * USB_DEVREQ_SET_CONFIGURATION.
    748  * @param instance root hub instance
    749  * @param request structure containing both request and response information
    750  * @return error code
    751  */
    752 static int process_request_with_input(rh_t *instance,
    753     usb_transfer_batch_t *request) {
    754         usb_device_request_setup_packet_t * setup_request =
    755             (usb_device_request_setup_packet_t*) request->setup_buffer;
    756         request->transfered_size = 0;
    757         if (setup_request->request == USB_DEVREQ_SET_DESCRIPTOR) {
     543
     544        /* Enabled features to clear: see page 269 of USB specs */
     545        switch (feature)
     546        {
     547        case USB_HUB_FEATURE_PORT_POWER:          //8
     548                /* No power switching */
     549                if (instance->registers->rh_desc_a & RHDA_NPS_FLAG)
     550                        return ENOTSUP;
     551                /* Ganged power switching */
     552                if (!(instance->registers->rh_desc_a & RHDA_PSM_FLAG)) {
     553                        instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;
     554                        return EOK;
     555                }
     556                instance->registers->rh_port_status[port - 1] =
     557                        RHPS_CLEAR_PORT_POWER;
     558                return EOK;
     559
     560        case USB_HUB_FEATURE_PORT_ENABLE:         //1
     561                instance->registers->rh_port_status[port - 1] =
     562                        RHPS_CLEAR_PORT_ENABLE;
     563                return EOK;
     564
     565        case USB_HUB_FEATURE_PORT_SUSPEND:        //2
     566                instance->registers->rh_port_status[port - 1] =
     567                        RHPS_CLEAR_PORT_SUSPEND;
     568                return EOK;
     569
     570        case USB_HUB_FEATURE_C_PORT_CONNECTION:   //16
     571        case USB_HUB_FEATURE_C_PORT_ENABLE:       //17
     572        case USB_HUB_FEATURE_C_PORT_SUSPEND:      //18
     573        case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: //19
     574        case USB_HUB_FEATURE_C_PORT_RESET:        //20
     575                /* Nice thing is that these shifts correspond to the position
     576                 * of control bits in register */
     577                instance->registers->rh_port_status[port - 1] = (1 << feature);
     578                return EOK;
     579
     580        default:
    758581                return ENOTSUP;
    759582        }
    760         if (setup_request->request == USB_DEVREQ_SET_CONFIGURATION) {
    761                 //set and get configuration requests do not have any meaning,
    762                 //only dummy values are returned
    763 
    764                 return EOK;
    765         }
    766         return ENOTSUP;
    767 }
    768 /*----------------------------------------------------------------------------*/
    769 
     583}
     584/*----------------------------------------------------------------------------*/
    770585/**
    771586 * process one of requests that do not request nor carry additional data
     
    777592 * @return error code
    778593 */
    779 static int process_request_without_data(rh_t *instance,
    780     usb_transfer_batch_t *request) {
    781         usb_device_request_setup_packet_t * setup_request =
    782             (usb_device_request_setup_packet_t*) request->setup_buffer;
    783         request->transfered_size = 0;
    784         if (setup_request->request == USB_DEVREQ_CLEAR_FEATURE) {
    785                 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
    786                         usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
    787                         return process_hub_feature_clear_request(instance,
    788                             setup_request->value);
    789                 }
    790                 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
    791                         usb_log_debug2("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
    792                         return process_port_feature_clear_request(instance,
    793                             setup_request->value,
    794                             setup_request->index);
    795                 }
    796                 usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
     594int set_feature(rh_t *instance, usb_transfer_batch_t *request)
     595{
     596        assert(instance);
     597        assert(request);
     598
     599        const usb_device_request_setup_packet_t *setup_request =
     600            (usb_device_request_setup_packet_t *) request->setup_buffer;
     601        switch (setup_request->request_type)
     602        {
     603        case USB_HUB_REQ_TYPE_SET_PORT_FEATURE:
     604                usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
     605                return set_feature_port(instance,
     606                    setup_request->value, setup_request->index);
     607
     608        case USB_HUB_REQ_TYPE_SET_HUB_FEATURE:
     609                /* Chapter 11.16.2 specifies that hub can be recipient
     610                 * only for C_HUB_LOCAL_POWER and C_HUB_OVER_CURRENT
     611                 * features. It makes no sense to SET either. */
     612                usb_log_error("Invalid HUB set feature request.\n");
     613                return ENOTSUP;
     614        default:
     615                usb_log_error("Invalid set feature request type: %d\n",
    797616                    setup_request->request_type);
    798617                return EINVAL;
    799618        }
    800         if (setup_request->request == USB_DEVREQ_SET_FEATURE) {
    801                 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
    802                         usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
    803                         return process_hub_feature_set_request(instance,
    804                             setup_request->value);
     619}
     620/*----------------------------------------------------------------------------*/
     621/**
     622 * process one of requests that do not request nor carry additional data
     623 *
     624 * Request can be one of USB_DEVREQ_CLEAR_FEATURE, USB_DEVREQ_SET_FEATURE or
     625 * USB_DEVREQ_SET_ADDRESS.
     626 * @param instance root hub instance
     627 * @param request structure containing both request and response information
     628 * @return error code
     629 */
     630int clear_feature(rh_t *instance, usb_transfer_batch_t *request)
     631{
     632        assert(instance);
     633        assert(request);
     634
     635        const usb_device_request_setup_packet_t *setup_request =
     636            (usb_device_request_setup_packet_t *) request->setup_buffer;
     637        request->transfered_size = 0;
     638        switch (setup_request->request_type)
     639        {
     640        case USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE:
     641                usb_log_debug("USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE\n");
     642                return clear_feature_port(instance,
     643                    setup_request->value, setup_request->index);
     644
     645        case USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE:
     646                usb_log_debug("USB_HUB_REQ_TYPE_CLEAR_HUB_FEATURE\n");
     647                /*
     648                 * Chapter 11.16.2 specifies that only C_HUB_LOCAL_POWER and
     649                 * C_HUB_OVER_CURRENT are supported. C_HUB_OVER_CURRENT is represented
     650                 * by OHCI RHS_OCIC_FLAG. C_HUB_LOCAL_POWER is not supported
     651                 * as root hubs do not support local power status feature.
     652                 * (OHCI pg. 127) */
     653                if (setup_request->value == USB_HUB_FEATURE_C_HUB_OVER_CURRENT) {
     654                        instance->registers->rh_status = RHS_OCIC_FLAG;
     655                        TRANSFER_OK(0);
    805656                }
    806                 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
    807                         usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
    808                         return process_port_feature_set_request(instance,
    809                             setup_request->value,
    810                             setup_request->index);
    811                 }
    812                 usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
     657        default:
     658                usb_log_error("Invalid clear feature request type: %d\n",
    813659                    setup_request->request_type);
    814660                return EINVAL;
    815661        }
    816         if (setup_request->request == USB_DEVREQ_SET_ADDRESS) {
    817                 usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
    818                 return process_address_set_request(instance,
    819                     setup_request->value);
    820         }
    821         usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",
    822             setup_request->request_type);
    823 
    824         return ENOTSUP;
    825 }
    826 /*----------------------------------------------------------------------------*/
    827 
    828 /**
    829  * process hub control request
     662}
     663/*----------------------------------------------------------------------------*/
     664/**
     665 * Process hub control request.
    830666 *
    831667 * If needed, writes answer into the request structure.
     
    844680 * @return error code
    845681 */
    846 static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request) {
     682int control_request(rh_t *instance, usb_transfer_batch_t *request)
     683{
     684        assert(instance);
     685        assert(request);
     686
    847687        if (!request->setup_buffer) {
    848                 usb_log_error("root hub received empty transaction?");
     688                usb_log_error("Root hub received empty transaction!");
    849689                return EINVAL;
    850690        }
    851         int opResult;
    852         if (sizeof (usb_device_request_setup_packet_t) > request->setup_size) {
     691
     692        if (sizeof(usb_device_request_setup_packet_t) > request->setup_size) {
    853693                usb_log_error("Setup packet too small\n");
    854                 return EINVAL;
    855         }
    856         usb_log_debug("CTRL packet: %s.\n",
    857             usb_debug_str_buffer(
    858             (const uint8_t *) request->setup_buffer, 8, 8));
    859         usb_device_request_setup_packet_t * setup_request =
    860             (usb_device_request_setup_packet_t*)
    861             request->setup_buffer;
    862         switch (setup_request->request) {
    863                 case USB_DEVREQ_GET_STATUS:
    864                 case USB_DEVREQ_GET_DESCRIPTOR:
    865                 case USB_DEVREQ_GET_CONFIGURATION:
    866                         usb_log_debug2("Processing request with output\n");
    867                         opResult = process_request_with_output(
    868                             instance, request);
    869                         break;
    870                 case USB_DEVREQ_CLEAR_FEATURE:
    871                 case USB_DEVREQ_SET_FEATURE:
    872                 case USB_DEVREQ_SET_ADDRESS:
    873                         usb_log_debug2("Processing request without "
    874                             "additional data\n");
    875                         opResult = process_request_without_data(
    876                             instance, request);
    877                         break;
    878                 case USB_DEVREQ_SET_DESCRIPTOR:
    879                 case USB_DEVREQ_SET_CONFIGURATION:
    880                         usb_log_debug2("Processing request with input\n");
    881                         opResult = process_request_with_input(
    882                             instance, request);
    883 
    884                         break;
    885                 default:
    886                         usb_log_warning("Received unsupported request: %d.\n",
    887                             setup_request->request);
    888                         opResult = ENOTSUP;
    889         }
    890         return opResult;
    891 }
    892 /*----------------------------------------------------------------------------*/
    893 
    894 /**
    895  * process hanging interrupt request
    896  *
    897  * If an interrupt transfer has been received and there was no change,
    898  * the driver stores the transfer information and waits for change to occcur.
    899  * This routine is called when that happens and it finalizes the interrupt
    900  * transfer.
    901  *
    902  * @param instance hub instance
    903  * @param request batch request to be processed
    904  *
    905  * @return
    906  */
    907 static int process_interrupt_mask_in_instance(rh_t *instance,
    908     usb_transfer_batch_t * request) {
    909         memcpy(request->data_buffer, instance->interrupt_buffer,
    910             instance->interrupt_mask_size);
    911         request->transfered_size = instance->interrupt_mask_size;
    912         instance->unfinished_interrupt_transfer = NULL;
    913         usb_transfer_batch_finish_error(request, EOK);
    914 
    915         return EOK;
    916 }
    917 
    918 /*----------------------------------------------------------------------------*/
    919 
    920 /**
    921  * return whether the buffer is full of zeros
    922  *
    923  * Convenience function.
    924  * @param buffer
    925  * @param size
    926  * @return
    927  */
    928 static bool is_zeros(void *buffer, size_t size) {
    929         if (!buffer) return true;
    930         if (!size) return true;
    931         size_t i;
    932         for (i = 0; i < size; ++i) {
    933                 if (((char*) buffer)[i])
    934                         return false;
    935         }
    936         return true;
     694                return EOVERFLOW;
     695        }
     696
     697        usb_log_debug2("CTRL packet: %s.\n",
     698            usb_debug_str_buffer((uint8_t *) request->setup_buffer, 8, 8));
     699        const usb_device_request_setup_packet_t *setup_request =
     700            (usb_device_request_setup_packet_t *) request->setup_buffer;
     701        switch (setup_request->request)
     702        {
     703        case USB_DEVREQ_GET_STATUS:
     704                usb_log_debug("USB_DEVREQ_GET_STATUS\n");
     705                return get_status(instance, request);
     706
     707        case USB_DEVREQ_GET_DESCRIPTOR:
     708                usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
     709                return get_descriptor(instance, request);
     710
     711        case USB_DEVREQ_GET_CONFIGURATION:
     712                usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
     713                if (request->buffer_size != 1)
     714                        return EINVAL;
     715                request->data_buffer[0] = 1;
     716                TRANSFER_OK(1);
     717
     718        case USB_DEVREQ_CLEAR_FEATURE:
     719                usb_log_debug2("Processing request without "
     720                    "additional data\n");
     721                return clear_feature(instance, request);
     722        case USB_DEVREQ_SET_FEATURE:
     723                usb_log_debug2("Processing request without "
     724                    "additional data\n");
     725                return set_feature(instance, request);
     726
     727        case USB_DEVREQ_SET_ADDRESS:
     728                usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
     729                instance->address = setup_request->value;
     730                TRANSFER_OK(0);
     731
     732        case USB_DEVREQ_SET_CONFIGURATION:
     733                usb_log_debug("USB_DEVREQ_SET_CONFIGURATION\n");
     734                /* We don't need to do anything */
     735                TRANSFER_OK(0);
     736
     737        case USB_DEVREQ_SET_DESCRIPTOR: /* Not supported by OHCI RH */
     738        default:
     739                usb_log_error("Received unsupported request: %d.\n",
     740                    setup_request->request);
     741                return ENOTSUP;
     742        }
    937743}
    938744
  • uspace/drv/bus/usb/ohci/root_hub.h

    r3e5c48c9 r159100a  
    4141#include "batch.h"
    4242
     43#define HUB_DESCRIPTOR_MAX_SIZE (7 + 2 + 2)
     44
    4345/**
    4446 * ohci root hub representation
     
    5153        /** hub port count */
    5254        size_t port_count;
    53         /** hubs descriptors */
    54         usb_device_descriptors_t descriptors;
    5555        /** interrupt transfer waiting for an actual interrupt to occur */
    56         usb_transfer_batch_t * unfinished_interrupt_transfer;
    57         /** pre-allocated interrupt mask
    58          *
    59          * This is allocated when initializing instance, so that memory
    60          * allocation is not needed when processing request. Buffer is used for
    61          * interrupt bitmask.
    62          */
    63         uint8_t * interrupt_buffer;
     56        usb_transfer_batch_t *unfinished_interrupt_transfer;
    6457        /** size of interrupt buffer */
    6558        size_t interrupt_mask_size;
    66         /** instance`s descriptor*/
    67         uint8_t * hub_descriptor;
     59        /** Descriptors */
     60        struct {
     61                usb_standard_configuration_descriptor_t configuration;
     62                usb_standard_interface_descriptor_t interface;
     63                usb_standard_endpoint_descriptor_t endpoint;
     64                uint8_t hub[HUB_DESCRIPTOR_MAX_SIZE];
     65        } __attribute__ ((packed)) descriptors;
    6866        /** size of hub descriptor */
    69         size_t descriptor_size;
    70 
     67        size_t hub_descriptor_size;
    7168
    7269} rh_t;
    7370
    74 int rh_init(rh_t *instance, ohci_regs_t *regs);
     71void rh_init(rh_t *instance, ohci_regs_t *regs);
    7572
    76 int rh_request(rh_t *instance, usb_transfer_batch_t *request);
     73void rh_request(rh_t *instance, usb_transfer_batch_t *request);
    7774
    7875void rh_interrupt(rh_t *instance);
  • uspace/drv/bus/usb/uhci/hc.c

    r3e5c48c9 r159100a  
    4747    (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)
    4848
     49static const irq_cmd_t uhci_irq_commands[] =
     50{
     51        { .cmd = CMD_PIO_READ_16, .dstarg = 1, .addr = NULL/*filled later*/},
     52        { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2,
     53          .value = UHCI_STATUS_USED_INTERRUPTS | UHCI_STATUS_NM_INTERRUPTS },
     54        { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 },
     55        { .cmd = CMD_PIO_WRITE_A_16, .srcarg = 1, .addr = NULL/*filled later*/},
     56        { .cmd = CMD_ACCEPT },
     57};
    4958
    5059static int hc_init_transfer_lists(hc_t *instance);
     
    5463static int hc_interrupt_emulator(void *arg);
    5564static int hc_debug_checker(void *arg);
     65
     66/*----------------------------------------------------------------------------*/
     67/** Get number of commands used in IRQ code.
     68 * @return Number of commands.
     69 */
     70size_t hc_irq_cmd_count(void)
     71{
     72        return sizeof(uhci_irq_commands) / sizeof(irq_cmd_t);
     73}
     74/*----------------------------------------------------------------------------*/
     75/** Generate IRQ code commands.
     76 * @param[out] cmds Place to store the commands.
     77 * @param[in] cmd_size Size of the place (bytes).
     78 * @param[in] regs Physical address of device's registers.
     79 * @param[in] reg_size Size of the register area (bytes).
     80 *
     81 * @return Error code.
     82 */
     83int hc_get_irq_commands(
     84    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size)
     85{
     86        if (cmd_size < sizeof(uhci_irq_commands)
     87            || reg_size < sizeof(uhci_regs_t))
     88                return EOVERFLOW;
     89
     90        uhci_regs_t *registers = (uhci_regs_t*)regs;
     91
     92        memcpy(cmds, uhci_irq_commands, sizeof(uhci_irq_commands));
     93
     94        cmds[0].addr = (void*)&registers->usbsts;
     95        cmds[3].addr = (void*)&registers->usbsts;
     96        return EOK;
     97}
    5698/*----------------------------------------------------------------------------*/
    5799/** Initialize UHCI hc driver structure
     
    69111int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interrupts)
    70112{
    71         assert(reg_size >= sizeof(regs_t));
     113        assert(reg_size >= sizeof(uhci_regs_t));
    72114        int ret;
    73115
     
    82124
    83125        /* allow access to hc control registers */
    84         regs_t *io;
     126        uhci_regs_t *io;
    85127        ret = pio_enable(regs, reg_size, (void **)&io);
    86         CHECK_RET_RETURN(ret,
    87             "Failed(%d) to gain access to registers at %p: %s.\n",
    88             ret, io, str_error(ret));
     128        CHECK_RET_RETURN(ret, "Failed to gain access to registers at %p: %s.\n",
     129            io, str_error(ret));
    89130        instance->registers = io;
    90         usb_log_debug("Device registers at %p (%zuB) accessible.\n",
    91             io, reg_size);
     131        usb_log_debug(
     132            "Device registers at %p (%zuB) accessible.\n", io, reg_size);
    92133
    93134        ret = hc_init_mem_structures(instance);
    94135        CHECK_RET_RETURN(ret,
    95             "Failed(%d) to initialize UHCI memory structures: %s.\n",
    96             ret, str_error(ret));
     136            "Failed to initialize UHCI memory structures: %s.\n",
     137            str_error(ret));
    97138
    98139        hc_init_hw(instance);
     
    116157{
    117158        assert(instance);
    118         regs_t *registers = instance->registers;
     159        uhci_regs_t *registers = instance->registers;
    119160
    120161        /* Reset everything, who knows what touched it before us */
    121162        pio_write_16(&registers->usbcmd, UHCI_CMD_GLOBAL_RESET);
    122         async_usleep(10000); /* 10ms according to USB spec */
     163        async_usleep(50000); /* 50ms according to USB spec(root hub reset) */
    123164        pio_write_16(&registers->usbcmd, 0);
    124165
    125         /* Reset hc, all states and counters */
     166        /* Reset hc, all states and counters. Hope that hw is not broken */
    126167        pio_write_16(&registers->usbcmd, UHCI_CMD_HCRESET);
    127168        do { async_usleep(10); }
     
    141182        }
    142183
    143         const uint16_t status = pio_read_16(&registers->usbcmd);
    144         if (status != 0)
    145                 usb_log_warning("Previous command value: %x.\n", status);
     184        const uint16_t cmd = pio_read_16(&registers->usbcmd);
     185        if (cmd != 0)
     186                usb_log_warning("Previous command value: %x.\n", cmd);
    146187
    147188        /* Start the hc with large(64B) packet FSBR */
     
    170211        } else (void) 0
    171212
    172         /* Init interrupt code */
    173         instance->interrupt_code.cmds = instance->interrupt_commands;
    174         {
    175                 /* Read status register */
    176                 instance->interrupt_commands[0].cmd = CMD_PIO_READ_16;
    177                 instance->interrupt_commands[0].dstarg = 1;
    178                 instance->interrupt_commands[0].addr =
    179                     &instance->registers->usbsts;
    180 
    181                 /* Test whether we are the interrupt cause */
    182                 instance->interrupt_commands[1].cmd = CMD_BTEST;
    183                 instance->interrupt_commands[1].value =
    184                     UHCI_STATUS_USED_INTERRUPTS | UHCI_STATUS_NM_INTERRUPTS;
    185                 instance->interrupt_commands[1].srcarg = 1;
    186                 instance->interrupt_commands[1].dstarg = 2;
    187 
    188                 /* Predicate cleaning and accepting */
    189                 instance->interrupt_commands[2].cmd = CMD_PREDICATE;
    190                 instance->interrupt_commands[2].value = 2;
    191                 instance->interrupt_commands[2].srcarg = 2;
    192 
    193                 /* Write clean status register */
    194                 instance->interrupt_commands[3].cmd = CMD_PIO_WRITE_A_16;
    195                 instance->interrupt_commands[3].srcarg = 1;
    196                 instance->interrupt_commands[3].addr =
    197                     &instance->registers->usbsts;
    198 
    199                 /* Accept interrupt */
    200                 instance->interrupt_commands[4].cmd = CMD_ACCEPT;
    201 
    202                 instance->interrupt_code.cmdcount = UHCI_NEEDED_IRQ_COMMANDS;
    203         }
    204 
    205213        /* Init transfer lists */
    206214        int ret = hc_init_transfer_lists(instance);
    207         CHECK_RET_RETURN(ret, "Failed to init transfer lists.\n");
     215        CHECK_RET_RETURN(ret, "Failed to initialize transfer lists.\n");
    208216        usb_log_debug("Initialized transfer lists.\n");
    209 
    210         /* Init USB frame list page*/
    211         instance->frame_list = get_page();
    212         ret = instance->frame_list ? EOK : ENOMEM;
    213         CHECK_RET_RETURN(ret, "Failed to get frame list page.\n");
    214         usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
    215 
    216         /* Set all frames to point to the first queue head */
    217         const uint32_t queue = LINK_POINTER_QH(
    218                 addr_to_phys(instance->transfers_interrupt.queue_head));
    219 
    220         unsigned i = 0;
    221         for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
    222                 instance->frame_list[i] = queue;
    223         }
    224217
    225218        /* Init device keeper */
    226219        usb_device_keeper_init(&instance->manager);
    227         usb_log_debug("Initialized device manager.\n");
     220        usb_log_debug("Initialized device keeper.\n");
    228221
    229222        ret = usb_endpoint_manager_init(&instance->ep_manager,
     
    232225            str_error(ret));
    233226
     227        /* Init USB frame list page*/
     228        instance->frame_list = get_page();
     229        if (!instance->frame_list) {
     230                usb_log_error("Failed to get frame list page.\n");
     231                usb_endpoint_manager_destroy(&instance->ep_manager);
     232                return ENOMEM;
     233        }
     234        usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
     235
     236        /* Set all frames to point to the first queue head */
     237        const uint32_t queue = LINK_POINTER_QH(
     238                addr_to_phys(instance->transfers_interrupt.queue_head));
     239        unsigned i = 0;
     240        for(; i < UHCI_FRAME_LIST_COUNT; ++i) {
     241                instance->frame_list[i] = queue;
     242        }
     243
    234244        return EOK;
    235245#undef CHECK_RET_RETURN
     
    252262        int ret = transfer_list_init(&instance->transfers_##type, name); \
    253263        if (ret != EOK) { \
    254                 usb_log_error("Failed(%d) to setup %s transfer list: %s.\n", \
    255                     ret, name, str_error(ret)); \
     264                usb_log_error("Failed to setup %s transfer list: %s.\n", \
     265                    name, str_error(ret)); \
    256266                transfer_list_fini(&instance->transfers_bulk_full); \
    257267                transfer_list_fini(&instance->transfers_control_full); \
  • uspace/drv/bus/usb/uhci/hc.h

    r3e5c48c9 r159100a  
    8484        /** SOF modification to match external timers */
    8585        uint8_t sofmod;
    86 } regs_t;
     86} uhci_regs_t;
    8787
    8888#define UHCI_FRAME_LIST_COUNT 1024
     
    100100
    101101        /** Addresses of I/O registers */
    102         regs_t *registers;
     102        uhci_regs_t *registers;
    103103
    104104        /** Frame List contains 1024 link pointers */
     
    116116        /** Pointer table to the above lists, helps during scheduling */
    117117        transfer_list_t *transfers[2][4];
    118 
    119         /** Code to be executed in kernel interrupt handler */
    120         irq_code_t interrupt_code;
    121 
    122         /** Commands that form interrupt code */
    123         irq_cmd_t interrupt_commands[UHCI_NEEDED_IRQ_COMMANDS];
    124 
    125118        /** Fibril periodically checking status register*/
    126119        fid_t interrupt_emulator;
    127 
    128120        /** Indicator of hw interrupts availability */
    129121        bool hw_interrupts;
     
    132124        unsigned hw_failures;
    133125} hc_t;
    134 
     126size_t hc_irq_cmd_count(void);
     127int hc_get_irq_commands(
     128    irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size);
    135129int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interupts);
    136 
    137130int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch);
    138 
    139131void hc_interrupt(hc_t *instance, uint16_t status);
    140132
  • uspace/drv/bus/usb/uhci/root_hub.c

    r3e5c48c9 r159100a  
    5555        int ret = asprintf(&match_str, "usb&uhci&root-hub");
    5656        if (ret < 0) {
    57                 usb_log_error(
    58                     "Failed(%d) to create root hub match string: %s.\n",
    59                     ret, str_error(ret));
     57                usb_log_error("Failed to create root hub match string: %s.\n",
     58                    str_error(ret));
    6059                return ret;
    6160        }
     
    6564        if (ret != EOK) {
    6665                free(match_str);
    67                 usb_log_error("Failed(%d) to add root hub match id: %s\n",
    68                     ret, str_error(ret));
     66                usb_log_error("Failed to add root hub match id: %s\n",
     67                    str_error(ret));
    6968                return ret;
    7069        }
  • uspace/drv/bus/usb/uhci/uhci.c

    r3e5c48c9 r159100a  
    6464{
    6565        assert(dev);
    66         assert(dev->driver_data);
    6766        return dev->driver_data;
    6867}
     
    7877        assert(dev);
    7978        uhci_t *uhci = dev_to_uhci(dev);
    80         hc_t *hc = &uhci->hc;
     79        if (!uhci) {
     80                usb_log_error("Interrupt on not yet initialized device.\n");
     81                return;
     82        }
    8183        const uint16_t status = IPC_GET_ARG1(*call);
    82         assert(hc);
    83         hc_interrupt(hc, status);
     84        hc_interrupt(&uhci->hc, status);
    8485}
    8586/*----------------------------------------------------------------------------*/
     
    192193        } \
    193194        free(instance); \
     195        device->driver_data = NULL; \
    194196        usb_log_error(message); \
    195197        return ret; \
     
    222224        ret = pci_disable_legacy(device);
    223225        CHECK_RET_DEST_FREE_RETURN(ret,
    224             "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret));
     226            "Failed to disable legacy USB: %s.\n", str_error(ret));
     227
     228        const size_t cmd_count = hc_irq_cmd_count();
     229        irq_cmd_t irq_cmds[cmd_count];
     230        ret =
     231            hc_get_irq_commands(irq_cmds, sizeof(irq_cmds), reg_base, reg_size);
     232        CHECK_RET_DEST_FREE_RETURN(ret,
     233            "Failed to generate IRQ commands: %s.\n", str_error(ret));
     234
     235        irq_code_t irq_code = { .cmdcount = cmd_count, .cmds = irq_cmds };
     236
     237        /* Register handler to avoid interrupt lockup */
     238        ret = register_interrupt_handler(device, irq, irq_handler, &irq_code);
     239        CHECK_RET_DEST_FREE_RETURN(ret,
     240            "Failed to register interrupt handler: %s.\n", str_error(ret));
    225241
    226242        bool interrupts = false;
    227 #ifdef CONFIG_USBHC_NO_INTERRUPTS
    228         usb_log_warning("Interrupts disabled in OS config, " \
    229             "falling back to polling.\n");
    230 #else
    231243        ret = pci_enable_interrupts(device);
    232244        if (ret != EOK) {
    233                 usb_log_warning("Failed to enable interrupts: %s.\n",
    234                     str_error(ret));
    235                 usb_log_info("HW interrupts not available, " \
    236                     "falling back to polling.\n");
     245                usb_log_warning("Failed to enable interrupts: %s."
     246                    " Falling back to polling.\n", str_error(ret));
    237247        } else {
    238248                usb_log_debug("Hw interrupts enabled.\n");
    239249                interrupts = true;
    240250        }
    241 #endif
    242 
    243251
    244252        ret = hc_init(&instance->hc, (void*)reg_base, reg_size, interrupts);
    245253        CHECK_RET_DEST_FREE_RETURN(ret,
    246             "Failed(%d) to init uhci_hcd: %s.\n", ret, str_error(ret));
     254            "Failed to init uhci_hcd: %s.\n", str_error(ret));
     255
     256        device->driver_data = instance;
    247257
    248258#define CHECK_RET_FINI_RETURN(ret, message...) \
     
    253263} else (void)0
    254264
    255         /* It does no harm if we register this on polling */
    256         ret = register_interrupt_handler(device, irq, irq_handler,
    257             &instance->hc.interrupt_code);
    258         CHECK_RET_FINI_RETURN(ret,
    259             "Failed(%d) to register interrupt handler: %s.\n",
    260             ret, str_error(ret));
    261 
    262265        ret = ddf_fun_bind(instance->hc_fun);
    263         CHECK_RET_FINI_RETURN(ret,
    264             "Failed(%d) to bind UHCI device function: %s.\n",
    265             ret, str_error(ret));
     266        CHECK_RET_FINI_RETURN(ret, "Failed to bind UHCI device function: %s.\n",
     267            str_error(ret));
    266268
    267269        ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
     
    272274            (uintptr_t)instance->hc.registers + 0x10, 4);
    273275        CHECK_RET_FINI_RETURN(ret,
    274             "Failed(%d) to setup UHCI root hub: %s.\n", ret, str_error(ret));
     276            "Failed to setup UHCI root hub: %s.\n", str_error(ret));
    275277
    276278        ret = ddf_fun_bind(instance->rh_fun);
    277279        CHECK_RET_FINI_RETURN(ret,
    278             "Failed(%d) to register UHCI root hub: %s.\n", ret, str_error(ret));
    279 
    280         device->driver_data = instance;
     280            "Failed to register UHCI root hub: %s.\n", str_error(ret));
     281
    281282        return EOK;
    282283#undef CHECK_RET_FINI_RETURN
  • uspace/drv/bus/usb/usbhub/usbhub.c

    r3e5c48c9 r159100a  
    220220 * @return error code
    221221 */
    222 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info) {
     222int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info)
     223{
    223224        // get hub descriptor
    224         usb_log_debug("Creating serialized descriptor\n");
     225        usb_log_debug("Retrieving descriptor\n");
    225226        uint8_t serialized_descriptor[USB_HUB_MAX_DESCRIPTOR_SIZE];
    226         usb_hub_descriptor_t * descriptor;
    227227        int opResult;
    228228
     
    234234
    235235        if (opResult != EOK) {
    236                 usb_log_error("Failed when receiving hub descriptor, "
    237                     "%s\n",
    238                     str_error(opResult));
    239                 free(serialized_descriptor);
     236                usb_log_error("Failed to receive hub descriptor: %s.\n",
     237                    str_error(opResult));
    240238                return opResult;
    241239        }
    242         usb_log_debug2("Deserializing descriptor\n");
    243         descriptor = usb_create_deserialized_hub_desriptor(
    244             serialized_descriptor);
    245         if (descriptor == NULL) {
    246                 usb_log_warning("could not deserialize descriptor \n");
    247                 return ENOMEM;
    248         }
    249         usb_log_debug("setting port count to %d\n", descriptor->ports_count);
    250         hub_info->port_count = descriptor->ports_count;
    251         bool is_power_switched =
    252             ((descriptor->hub_characteristics & 1) == 0);
    253         bool has_individual_port_powering =
    254             ((descriptor->hub_characteristics & 1) != 0);
    255         hub_info->ports = malloc(
    256             sizeof (usb_hub_port_t) * (hub_info->port_count + 1));
     240        usb_log_debug2("Parsing descriptor\n");
     241        usb_hub_descriptor_t descriptor;
     242        opResult = usb_deserialize_hub_desriptor(
     243                serialized_descriptor, received_size, &descriptor);
     244        if (opResult != EOK) {
     245                usb_log_error("Could not parse descriptor: %s\n",
     246                    str_error(opResult));
     247                return opResult;
     248        }
     249        usb_log_debug("Setting port count to %d.\n", descriptor.ports_count);
     250        hub_info->port_count = descriptor.ports_count;
     251
     252        hub_info->ports =
     253            malloc(sizeof(usb_hub_port_t) * (hub_info->port_count + 1));
    257254        if (!hub_info->ports) {
    258255                return ENOMEM;
    259256        }
     257
    260258        size_t port;
    261259        for (port = 0; port < hub_info->port_count + 1; ++port) {
    262260                usb_hub_port_init(&hub_info->ports[port]);
    263261        }
     262
     263        const bool is_power_switched =
     264            !(descriptor.hub_characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG);
    264265        if (is_power_switched) {
    265266                usb_log_debug("Hub power switched\n");
    266 
    267                 if (!has_individual_port_powering) {
    268                         //this setting actually makes no difference
    269                         usb_log_debug("Hub has global powering\n");
    270                 }
     267                const bool per_port_power = descriptor.hub_characteristics
     268                    & HUB_CHAR_POWER_PER_PORT_FLAG;
    271269
    272270                for (port = 1; port <= hub_info->port_count; ++port) {
    273271                        usb_log_debug("Powering port %zu.\n", port);
    274                         opResult = usb_hub_set_port_feature(hub_info->control_pipe,
     272                        opResult = usb_hub_set_port_feature(
     273                            hub_info->control_pipe,
    275274                            port, USB_HUB_FEATURE_PORT_POWER);
    276275                        if (opResult != EOK) {
    277276                                usb_log_error("Cannot power on port %zu: %s.\n",
    278277                                    port, str_error(opResult));
     278                        } else {
     279                                if (!per_port_power) {
     280                                        usb_log_debug(
     281                                            "Ganged power switching mode, "
     282                                            "one port is enough.\n");
     283                                        break;
     284                                }
    279285                        }
    280286                }
     
    283289                usb_log_debug("Power not switched, not going to be powered\n");
    284290        }
    285         usb_log_debug2("Freeing data\n");
    286         free(descriptor);
    287291        return EOK;
    288292}
  • uspace/drv/bus/usb/usbhub/usbhub_private.h

    r3e5c48c9 r159100a  
    171171    void * serialized_descriptor);
    172172
    173 usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor(
    174     void * serialized_descriptor);
    175 
    176 void usb_deserialize_hub_desriptor(void * serialized_descriptor,
    177     usb_hub_descriptor_t * descriptor);
     173int usb_deserialize_hub_desriptor(
     174    void *serialized_descriptor, size_t size, usb_hub_descriptor_t *descriptor);
    178175
    179176
  • uspace/drv/bus/usb/usbhub/utils.c

    r3e5c48c9 r159100a  
    110110}
    111111
     112/*----------------------------------------------------------------------------*/
    112113/**
    113  * create deserialized desriptor structure out of serialized descriptor
     114 * Deserialize descriptor into given pointer
    114115 *
    115  * The serialized descriptor must be proper usb hub descriptor,
    116  * otherwise an eerror might occur.
    117  *
    118  * @param sdescriptor serialized descriptor
    119  * @return newly created deserialized descriptor pointer
    120  */
    121 usb_hub_descriptor_t * usb_create_deserialized_hub_desriptor(
    122     void *serialized_descriptor) {
    123         uint8_t * sdescriptor = serialized_descriptor;
    124 
    125         if (sdescriptor[1] != USB_DESCTYPE_HUB) {
    126                 usb_log_warning("trying to deserialize wrong descriptor %x\n",
    127                     sdescriptor[1]);
    128                 return NULL;
    129         }
    130 
    131         usb_hub_descriptor_t * result = malloc(sizeof (usb_hub_descriptor_t));
    132         if (result)
    133                 usb_deserialize_hub_desriptor(serialized_descriptor, result);
    134         return result;
    135 }
    136 
    137 /**
    138  * deserialize descriptor into given pointer
    139  *
    140116 * @param serialized_descriptor
    141117 * @param descriptor
    142118 * @return
    143119 */
    144 void usb_deserialize_hub_desriptor(
    145     void * serialized_descriptor, usb_hub_descriptor_t *descriptor) {
     120int usb_deserialize_hub_desriptor(
     121    void *serialized_descriptor, size_t size, usb_hub_descriptor_t *descriptor)
     122{
    146123        uint8_t * sdescriptor = serialized_descriptor;
     124
     125        if (sdescriptor[1] != USB_DESCTYPE_HUB) {
     126                usb_log_error("Trying to deserialize wrong descriptor %x\n",
     127                    sdescriptor[1]);
     128                return EINVAL;
     129        }
     130        if (size < 7) {
     131                usb_log_error("Serialized descriptor too small.\n");
     132                return EOVERFLOW;
     133        }
     134
    147135        descriptor->ports_count = sdescriptor[2];
    148         /// @fixme handling of endianness??
    149         descriptor->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
     136        descriptor->hub_characteristics = sdescriptor[3] + 256 * sdescriptor[4];
    150137        descriptor->pwr_on_2_good_time = sdescriptor[5];
    151138        descriptor->current_requirement = sdescriptor[6];
    152         size_t var_size = (descriptor->ports_count + 7) / 8;
     139        const size_t var_size = (descriptor->ports_count + 7) / 8;
    153140        //descriptor->devices_removable = (uint8_t*) malloc(var_size);
    154141
    155         size_t i;
    156         for (i = 0; i < var_size; ++i) {
     142        if (size < (7 + var_size)) {
     143                usb_log_error("Serialized descriptor too small.\n");
     144                return EOVERFLOW;
     145        }
     146        size_t i = 0;
     147        for (; i < var_size; ++i) {
    157148                descriptor->devices_removable[i] = sdescriptor[7 + i];
    158149        }
     150        return EOK;
    159151}
    160 
     152/*----------------------------------------------------------------------------*/
    161153/**
    162154 * @}
  • uspace/drv/bus/usb/vhc/connhost.c

    r3e5c48c9 r159100a  
    141141    size_t max_packet_size, unsigned int interval)
    142142{
    143         VHC_DATA(vhc, fun);
    144 
    145         endpoint_t *ep = malloc(sizeof(endpoint_t));
     143        /* TODO: Use usb_endpoint_manager_add_ep */
     144        VHC_DATA(vhc, fun);
     145
     146        endpoint_t *ep = endpoint_get(
     147            address, endpoint, direction, transfer_type, USB_SPEED_FULL, 1);
    146148        if (ep == NULL) {
    147149                return ENOMEM;
    148150        }
    149151
    150         int rc = endpoint_init(ep, address, endpoint, direction, transfer_type,
    151             USB_SPEED_FULL, 1);
    152         if (rc != EOK) {
    153                 free(ep);
    154                 return rc;
    155         }
    156 
    157         rc = usb_endpoint_manager_register_ep(&vhc->ep_manager, ep, 1);
     152        int rc = usb_endpoint_manager_register_ep(&vhc->ep_manager, ep, 1);
    158153        if (rc != EOK) {
    159154                endpoint_destroy(ep);
  • uspace/lib/usb/include/usb/classes/hub.h

    r3e5c48c9 r159100a  
    119119     */
    120120    uint16_t hub_characteristics;
     121#define HUB_CHAR_POWER_PER_PORT_FLAG  (1 << 0)
     122#define HUB_CHAR_NO_POWER_SWITCH_FLAG (1 << 1)
    121123
    122124    /**
  • uspace/lib/usbhost/include/usb/host/endpoint.h

    r3e5c48c9 r159100a  
    6161} endpoint_t;
    6262
    63 int endpoint_init(endpoint_t *instance, usb_address_t address,
    64     usb_endpoint_t endpoint, usb_direction_t direction,
    65     usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size);
     63endpoint_t * endpoint_get(usb_address_t address, usb_endpoint_t endpoint,
     64    usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed,
     65    size_t max_packet_size);
    6666
    6767void endpoint_destroy(endpoint_t *instance);
  • uspace/lib/usbhost/include/usb/host/usb_endpoint_manager.h

    r3e5c48c9 r159100a  
    8282    size_t data_size)
    8383{
    84         endpoint_t *ep = malloc(sizeof(endpoint_t));
    85         if (ep == NULL)
     84        endpoint_t *ep = endpoint_get(
     85            address, endpoint, direction, type, speed, max_packet_size);
     86        if (!ep)
    8687                return ENOMEM;
    8788
    88         int ret = endpoint_init(ep, address, endpoint, direction, type, speed,
    89             max_packet_size);
    90         if (ret != EOK) {
    91                 free(ep);
    92                 return ret;
    93         }
    94 
    95         ret = usb_endpoint_manager_register_ep(instance, ep, data_size);
     89        const int ret =
     90            usb_endpoint_manager_register_ep(instance, ep, data_size);
    9691        if (ret != EOK) {
    9792                endpoint_destroy(ep);
    98                 return ret;
    9993        }
    100         return EOK;
     94        return ret;
    10195}
    10296#endif
  • uspace/lib/usbhost/src/batch.c

    r3e5c48c9 r159100a  
    109109        assert(instance);
    110110        assert(instance->ep);
     111        assert(instance->next_step);
    111112        endpoint_release(instance->ep);
    112113        instance->next_step(instance);
  • uspace/lib/usbhost/src/endpoint.c

    r3e5c48c9 r159100a  
    3939#include <usb/host/endpoint.h>
    4040
    41 int endpoint_init(endpoint_t *instance, usb_address_t address,
    42     usb_endpoint_t endpoint, usb_direction_t direction,
    43     usb_transfer_type_t type, usb_speed_t speed, size_t max_packet_size)
     41endpoint_t * endpoint_get(usb_address_t address, usb_endpoint_t endpoint,
     42    usb_direction_t direction, usb_transfer_type_t type, usb_speed_t speed,
     43    size_t max_packet_size)
    4444{
    45         assert(instance);
    46         instance->address = address;
    47         instance->endpoint = endpoint;
    48         instance->direction = direction;
    49         instance->transfer_type = type;
    50         instance->speed = speed;
    51         instance->max_packet_size = max_packet_size;
    52         instance->toggle = 0;
    53         instance->active = false;
    54         fibril_mutex_initialize(&instance->guard);
    55         fibril_condvar_initialize(&instance->avail);
    56         endpoint_clear_hc_data(instance);
    57         return EOK;
     45        endpoint_t *instance = malloc(sizeof(endpoint_t));
     46        if (instance) {
     47                instance->address = address;
     48                instance->endpoint = endpoint;
     49                instance->direction = direction;
     50                instance->transfer_type = type;
     51                instance->speed = speed;
     52                instance->max_packet_size = max_packet_size;
     53                instance->toggle = 0;
     54                instance->active = false;
     55                fibril_mutex_initialize(&instance->guard);
     56                fibril_condvar_initialize(&instance->avail);
     57                endpoint_clear_hc_data(instance);
     58        }
     59        return instance;
    5860}
    5961/*----------------------------------------------------------------------------*/
Note: See TracChangeset for help on using the changeset viewer.