Ignore:
File:
1 edited

Legend:

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

    ref9460b rd57122c  
    4242
    4343#include "hc.h"
    44 #include "hcd_endpoint.h"
     44#include "ohci_endpoint.h"
    4545
    4646#define OHCI_USED_INTERRUPTS \
    4747    (I_SO | I_WDH | I_UE | I_RHSC)
    4848
    49 static const irq_cmd_t ohci_irq_commands[] =
    50 {
    51         { .cmd = CMD_MEM_READ_32, .dstarg = 1, .addr = NULL /*filled later*/ },
     49static const irq_pio_range_t ohci_pio_ranges[] = {
     50        {
     51                .base = 0,      /* filled later */
     52                .size = sizeof(ohci_regs_t)
     53        }
     54};
     55
     56static const irq_cmd_t ohci_irq_commands[] = {
     57        { .cmd = CMD_PIO_READ_32, .dstarg = 1, .addr = NULL /* filled later */ },
    5258        { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS },
    5359        { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 },
    54         { .cmd = CMD_MEM_WRITE_A_32, .srcarg = 1, .addr = NULL /*filled later*/ },
     60        { .cmd = CMD_PIO_WRITE_A_32, .srcarg = 1, .addr = NULL /* filled later */ },
    5561        { .cmd = CMD_ACCEPT },
    5662};
     
    6167static int hc_init_memory(hc_t *instance);
    6268static int interrupt_emulator(hc_t *instance);
    63 
     69static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
     70/*----------------------------------------------------------------------------*/
     71/** Get number of PIO ranges used in IRQ code.
     72 * @return Number of ranges.
     73 */
     74size_t hc_irq_pio_range_count(void)
     75{
     76        return sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t);
     77}
     78/*----------------------------------------------------------------------------*/
    6479/*----------------------------------------------------------------------------*/
    6580/** Get number of commands used in IRQ code.
     
    7186}
    7287/*----------------------------------------------------------------------------*/
    73 /** Generate IRQ code commands.
    74  * @param[out] cmds Place to store the commands.
    75  * @param[in] cmd_size Size of the place (bytes).
     88/** Generate IRQ code.
     89 * @param[out] ranges PIO ranges buffer.
     90 * @param[in] ranges_size Size of the ranges buffer (bytes).
     91 * @param[out] cmds Commands buffer.
     92 * @param[in] cmds_size Size of the commands buffer (bytes).
    7693 * @param[in] regs Physical address of device's registers.
    7794 * @param[in] reg_size Size of the register area (bytes).
     
    7996 * @return Error code.
    8097 */
    81 int 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))
     98int
     99hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[],
     100    size_t cmds_size, uintptr_t regs, size_t reg_size)
     101{
     102        if ((ranges_size < sizeof(ohci_pio_ranges)) ||
     103            (cmds_size < sizeof(ohci_irq_commands)) ||
     104            (reg_size < sizeof(ohci_regs_t)))
    86105                return EOVERFLOW;
    87106
    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;
     107        memcpy(ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges));
     108        ranges[0].base = regs;
    109109
    110110        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;
     111        ohci_regs_t *registers = (ohci_regs_t *) regs;
     112        cmds[0].addr = (void *) &registers->interrupt_status;
     113        cmds[3].addr = (void *) &registers->interrupt_status;
     114
    115115        return EOK;
    116116}
     
    127127        assert(hub_fun);
    128128
    129         const usb_address_t hub_address =
    130             device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
    131         if (hub_address <= 0) {
     129        /* Try to get address 1 for root hub. */
     130        instance->rh.address = 1;
     131        int ret = usb_device_manager_request_address(
     132            &instance->generic.dev_manager, &instance->rh.address, false,
     133            USB_SPEED_FULL);
     134        if (ret != EOK) {
    132135                usb_log_error("Failed to get OHCI root hub address: %s\n",
    133                     str_error(hub_address));
    134                 return hub_address;
    135         }
    136         instance->rh.address = hub_address;
    137         usb_device_keeper_bind(
    138             &instance->manager, hub_address, hub_fun->handle);
    139 
    140 #define CHECK_RET_RELEASE(ret, message...) \
     136                    str_error(ret));
     137                return ret;
     138        }
     139
     140#define CHECK_RET_UNREG_RETURN(ret, message...) \
    141141if (ret != EOK) { \
    142142        usb_log_error(message); \
    143         hc_remove_endpoint(instance, hub_address, 0, USB_DIRECTION_BOTH); \
    144         usb_device_keeper_release(&instance->manager, hub_address); \
     143        usb_endpoint_manager_remove_ep( \
     144            &instance->generic.ep_manager, instance->rh.address, 0, \
     145            USB_DIRECTION_BOTH, NULL, NULL); \
     146        usb_device_manager_release_address( \
     147            &instance->generic.dev_manager, instance->rh.address); \
    145148        return ret; \
    146149} else (void)0
    147150
    148         int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
    149             USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
    150         CHECK_RET_RELEASE(ret,
    151             "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret));
     151        ret = usb_endpoint_manager_add_ep(
     152            &instance->generic.ep_manager, instance->rh.address, 0,
     153            USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64,
     154            0, NULL, NULL);
     155        CHECK_RET_UNREG_RETURN(ret,
     156            "Failed to register root hub control endpoint: %s.\n",
     157            str_error(ret));
    152158
    153159        ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
    154         CHECK_RET_RELEASE(ret,
     160        CHECK_RET_UNREG_RETURN(ret,
    155161            "Failed to add root hub match-id: %s.\n", str_error(ret));
    156162
    157163        ret = ddf_fun_bind(hub_fun);
    158         CHECK_RET_RELEASE(ret,
     164        CHECK_RET_UNREG_RETURN(ret,
    159165            "Failed to bind root hub function: %s.\n", str_error(ret));
     166
     167        ret = usb_device_manager_bind_address(&instance->generic.dev_manager,
     168            instance->rh.address, hub_fun->handle);
     169        if (ret != EOK)
     170                usb_log_warning("Failed to bind root hub address: %s.\n",
     171                    str_error(ret));
    160172
    161173        return EOK;
     
    187199
    188200        list_initialize(&instance->pending_batches);
    189         usb_device_keeper_init(&instance->manager);
    190 
    191         ret = usb_endpoint_manager_init(&instance->ep_manager,
    192             BANDWIDTH_AVAILABLE_USB11);
    193         CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
    194             str_error(ret));
     201
     202        hcd_init(&instance->generic, USB_SPEED_FULL,
     203            BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
     204        instance->generic.private_data = instance;
     205        instance->generic.schedule = hc_schedule;
     206        instance->generic.ep_add_hook = ohci_endpoint_init;
     207        instance->generic.ep_remove_hook = ohci_endpoint_fini;
    195208
    196209        ret = hc_init_memory(instance);
     
    215228}
    216229/*----------------------------------------------------------------------------*/
    217 /** Create and register endpoint structures.
    218  *
    219  * @param[in] instance OHCI driver structure.
    220  * @param[in] address USB address of the device.
    221  * @param[in] endpoint USB endpoint number.
    222  * @param[in] speed Communication speeed of the device.
    223  * @param[in] type Endpoint's transfer type.
    224  * @param[in] direction Endpoint's direction.
    225  * @param[in] mps Maximum packet size the endpoint accepts.
    226  * @param[in] size Maximum allowed buffer size.
    227  * @param[in] interval Time between transfers(interrupt transfers only).
    228  * @return Error code
    229  */
    230 int hc_add_endpoint(
    231     hc_t *instance, usb_address_t address, usb_endpoint_t endpoint,
    232     usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
    233     size_t mps, size_t size, unsigned interval)
    234 {
    235         endpoint_t *ep =
    236             endpoint_get(address, endpoint, direction, type, speed, mps);
    237         if (ep == NULL)
    238                 return ENOMEM;
    239 
    240         hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
    241         if (hcd_ep == NULL) {
    242                 endpoint_destroy(ep);
    243                 return ENOMEM;
    244         }
    245 
    246         int ret =
    247             usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
    248         if (ret != EOK) {
    249                 hcd_endpoint_clear(ep);
    250                 endpoint_destroy(ep);
    251                 return ret;
    252         }
    253 
    254         /* Enqueue hcd_ep */
     230void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
     231{
     232        assert(instance);
     233        assert(ep);
     234
     235        endpoint_list_t *list = &instance->lists[ep->transfer_type];
     236        ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
     237        assert(list);
     238        assert(ohci_ep);
     239
     240        /* Enqueue ep */
    255241        switch (ep->transfer_type) {
    256242        case USB_TRANSFER_CONTROL:
    257243                instance->registers->control &= ~C_CLE;
    258                 endpoint_list_add_ep(
    259                     &instance->lists[ep->transfer_type], hcd_ep);
     244                endpoint_list_add_ep(list, ohci_ep);
    260245                instance->registers->control_current = 0;
    261246                instance->registers->control |= C_CLE;
     
    263248        case USB_TRANSFER_BULK:
    264249                instance->registers->control &= ~C_BLE;
    265                 endpoint_list_add_ep(
    266                     &instance->lists[ep->transfer_type], hcd_ep);
     250                endpoint_list_add_ep(list, ohci_ep);
    267251                instance->registers->control |= C_BLE;
    268252                break;
     
    270254        case USB_TRANSFER_INTERRUPT:
    271255                instance->registers->control &= (~C_PLE & ~C_IE);
    272                 endpoint_list_add_ep(
    273                     &instance->lists[ep->transfer_type], hcd_ep);
     256                endpoint_list_add_ep(list, ohci_ep);
    274257                instance->registers->control |= C_PLE | C_IE;
    275258                break;
    276259        }
    277 
    278         return EOK;
    279 }
    280 /*----------------------------------------------------------------------------*/
    281 /** Dequeue and delete endpoint structures
    282  *
    283  * @param[in] instance OHCI hc driver structure.
    284  * @param[in] address USB address of the device.
    285  * @param[in] endpoint USB endpoint number.
    286  * @param[in] direction Direction of the endpoint.
    287  * @return Error code
    288  */
    289 int hc_remove_endpoint(hc_t *instance, usb_address_t address,
    290     usb_endpoint_t endpoint, usb_direction_t direction)
    291 {
    292         assert(instance);
    293         fibril_mutex_lock(&instance->guard);
    294         endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
    295             address, endpoint, direction, NULL);
    296         if (ep == NULL) {
    297                 usb_log_error("Endpoint unregister failed: No such EP.\n");
    298                 fibril_mutex_unlock(&instance->guard);
    299                 return ENOENT;
    300         }
    301 
    302         hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
    303         if (hcd_ep) {
    304                 /* Dequeue hcd_ep */
    305                 switch (ep->transfer_type) {
    306                 case USB_TRANSFER_CONTROL:
    307                         instance->registers->control &= ~C_CLE;
    308                         endpoint_list_remove_ep(
    309                             &instance->lists[ep->transfer_type], hcd_ep);
    310                         instance->registers->control_current = 0;
    311                         instance->registers->control |= C_CLE;
    312                         break;
    313                 case USB_TRANSFER_BULK:
    314                         instance->registers->control &= ~C_BLE;
    315                         endpoint_list_remove_ep(
    316                             &instance->lists[ep->transfer_type], hcd_ep);
    317                         instance->registers->control |= C_BLE;
    318                         break;
    319                 case USB_TRANSFER_ISOCHRONOUS:
    320                 case USB_TRANSFER_INTERRUPT:
    321                         instance->registers->control &= (~C_PLE & ~C_IE);
    322                         endpoint_list_remove_ep(
    323                             &instance->lists[ep->transfer_type], hcd_ep);
    324                         instance->registers->control |= C_PLE | C_IE;
    325                         break;
    326                 default:
    327                         break;
    328                 }
    329                 hcd_endpoint_clear(ep);
    330         } else {
    331                 usb_log_warning("Endpoint without hcd equivalent structure.\n");
    332         }
    333         int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager,
    334             address, endpoint, direction);
    335         fibril_mutex_unlock(&instance->guard);
    336         return ret;
    337 }
    338 /*----------------------------------------------------------------------------*/
    339 /** Get access to endpoint structures
    340  *
    341  * @param[in] instance OHCI hc driver structure.
    342  * @param[in] address USB address of the device.
    343  * @param[in] endpoint USB endpoint number.
    344  * @param[in] direction Direction of the endpoint.
    345  * @param[out] bw Reserved bandwidth.
    346  * @return Error code
    347  */
    348 endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
    349     usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw)
    350 {
    351         assert(instance);
    352         fibril_mutex_lock(&instance->guard);
    353         endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
    354             address, endpoint, direction, bw);
    355         fibril_mutex_unlock(&instance->guard);
    356         return ep;
     260}
     261/*----------------------------------------------------------------------------*/
     262void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep)
     263{
     264        assert(instance);
     265        assert(ep);
     266
     267        /* Dequeue ep */
     268        endpoint_list_t *list = &instance->lists[ep->transfer_type];
     269        ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep);
     270
     271        assert(list);
     272        assert(ohci_ep);
     273        switch (ep->transfer_type) {
     274        case USB_TRANSFER_CONTROL:
     275                instance->registers->control &= ~C_CLE;
     276                endpoint_list_remove_ep(list, ohci_ep);
     277                instance->registers->control_current = 0;
     278                instance->registers->control |= C_CLE;
     279                break;
     280        case USB_TRANSFER_BULK:
     281                instance->registers->control &= ~C_BLE;
     282                endpoint_list_remove_ep(list, ohci_ep);
     283                instance->registers->control |= C_BLE;
     284                break;
     285        case USB_TRANSFER_ISOCHRONOUS:
     286        case USB_TRANSFER_INTERRUPT:
     287                instance->registers->control &= (~C_PLE & ~C_IE);
     288                endpoint_list_remove_ep(list, ohci_ep);
     289                instance->registers->control |= C_PLE | C_IE;
     290                break;
     291        default:
     292                break;
     293        }
    357294}
    358295/*----------------------------------------------------------------------------*/
     
    363300 * @return Error code.
    364301 */
    365 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
    366 {
    367         assert(instance);
    368         assert(batch);
    369         assert(batch->ep);
     302int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     303{
     304        assert(hcd);
     305        hc_t *instance = hcd->private_data;
     306        assert(instance);
    370307
    371308        /* Check for root hub communication */
     
    374311                return EOK;
    375312        }
     313        ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);
     314        if (!ohci_batch)
     315                return ENOMEM;
    376316
    377317        fibril_mutex_lock(&instance->guard);
    378         list_append(&batch->link, &instance->pending_batches);
    379         batch_commit(batch);
     318        list_append(&ohci_batch->link, &instance->pending_batches);
     319        ohci_transfer_batch_commit(ohci_batch);
    380320
    381321        /* Control and bulk schedules need a kick to start working */
     
    417357                    instance->registers->periodic_current);
    418358
    419                 link_t *current = instance->pending_batches.head.next;
    420                 while (current != &instance->pending_batches.head) {
     359                link_t *current = list_first(&instance->pending_batches);
     360                while (current && current != &instance->pending_batches.head) {
    421361                        link_t *next = current->next;
    422                         usb_transfer_batch_t *batch =
    423                             usb_transfer_batch_from_link(current);
    424 
    425                         if (batch_is_complete(batch)) {
     362                        ohci_transfer_batch_t *batch =
     363                            ohci_transfer_batch_from_link(current);
     364
     365                        if (ohci_transfer_batch_is_complete(batch)) {
    426366                                list_remove(current);
    427                                 usb_transfer_batch_finish(batch);
     367                                ohci_transfer_batch_finish_dispose(batch);
    428368                        }
    429369
     
    434374
    435375        if (status & I_UE) {
     376                usb_log_fatal("Error like no other!\n");
    436377                hc_start(instance);
    437378        }
     
    643584
    644585        /*Init HCCA */
    645         instance->hcca = malloc32(sizeof(hcca_t));
     586        instance->hcca = hcca_get();
    646587        if (instance->hcca == NULL)
    647588                return ENOMEM;
     
    649590        usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
    650591
    651         unsigned i = 0;
    652         for (; i < 32; ++i) {
     592        for (unsigned i = 0; i < 32; ++i) {
    653593                instance->hcca->int_ep[i] =
    654594                    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
Note: See TracChangeset for help on using the changeset viewer.