Changeset c7dd69d in mainline for uspace/drv/ohci/hc.c


Ignore:
Timestamp:
2011-04-15T13:19:59Z (13 years ago)
Author:
Lubos Slovak <lubos.slovak@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
da1dd48
Parents:
e3b5129 (diff), 8fd4ba0 (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:

Development changes

File:
1 edited

Legend:

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

    re3b5129 rc7dd69d  
    4343
    4444#include "hc.h"
     45#include "hcd_endpoint.h"
    4546
    4647static int interrupt_emulator(hc_t *instance);
     
    5556        assert(hub_fun);
    5657
     58        int ret;
     59
    5760        usb_address_t hub_address =
    5861            device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL);
     62        if (hub_address <= 0) {
     63                usb_log_error("Failed to get OHCI root hub address.\n");
     64                return hub_address;
     65        }
    5966        instance->rh.address = hub_address;
    6067        usb_device_keeper_bind(
    6168            &instance->manager, hub_address, hub_fun->handle);
    6269
    63         endpoint_t *ep = malloc(sizeof(endpoint_t));
    64         assert(ep);
    65         int ret = endpoint_init(ep, hub_address, 0, USB_DIRECTION_BOTH,
    66             USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64);
    67         assert(ret == EOK);
    68         ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, 0);
    69         assert(ret == EOK);
     70        ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,
     71            USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);
     72        if (ret != EOK) {
     73                usb_log_error("Failed to add OHCI rh endpoint 0.\n");
     74                usb_device_keeper_release(&instance->manager, hub_address);
     75                return ret;
     76        }
    7077
    7178        char *match_str = NULL;
     79        /* DDF needs heap allocated string */
    7280        ret = asprintf(&match_str, "usb&class=hub");
    73 //      ret = (match_str == NULL) ? ret : EOK;
    7481        if (ret < 0) {
    7582                usb_log_error(
    7683                    "Failed(%d) to create root hub match-id string.\n", ret);
     84                usb_device_keeper_release(&instance->manager, hub_address);
    7785                return ret;
    7886        }
     
    8088        ret = ddf_fun_add_match_id(hub_fun, match_str, 100);
    8189        if (ret != EOK) {
    82                 usb_log_error("Failed add create root hub match-id.\n");
     90                usb_log_error("Failed add root hub match-id.\n");
    8391        }
    8492        return ret;
     
    101109            ret, str_error(ret));
    102110
    103         instance->ddf_instance = fun;
    104111        usb_device_keeper_init(&instance->manager);
    105112        ret = usb_endpoint_manager_init(&instance->ep_manager,
     
    113120            ret, str_error(ret));
    114121        hc_init_hw(instance);
    115 
    116         rh_init(&instance->rh, dev, instance->registers);
     122        fibril_mutex_initialize(&instance->guard);
     123
     124        rh_init(&instance->rh, instance->registers);
    117125
    118126        if (!interrupts) {
     
    122130        }
    123131
    124         return EOK;
    125 }
    126 /*----------------------------------------------------------------------------*/
    127 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
    128 {
    129         assert(instance);
    130         assert(batch);
    131 
    132         /* check for root hub communication */
    133         if (batch->target.address == instance->rh.address) {
    134                 return rh_request(&instance->rh, batch);
    135         }
    136 
    137         transfer_list_add_batch(
    138             instance->transfers[batch->transfer_type], batch);
    139 
    140         switch (batch->transfer_type) {
     132        list_initialize(&instance->pending_batches);
     133#undef CHECK_RET_RETURN
     134        return EOK;
     135}
     136/*----------------------------------------------------------------------------*/
     137int hc_add_endpoint(
     138    hc_t *instance, usb_address_t address, usb_endpoint_t endpoint,
     139    usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,
     140    size_t mps, size_t size, unsigned interval)
     141{
     142        endpoint_t *ep = malloc(sizeof(endpoint_t));
     143        if (ep == NULL)
     144                return ENOMEM;
     145        int ret =
     146            endpoint_init(ep, address, endpoint, direction, type, speed, mps);
     147        if (ret != EOK) {
     148                free(ep);
     149                return ret;
     150        }
     151
     152        hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);
     153        if (hcd_ep == NULL) {
     154                endpoint_destroy(ep);
     155                return ENOMEM;
     156        }
     157
     158        ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);
     159        if (ret != EOK) {
     160                hcd_endpoint_clear(ep);
     161                endpoint_destroy(ep);
     162                return ret;
     163        }
     164
     165        /* Enqueue hcd_ep */
     166        switch (ep->transfer_type) {
    141167        case USB_TRANSFER_CONTROL:
    142168                instance->registers->control &= ~C_CLE;
     169                endpoint_list_add_ep(
     170                    &instance->lists[ep->transfer_type], hcd_ep);
     171                instance->registers->control_current = 0;
     172                instance->registers->control |= C_CLE;
     173                break;
     174        case USB_TRANSFER_BULK:
     175                instance->registers->control &= ~C_BLE;
     176                endpoint_list_add_ep(
     177                    &instance->lists[ep->transfer_type], hcd_ep);
     178                instance->registers->control |= C_BLE;
     179                break;
     180        case USB_TRANSFER_ISOCHRONOUS:
     181        case USB_TRANSFER_INTERRUPT:
     182                instance->registers->control &= (~C_PLE & ~C_IE);
     183                endpoint_list_add_ep(
     184                    &instance->lists[ep->transfer_type], hcd_ep);
     185                instance->registers->control |= C_PLE | C_IE;
     186                break;
     187        default:
     188                break;
     189        }
     190
     191        return EOK;
     192}
     193/*----------------------------------------------------------------------------*/
     194int hc_remove_endpoint(hc_t *instance, usb_address_t address,
     195    usb_endpoint_t endpoint, usb_direction_t direction)
     196{
     197        assert(instance);
     198        fibril_mutex_lock(&instance->guard);
     199        endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
     200            address, endpoint, direction, NULL);
     201        if (ep == NULL) {
     202                usb_log_error("Endpoint unregister failed: No such EP.\n");
     203                fibril_mutex_unlock(&instance->guard);
     204                return ENOENT;
     205        }
     206
     207        hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);
     208        if (hcd_ep) {
     209                /* Dequeue hcd_ep */
     210                switch (ep->transfer_type) {
     211                case USB_TRANSFER_CONTROL:
     212                        instance->registers->control &= ~C_CLE;
     213                        endpoint_list_remove_ep(
     214                            &instance->lists[ep->transfer_type], hcd_ep);
     215                        instance->registers->control_current = 0;
     216                        instance->registers->control |= C_CLE;
     217                        break;
     218                case USB_TRANSFER_BULK:
     219                        instance->registers->control &= ~C_BLE;
     220                        endpoint_list_remove_ep(
     221                            &instance->lists[ep->transfer_type], hcd_ep);
     222                        instance->registers->control |= C_BLE;
     223                        break;
     224                case USB_TRANSFER_ISOCHRONOUS:
     225                case USB_TRANSFER_INTERRUPT:
     226                        instance->registers->control &= (~C_PLE & ~C_IE);
     227                        endpoint_list_remove_ep(
     228                            &instance->lists[ep->transfer_type], hcd_ep);
     229                        instance->registers->control |= C_PLE | C_IE;
     230                        break;
     231                default:
     232                        break;
     233                }
     234                hcd_endpoint_clear(ep);
     235        } else {
     236                usb_log_warning("Endpoint without hcd equivalent structure.\n");
     237        }
     238        int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager,
     239            address, endpoint, direction);
     240        fibril_mutex_unlock(&instance->guard);
     241        return ret;
     242}
     243/*----------------------------------------------------------------------------*/
     244endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,
     245    usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw)
     246{
     247        assert(instance);
     248        fibril_mutex_lock(&instance->guard);
     249        endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,
     250            address, endpoint, direction, bw);
     251        fibril_mutex_unlock(&instance->guard);
     252        return ep;
     253}
     254/*----------------------------------------------------------------------------*/
     255int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
     256{
     257        assert(instance);
     258        assert(batch);
     259        assert(batch->ep);
     260
     261        /* check for root hub communication */
     262        if (batch->ep->address == instance->rh.address) {
     263                return rh_request(&instance->rh, batch);
     264        }
     265
     266        fibril_mutex_lock(&instance->guard);
     267        list_append(&batch->link, &instance->pending_batches);
     268        batch_commit(batch);
     269        switch (batch->ep->transfer_type) {
     270        case USB_TRANSFER_CONTROL:
    143271                instance->registers->command_status |= CS_CLF;
    144                 usb_log_debug2("Set control transfer filled: %x.\n",
    145                         instance->registers->command_status);
    146                 instance->registers->control |= C_CLE;
    147272                break;
    148273        case USB_TRANSFER_BULK:
    149274                instance->registers->command_status |= CS_BLF;
    150                 usb_log_debug2("Set bulk transfer filled: %x.\n",
    151                         instance->registers->command_status);
    152275                break;
    153276        default:
    154277                break;
    155278        }
     279
     280        fibril_mutex_unlock(&instance->guard);
    156281        return EOK;
    157282}
     
    165290                rh_interrupt(&instance->rh);
    166291
    167         usb_log_info("OHCI interrupt: %x.\n", status);
    168 
    169 
    170         LIST_INITIALIZE(done);
    171         transfer_list_remove_finished(&instance->transfers_interrupt, &done);
    172         transfer_list_remove_finished(&instance->transfers_isochronous, &done);
    173         transfer_list_remove_finished(&instance->transfers_control, &done);
    174         transfer_list_remove_finished(&instance->transfers_bulk, &done);
    175 
    176         while (!list_empty(&done)) {
    177                 link_t *item = done.next;
    178                 list_remove(item);
    179                 usb_transfer_batch_t *batch =
    180                     list_get_instance(item, usb_transfer_batch_t, link);
    181                 usb_transfer_batch_finish(batch);
     292        usb_log_debug("OHCI interrupt: %x.\n", status);
     293
     294        if (status & IS_WDH) {
     295                fibril_mutex_lock(&instance->guard);
     296                usb_log_debug2("HCCA: %p-%p(%p).\n", instance->hcca,
     297                    instance->registers->hcca, addr_to_phys(instance->hcca));
     298                usb_log_debug2("Periodic current: %p.\n",
     299                    instance->registers->periodic_current);
     300
     301                link_t *current = instance->pending_batches.next;
     302                while (current != &instance->pending_batches) {
     303                        link_t *next = current->next;
     304                        usb_transfer_batch_t *batch =
     305                            usb_transfer_batch_from_link(current);
     306
     307                        if (batch_is_complete(batch)) {
     308                                list_remove(current);
     309                                usb_transfer_batch_finish(batch);
     310                        }
     311                        current = next;
     312                }
     313                fibril_mutex_unlock(&instance->guard);
    182314        }
    183315}
     
    191323                instance->registers->interrupt_status = status;
    192324                hc_interrupt(instance, status);
    193                 async_usleep(1000);
     325                async_usleep(50000);
    194326        }
    195327        return EOK;
     
    267399            instance->registers->control);
    268400
     401        /* Use HCCA */
     402        instance->registers->hcca = addr_to_phys(instance->hcca);
     403
     404        /* Use queues */
     405        instance->registers->bulk_head =
     406            instance->lists[USB_TRANSFER_BULK].list_head_pa;
     407        usb_log_debug2("Bulk HEAD set to: %p(%p).\n",
     408            instance->lists[USB_TRANSFER_BULK].list_head,
     409            instance->lists[USB_TRANSFER_BULK].list_head_pa);
     410
     411        instance->registers->control_head =
     412            instance->lists[USB_TRANSFER_CONTROL].list_head_pa;
     413        usb_log_debug2("Control HEAD set to: %p(%p).\n",
     414            instance->lists[USB_TRANSFER_CONTROL].list_head,
     415            instance->lists[USB_TRANSFER_CONTROL].list_head_pa);
     416
    269417        /* Enable queues */
    270418        instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE);
     
    296444        assert(instance);
    297445
    298 #define SETUP_TRANSFER_LIST(type, name) \
     446#define SETUP_ENDPOINT_LIST(type) \
    299447do { \
    300         int ret = transfer_list_init(&instance->type, name); \
     448        const char *name = usb_str_transfer_type(type); \
     449        int ret = endpoint_list_init(&instance->lists[type], name); \
    301450        if (ret != EOK) { \
    302                 usb_log_error("Failed(%d) to setup %s transfer list.\n", \
     451                usb_log_error("Failed(%d) to setup %s endpoint list.\n", \
    303452                    ret, name); \
    304                 transfer_list_fini(&instance->transfers_isochronous); \
    305                 transfer_list_fini(&instance->transfers_interrupt); \
    306                 transfer_list_fini(&instance->transfers_control); \
    307                 transfer_list_fini(&instance->transfers_bulk); \
     453                endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]); \
     454                endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \
     455                endpoint_list_fini(&instance->lists[USB_TRANSFER_CONTROL]); \
     456                endpoint_list_fini(&instance->lists[USB_TRANSFER_BULK]); \
    308457        } \
    309458} while (0)
    310459
    311         SETUP_TRANSFER_LIST(transfers_isochronous, "ISOCHRONOUS");
    312         SETUP_TRANSFER_LIST(transfers_interrupt, "INTERRUPT");
    313         SETUP_TRANSFER_LIST(transfers_control, "CONTROL");
    314         SETUP_TRANSFER_LIST(transfers_bulk, "BULK");
    315 
    316         transfer_list_set_next(&instance->transfers_interrupt,
    317             &instance->transfers_isochronous);
    318 
    319         /* Assign pointers to be used during scheduling */
    320         instance->transfers[USB_TRANSFER_INTERRUPT] =
    321           &instance->transfers_interrupt;
    322         instance->transfers[USB_TRANSFER_ISOCHRONOUS] =
    323           &instance->transfers_interrupt;
    324         instance->transfers[USB_TRANSFER_CONTROL] =
    325           &instance->transfers_control;
    326         instance->transfers[USB_TRANSFER_BULK] =
    327           &instance->transfers_bulk;
    328 
    329         return EOK;
    330 #undef CHECK_RET_CLEAR_RETURN
     460        SETUP_ENDPOINT_LIST(USB_TRANSFER_ISOCHRONOUS);
     461        SETUP_ENDPOINT_LIST(USB_TRANSFER_INTERRUPT);
     462        SETUP_ENDPOINT_LIST(USB_TRANSFER_CONTROL);
     463        SETUP_ENDPOINT_LIST(USB_TRANSFER_BULK);
     464#undef SETUP_ENDPOINT_LIST
     465        endpoint_list_set_next(&instance->lists[USB_TRANSFER_INTERRUPT],
     466            &instance->lists[USB_TRANSFER_ISOCHRONOUS]);
     467
     468        return EOK;
    331469}
    332470/*----------------------------------------------------------------------------*/
     
    342480                return ENOMEM;
    343481        bzero(instance->hcca, sizeof(hcca_t));
    344         instance->registers->hcca = addr_to_phys(instance->hcca);
    345         usb_log_debug2("OHCI HCCA initialized at %p(%p).\n",
    346             instance->hcca, instance->registers->hcca);
    347 
    348         /* Use queues */
    349         instance->registers->bulk_head = instance->transfers_bulk.list_head_pa;
    350         usb_log_debug2("Bulk HEAD set to: %p(%p).\n",
    351             instance->transfers_bulk.list_head,
    352             instance->transfers_bulk.list_head_pa);
    353 
    354         instance->registers->control_head =
    355             instance->transfers_control.list_head_pa;
    356         usb_log_debug2("Control HEAD set to: %p(%p).\n",
    357             instance->transfers_control.list_head,
    358             instance->transfers_control.list_head_pa);
     482        usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca);
    359483
    360484        unsigned i = 0;
    361485        for (; i < 32; ++i) {
    362486                instance->hcca->int_ep[i] =
    363                     instance->transfers_interrupt.list_head_pa;
     487                    instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
    364488        }
    365489        usb_log_debug2("Interrupt HEADs set to: %p(%p).\n",
    366             instance->transfers_interrupt.list_head,
    367             instance->transfers_interrupt.list_head_pa);
     490            instance->lists[USB_TRANSFER_INTERRUPT].list_head,
     491            instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa);
    368492
    369493        return EOK;
Note: See TracChangeset for help on using the changeset viewer.