Ignore:
File:
1 edited

Legend:

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

    rd57122c ref9460b  
    4242
    4343#include "hc.h"
    44 #include "ohci_endpoint.h"
     44#include "hcd_endpoint.h"
    4545
    4646#define OHCI_USED_INTERRUPTS \
    4747    (I_SO | I_WDH | I_UE | I_RHSC)
    4848
    49 static const irq_pio_range_t ohci_pio_ranges[] = {
    50         {
    51                 .base = 0,      /* filled later */
    52                 .size = sizeof(ohci_regs_t)
    53         }
    54 };
    55 
    56 static const irq_cmd_t ohci_irq_commands[] = {
    57         { .cmd = CMD_PIO_READ_32, .dstarg = 1, .addr = NULL /* filled later */ },
     49static const irq_cmd_t ohci_irq_commands[] =
     50{
     51        { .cmd = CMD_MEM_READ_32, .dstarg = 1, .addr = NULL /*filled later*/ },
    5852        { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS },
    5953        { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 },
    60         { .cmd = CMD_PIO_WRITE_A_32, .srcarg = 1, .addr = NULL /* filled later */ },
     54        { .cmd = CMD_MEM_WRITE_A_32, .srcarg = 1, .addr = NULL /*filled later*/ },
    6155        { .cmd = CMD_ACCEPT },
    6256};
     
    6761static int hc_init_memory(hc_t *instance);
    6862static int interrupt_emulator(hc_t *instance);
    69 static 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  */
    74 size_t hc_irq_pio_range_count(void)
    75 {
    76         return sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t);
    77 }
    78 /*----------------------------------------------------------------------------*/
     63
    7964/*----------------------------------------------------------------------------*/
    8065/** Get number of commands used in IRQ code.
     
    8671}
    8772/*----------------------------------------------------------------------------*/
    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).
     73/** Generate IRQ code commands.
     74 * @param[out] cmds Place to store the commands.
     75 * @param[in] cmd_size Size of the place (bytes).
    9376 * @param[in] regs Physical address of device's registers.
    9477 * @param[in] reg_size Size of the register area (bytes).
     
    9679 * @return Error code.
    9780 */
    98 int
    99 hc_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)))
     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))
    10586                return EOVERFLOW;
    10687
    107         memcpy(ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges));
    108         ranges[0].base = regs;
     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;
    109109
    110110        memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
    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 
     111
     112        void *address = (void*)&registers->interrupt_status;
     113        cmds[0].addr = address;
     114        cmds[3].addr = address;
    115115        return EOK;
    116116}
     
    127127        assert(hub_fun);
    128128
    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) {
     129        const usb_address_t hub_address =
     130            device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
     131        if (hub_address <= 0) {
    135132                usb_log_error("Failed to get OHCI root hub address: %s\n",
    136                     str_error(ret));
    137                 return ret;
    138         }
    139 
    140 #define CHECK_RET_UNREG_RETURN(ret, message...) \
     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...) \
    141141if (ret != EOK) { \
    142142        usb_log_error(message); \
    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); \
     143        hc_remove_endpoint(instance, hub_address, 0, USB_DIRECTION_BOTH); \
     144        usb_device_keeper_release(&instance->manager, hub_address); \
    148145        return ret; \
    149146} else (void)0
    150147
    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));
     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));
    158152
    159153        ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
    160         CHECK_RET_UNREG_RETURN(ret,
     154        CHECK_RET_RELEASE(ret,
    161155            "Failed to add root hub match-id: %s.\n", str_error(ret));
    162156
    163157        ret = ddf_fun_bind(hub_fun);
    164         CHECK_RET_UNREG_RETURN(ret,
     158        CHECK_RET_RELEASE(ret,
    165159            "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));
    172160
    173161        return EOK;
     
    199187
    200188        list_initialize(&instance->pending_batches);
    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;
     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));
    208195
    209196        ret = hc_init_memory(instance);
     
    228215}
    229216/*----------------------------------------------------------------------------*/
    230 void 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 */
     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 */
     230int 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 */
    241255        switch (ep->transfer_type) {
    242256        case USB_TRANSFER_CONTROL:
    243257                instance->registers->control &= ~C_CLE;
    244                 endpoint_list_add_ep(list, ohci_ep);
     258                endpoint_list_add_ep(
     259                    &instance->lists[ep->transfer_type], hcd_ep);
    245260                instance->registers->control_current = 0;
    246261                instance->registers->control |= C_CLE;
     
    248263        case USB_TRANSFER_BULK:
    249264                instance->registers->control &= ~C_BLE;
    250                 endpoint_list_add_ep(list, ohci_ep);
     265                endpoint_list_add_ep(
     266                    &instance->lists[ep->transfer_type], hcd_ep);
    251267                instance->registers->control |= C_BLE;
    252268                break;
     
    254270        case USB_TRANSFER_INTERRUPT:
    255271                instance->registers->control &= (~C_PLE & ~C_IE);
    256                 endpoint_list_add_ep(list, ohci_ep);
     272                endpoint_list_add_ep(
     273                    &instance->lists[ep->transfer_type], hcd_ep);
    257274                instance->registers->control |= C_PLE | C_IE;
    258275                break;
    259276        }
    260 }
    261 /*----------------------------------------------------------------------------*/
    262 void 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         }
     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 */
     289int 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 */
     348endpoint_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;
    294357}
    295358/*----------------------------------------------------------------------------*/
     
    300363 * @return Error code.
    301364 */
    302 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    303 {
    304         assert(hcd);
    305         hc_t *instance = hcd->private_data;
    306         assert(instance);
     365int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
     366{
     367        assert(instance);
     368        assert(batch);
     369        assert(batch->ep);
    307370
    308371        /* Check for root hub communication */
     
    311374                return EOK;
    312375        }
    313         ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);
    314         if (!ohci_batch)
    315                 return ENOMEM;
    316376
    317377        fibril_mutex_lock(&instance->guard);
    318         list_append(&ohci_batch->link, &instance->pending_batches);
    319         ohci_transfer_batch_commit(ohci_batch);
     378        list_append(&batch->link, &instance->pending_batches);
     379        batch_commit(batch);
    320380
    321381        /* Control and bulk schedules need a kick to start working */
     
    357417                    instance->registers->periodic_current);
    358418
    359                 link_t *current = list_first(&instance->pending_batches);
    360                 while (current && current != &instance->pending_batches.head) {
     419                link_t *current = instance->pending_batches.head.next;
     420                while (current != &instance->pending_batches.head) {
    361421                        link_t *next = current->next;
    362                         ohci_transfer_batch_t *batch =
    363                             ohci_transfer_batch_from_link(current);
    364 
    365                         if (ohci_transfer_batch_is_complete(batch)) {
     422                        usb_transfer_batch_t *batch =
     423                            usb_transfer_batch_from_link(current);
     424
     425                        if (batch_is_complete(batch)) {
    366426                                list_remove(current);
    367                                 ohci_transfer_batch_finish_dispose(batch);
     427                                usb_transfer_batch_finish(batch);
    368428                        }
    369429
     
    374434
    375435        if (status & I_UE) {
    376                 usb_log_fatal("Error like no other!\n");
    377436                hc_start(instance);
    378437        }
     
    584643
    585644        /*Init HCCA */
    586         instance->hcca = hcca_get();
     645        instance->hcca = malloc32(sizeof(hcca_t));
    587646        if (instance->hcca == NULL)
    588647                return ENOMEM;
     
    590649        usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
    591650
    592         for (unsigned i = 0; i < 32; ++i) {
     651        unsigned i = 0;
     652        for (; i < 32; ++i) {
    593653                instance->hcca->int_ep[i] =
    594654                    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
Note: See TracChangeset for help on using the changeset viewer.