Changeset 8ff0bd2 in mainline for uspace/drv/bus/usb/ohci/hc.c


Ignore:
Timestamp:
2011-09-04T11:30:58Z (14 years ago)
Author:
Maurizio Lombardi <m.lombardi85@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
03bc76a
Parents:
d2c67e7 (diff), deac215e (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 mainline changes

File:
1 moved

Legend:

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

    rd2c67e7 r8ff0bd2  
    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
     
    65130            device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
    66131        if (hub_address <= 0) {
    67                 usb_log_error("Failed(%d) to get OHCI root hub address.\n",
    68                     hub_address);
     132                usb_log_error("Failed to get OHCI root hub address: %s\n",
     133                    str_error(hub_address));
    69134                return hub_address;
    70135        }
     
    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
     
    357417                    instance->registers->periodic_current);
    358418
    359                 link_t *current = instance->pending_batches.next;
    360                 while (current != &instance->pending_batches) {
     419                link_t *current = instance->pending_batches.head.next;
     420                while (current != &instance->pending_batches.head) {
    361421                        link_t *next = current->next;
    362422                        usb_transfer_batch_t *batch =
     
    367427                                usb_transfer_batch_finish(batch);
    368428                        }
     429
    369430                        current = next;
    370431                }
     
    373434
    374435        if (status & I_UE) {
    375                 hc_start_hw(instance);
     436                hc_start(instance);
    376437        }
    377438
     
    398459/** Turn off any (BIOS)driver that might be in control of the device.
    399460 *
     461 * This function implements routines described in chapter 5.1.1.3 of the OHCI
     462 * specification (page 40, pdf page 54).
     463 *
    400464 * @param[in] instance OHCI hc driver structure.
    401465 */
     
    403467{
    404468        assert(instance);
     469
    405470        usb_log_debug("Requesting OHCI control.\n");
    406         /* Turn off legacy emulation */
    407         volatile uint32_t *ohci_emulation_reg =
    408             (uint32_t*)((char*)instance->registers + 0x100);
    409         usb_log_debug("OHCI legacy register %p: %x.\n",
    410             ohci_emulation_reg, *ohci_emulation_reg);
    411         /* Do not change A20 state */
    412         *ohci_emulation_reg &= 0x100;
    413         usb_log_debug("OHCI legacy register %p: %x.\n",
    414             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        }
    415487
    416488        /* Interrupt routing enabled => smm driver is active */
     
    418490                usb_log_debug("SMM driver: request ownership change.\n");
    419491                instance->registers->command_status |= CS_OCR;
     492                /* Hope that SMM actually knows its stuff or we can hang here */
    420493                while (instance->registers->control & C_IR) {
    421494                        async_usleep(1000);
    422495                }
    423496                usb_log_info("SMM driver: Ownership taken.\n");
    424                 instance->registers->control &= (C_HCFS_RESET << C_HCFS_SHIFT);
     497                C_HCFS_SET(instance->registers->control, C_HCFS_RESET);
    425498                async_usleep(50000);
    426499                return;
    427500        }
    428501
    429         const unsigned hc_status =
    430             (instance->registers->control >> C_HCFS_SHIFT) & C_HCFS_MASK;
     502        const unsigned hc_status = C_HCFS_GET(instance->registers->control);
    431503        /* Interrupt routing disabled && status != USB_RESET => BIOS active */
    432504        if (hc_status != C_HCFS_RESET) {
     
    436508                        return;
    437509                }
    438                 /* HC is suspended assert resume for 20ms */
    439                 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);
    440512                async_usleep(20000);
    441513                usb_log_info("BIOS driver: HC resumed.\n");
     
    445517        /* HC is in reset (hw startup) => no other driver
    446518         * maintain reset for at least the time specified in USB spec (50 ms)*/
    447         usb_log_info("HC found in reset.\n");
     519        usb_log_debug("Host controller found in reset state.\n");
    448520        async_usleep(50000);
    449521}
     
    453525 * @param[in] instance OHCI hc driver structure.
    454526 */
    455 void hc_start_hw(hc_t *instance)
     527void hc_start(hc_t *instance)
    456528{
    457529        /* OHCI guide page 42 */
     
    515587            instance->registers->periodic_start, frame_length);
    516588
    517         instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT);
    518         usb_log_info("OHCI HC up and running(%x).\n",
     589        C_HCFS_SET(instance->registers->control, C_HCFS_OPERATIONAL);
     590        usb_log_debug("OHCI HC up and running (ctl_reg=0x%x).\n",
    519591            instance->registers->control);
    520592}
     
    533605        int ret = endpoint_list_init(&instance->lists[type], name); \
    534606        if (ret != EOK) { \
    535                 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
    536                     ret, name); \
     607                usb_log_error("Failed to setup %s endpoint list: %s.\n", \
     608                    name, str_error(ret)); \
    537609                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]);\
    538610                endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
     
    586658            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    587659
    588         /* Init interrupt code */
    589         instance->interrupt_code.cmds = instance->interrupt_commands;
    590         instance->interrupt_code.cmdcount = OHCI_NEEDED_IRQ_COMMANDS;
    591         {
    592                 /* Read status register */
    593                 instance->interrupt_commands[0].cmd = CMD_MEM_READ_32;
    594                 instance->interrupt_commands[0].dstarg = 1;
    595                 instance->interrupt_commands[0].addr =
    596                     (void*)&instance->registers->interrupt_status;
    597 
    598                 /* Test whether we are the interrupt cause */
    599                 instance->interrupt_commands[1].cmd = CMD_BTEST;
    600                 instance->interrupt_commands[1].value =
    601                     OHCI_USED_INTERRUPTS;
    602                 instance->interrupt_commands[1].srcarg = 1;
    603                 instance->interrupt_commands[1].dstarg = 2;
    604 
    605                 /* Predicate cleaning and accepting */
    606                 instance->interrupt_commands[2].cmd = CMD_PREDICATE;
    607                 instance->interrupt_commands[2].value = 2;
    608                 instance->interrupt_commands[2].srcarg = 2;
    609 
    610                 /* Write-clean status register */
    611                 instance->interrupt_commands[3].cmd = CMD_MEM_WRITE_A_32;
    612                 instance->interrupt_commands[3].srcarg = 1;
    613                 instance->interrupt_commands[3].addr =
    614                     (void*)&instance->registers->interrupt_status;
    615 
    616                 /* Accept interrupt */
    617                 instance->interrupt_commands[4].cmd = CMD_ACCEPT;
    618         }
    619 
    620         return EOK;
    621 }
     660        return EOK;
     661}
     662
    622663/**
    623664 * @}
Note: See TracChangeset for help on using the changeset viewer.