Changeset 6c69d19 in mainline for uspace/drv/bus/usb/ohci/hc.c


Ignore:
Timestamp:
2011-07-25T20:34:17Z (13 years ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
00c2de63, c936c7f
Parents:
5889fc74 (diff), d542aad (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 libposix.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/ohci/hc.c

    r5889fc74 r6c69d19  
    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);
    86 
    87         char *match_str = NULL;
    88         /* DDF needs heap allocated string */
    89         ret = asprintf(&match_str, "usb&class=hub");
    90         ret = ret > 0 ? 0 : ret;
    91         CHECK_RET_RELEASE(ret, "Failed(%d) to create match-id string.\n", ret);
    92 
    93         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);
     150        CHECK_RET_RELEASE(ret,
     151            "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret));
     152
     153        ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
     154        CHECK_RET_RELEASE(ret,
     155            "Failed to add root hub match-id: %s.\n", str_error(ret));
    95156
    96157        ret = ddf_fun_bind(hub_fun);
    97         CHECK_RET_RELEASE(ret, "Failed(%d) to bind root hub function.\n", ret);
     158        CHECK_RET_RELEASE(ret,
     159            "Failed to bind root hub function: %s.\n", str_error(ret));
    98160
    99161        return EOK;
     
    112174{
    113175        assert(instance);
    114         int ret = EOK;
     176
    115177#define CHECK_RET_RETURN(ret, message...) \
    116178if (ret != EOK) { \
     
    119181} else (void)0
    120182
    121         ret = pio_enable((void*)regs, reg_size, (void**)&instance->registers);
     183        int ret =
     184            pio_enable((void*)regs, reg_size, (void**)&instance->registers);
    122185        CHECK_RET_RETURN(ret,
    123             "Failed(%d) to gain access to device registers: %s.\n",
    124             ret, str_error(ret));
     186            "Failed to gain access to device registers: %s.\n", str_error(ret));
    125187
    126188        list_initialize(&instance->pending_batches);
    127189        usb_device_keeper_init(&instance->manager);
     190
    128191        ret = usb_endpoint_manager_init(&instance->ep_manager,
    129192            BANDWIDTH_AVAILABLE_USB11);
     
    137200
    138201        fibril_mutex_initialize(&instance->guard);
     202
    139203        hc_gain_control(instance);
    140 
    141         rh_init(&instance->rh, instance->registers);
    142204
    143205        if (!interrupts) {
     
    147209        }
    148210
    149         return EOK;
    150 }
    151 /*----------------------------------------------------------------------------*/
    152 /** Create end register endpoint structures
     211        rh_init(&instance->rh, instance->registers);
     212        hc_start(instance);
     213
     214        return EOK;
     215}
     216/*----------------------------------------------------------------------------*/
     217/** Create and register endpoint structures.
    153218 *
    154219 * @param[in] instance OHCI driver structure.
     
    168233    size_t mps, size_t size, unsigned interval)
    169234{
    170         endpoint_t *ep = malloc(sizeof(endpoint_t));
     235        endpoint_t *ep =
     236            endpoint_get(address, endpoint, direction, type, speed, mps);
    171237        if (ep == NULL)
    172238                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         }
    179239
    180240        hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
     
    184244        }
    185245
    186         ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
     246        int ret =
     247            usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
    187248        if (ret != EOK) {
    188249                hcd_endpoint_clear(ep);
     
    212273                    &instance->lists[ep->transfer_type], hcd_ep);
    213274                instance->registers->control |= C_PLE | C_IE;
    214                 break;
    215         default:
    216275                break;
    217276        }
     
    312371        /* Check for root hub communication */
    313372        if (batch->ep->address == instance->rh.address) {
    314                 return rh_request(&instance->rh, batch);
     373                rh_request(&instance->rh, batch);
     374                return EOK;
    315375        }
    316376
     
    374434
    375435        if (status & I_UE) {
    376                 hc_start_hw(instance);
     436                hc_start(instance);
    377437        }
    378438
     
    399459/** Turn off any (BIOS)driver that might be in control of the device.
    400460 *
     461 * This function implements routines described in chapter 5.1.1.3 of the OHCI
     462 * specification (page 40, pdf page 54).
     463 *
    401464 * @param[in] instance OHCI hc driver structure.
    402465 */
     
    404467{
    405468        assert(instance);
     469
    406470        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);
     471        if (instance->registers->revision & R_LEGACY_FLAG) {
     472                /* Turn off legacy emulation, it should be enough to zero
     473                 * the lowest bit, but it caused problems. Thus clear all
     474                 * except GateA20 (causes restart on some hw).
     475                 * See page 145 of the specs for details.
     476                 */
     477                volatile uint32_t *ohci_emulation_reg =
     478                (uint32_t*)((char*)instance->registers + LEGACY_REGS_OFFSET);
     479                usb_log_debug("OHCI legacy register %p: %x.\n",
     480                    ohci_emulation_reg, *ohci_emulation_reg);
     481                /* Zero everything but A20State */
     482                *ohci_emulation_reg &= 0x100;
     483                usb_log_debug(
     484                    "OHCI legacy register (should be 0 or 0x100) %p: %x.\n",
     485                    ohci_emulation_reg, *ohci_emulation_reg);
     486        }
    416487
    417488        /* Interrupt routing enabled => smm driver is active */
     
    419490                usb_log_debug("SMM driver: request ownership change.\n");
    420491                instance->registers->command_status |= CS_OCR;
     492                /* Hope that SMM actually knows its stuff or we can hang here */
    421493                while (instance->registers->control & C_IR) {
    422494                        async_usleep(1000);
    423495                }
    424496                usb_log_info("SMM driver: Ownership taken.\n");
    425                 instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
     497                C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
    426498                async_usleep(50000);
    427499                return;
    428500        }
    429501
    430         const unsigned hc_status =
    431             (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
     502        const unsigned hc_status = C_HCFS_GET(instance->registers->control);
    432503        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    433504        if (hc_status != C_HCFS_RESET) {
     
    437508                        return;
    438509                }
    439                 /* HC is suspended assert resume for 20ms */
    440                 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT);
     510                /* HC is suspended assert resume for 20ms, */
     511                C_HCFS_SET(instance->registers->control, C_HCFS_RESUME);
    441512                async_usleep(20000);
    442513                usb_log_info("BIOS driver: HC resumed.\n");
     
    454525 * @param[in] instance OHCI hc driver structure.
    455526 */
    456 void hc_start_hw(hc_t *instance)
     527void hc_start(hc_t *instance)
    457528{
    458529        /* OHCI guide page 42 */
     
    516587            instance->registers->periodic_start, frame_length);
    517588
    518         instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
     589        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
    519590        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
    520591            instance->registers->control);
     
    534605        int ret = endpoint_list_init(&instance->lists[type], name); \
    535606        if (ret != EOK) { \
    536                 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
    537                     ret, name); \
     607                usb_log_error("Failed to setup %s endpoint list: %s.\n", \
     608                    name, str_error(ret)); \
    538609                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
    539610                endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
     
    587658            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    588659
    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 }
     660        return EOK;
     661}
     662
    623663/**
    624664 * @}
Note: See TracChangeset for help on using the changeset viewer.