Ignore:
File:
1 edited

Legend:

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

    re991937 r7de1988c  
    3434 */
    3535
     36/* XXX Fix this */
     37#define _DDF_DATA_IMPLANT
     38
    3639#include <errno.h>
    3740#include <str_error.h>
    3841#include <ddf/interrupt.h>
     42#include <usb_iface.h>
    3943#include <usb/usb.h>
     44#include <usb/ddfiface.h>
    4045#include <usb/debug.h>
    41 
    42 #include <usb/host/ddf_helpers.h>
    4346
    4447#include "ohci.h"
     
    4649#include "hc.h"
    4750
    48 
    49 
     51typedef struct ohci {
     52        ddf_fun_t *hc_fun;
     53        ddf_fun_t *rh_fun;
     54
     55        hc_t hc;
     56} ohci_t;
     57
     58static inline ohci_t *dev_to_ohci(ddf_dev_t *dev)
     59{
     60        return ddf_dev_data_get(dev);
     61}
    5062/** IRQ handling callback, identifies device
    5163 *
     
    5769{
    5870        assert(dev);
    59         hcd_t *hcd = dev_to_hcd(dev);
    60         if (!hcd || !hcd->private_data) {
     71
     72        ohci_t *ohci = dev_to_ohci(dev);
     73        if (!ohci) {
    6174                usb_log_warning("Interrupt on device that is not ready.\n");
    6275                return;
    6376        }
    64 
    6577        const uint16_t status = IPC_GET_ARG1(*call);
    66         hc_interrupt(hcd->private_data, status);
    67 }
     78        hc_interrupt(&ohci->hc, status);
     79}
     80
     81/** Get USB address assigned to root hub.
     82 *
     83 * @param[in] fun Root hub function.
     84 * @param[out] address Store the address here.
     85 * @return Error code.
     86 */
     87static int rh_get_my_address(ddf_fun_t *fun, usb_address_t *address)
     88{
     89        assert(fun);
     90
     91        if (address != NULL) {
     92                *address = dev_to_ohci(ddf_fun_get_dev(fun))->hc.rh.address;
     93        }
     94
     95        return EOK;
     96}
     97
     98/** Gets handle of the respective hc (this device, hc function).
     99 *
     100 * @param[in] root_hub_fun Root hub function seeking hc handle.
     101 * @param[out] handle Place to write the handle.
     102 * @return Error code.
     103 */
     104static int rh_get_hc_handle(
     105    ddf_fun_t *fun, devman_handle_t *handle)
     106{
     107        assert(fun);
     108        ddf_fun_t *hc_fun = dev_to_ohci(ddf_fun_get_dev(fun))->hc_fun;
     109        assert(hc_fun);
     110
     111        if (handle != NULL)
     112                *handle = ddf_fun_get_handle(hc_fun);
     113        return EOK;
     114}
     115
     116/** Root hub USB interface */
     117static usb_iface_t usb_iface = {
     118        .get_hc_handle = rh_get_hc_handle,
     119        .get_my_address = rh_get_my_address,
     120};
     121
     122/** Standard USB HC options (HC interface) */
     123static ddf_dev_ops_t hc_ops = {
     124        .interfaces[USBHC_DEV_IFACE] = &hcd_iface,
     125};
     126
     127/** Standard USB RH options (RH interface) */
     128static ddf_dev_ops_t rh_ops = {
     129        .interfaces[USB_DEV_IFACE] = &usb_iface,
     130};
    68131
    69132/** Initialize hc and rh ddf structures and their respective drivers.
     
    80143int device_setup_ohci(ddf_dev_t *device)
    81144{
    82 #define CHECK_RET_RETURN(ret, message...) \
    83 if (ret != EOK) { \
    84         usb_log_error(message); \
    85         return ret; \
    86 }
    87 
    88         uintptr_t reg_base = 0;
    89         size_t reg_size = 0;
     145        bool ih_registered = false;
     146        bool hc_inited = false;
     147        int rc;
     148
     149        if (device == NULL)
     150                return EBADMEM;
     151
     152        ohci_t *instance = ddf_dev_data_alloc(device,sizeof(ohci_t));
     153        if (instance == NULL) {
     154                usb_log_error("Failed to allocate OHCI driver.\n");
     155                return ENOMEM;
     156        }
     157
     158        instance->hc_fun = ddf_fun_create(device, fun_exposed, "ohci_hc");
     159        if (instance->hc_fun == NULL) {
     160                usb_log_error("Failed to create OHCI HC function: %s.\n",
     161                    str_error(ENOMEM));
     162                rc = ENOMEM;
     163                goto error;
     164        }
     165
     166        ddf_fun_set_ops(instance->hc_fun, &hc_ops);
     167        ddf_fun_data_implant(instance->hc_fun, &instance->hc);
     168
     169        instance->rh_fun = ddf_fun_create(device, fun_inner, "ohci_rh");
     170        if (instance->rh_fun == NULL) {
     171                usb_log_error("Failed to create OHCI RH function: %s.\n",
     172                    str_error(ENOMEM));
     173                rc = ENOMEM;
     174                goto error;
     175        }
     176
     177        ddf_fun_set_ops(instance->rh_fun, &rh_ops);
     178
     179        addr_range_t regs;
    90180        int irq = 0;
    91181
    92         int ret = get_my_registers(device, &reg_base, &reg_size, &irq);
    93         CHECK_RET_RETURN(ret, "Failed to get register memory addresses for %"
    94             PRIun ": %s.\n", ddf_dev_get_handle(device), str_error(ret));
     182        rc = get_my_registers(device, &regs, &irq);
     183        if (rc != EOK) {
     184                usb_log_error("Failed to get register memory addresses "
     185                    "for %" PRIun ": %s.\n", ddf_dev_get_handle(device),
     186                    str_error(rc));
     187                goto error;
     188        }
    95189
    96190        usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
    97             (void *) reg_base, reg_size, irq);
    98 
    99         const size_t ranges_count = hc_irq_pio_range_count();
    100         const size_t cmds_count = hc_irq_cmd_count();
    101         irq_pio_range_t irq_ranges[ranges_count];
    102         irq_cmd_t irq_cmds[cmds_count];
    103         irq_code_t irq_code = {
    104                 .rangecount = ranges_count,
    105                 .ranges = irq_ranges,
    106                 .cmdcount = cmds_count,
    107                 .cmds = irq_cmds
    108         };
    109 
    110         ret = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds,
    111             sizeof(irq_cmds), reg_base, reg_size);
    112         CHECK_RET_RETURN(ret, "Failed to gen IRQ code: %s.\n", str_error(ret));
    113 
    114         /* Register handler to avoid interrupt lockup */
    115         ret = register_interrupt_handler(device, irq, irq_handler, &irq_code);
    116         CHECK_RET_RETURN(ret,
    117             "Failed to register irq handler: %s.\n", str_error(ret));
     191            RNGABSPTR(regs), RNGSZ(regs), irq);
     192
     193        rc = hc_register_irq_handler(device, &regs, irq, irq_handler);
     194        if (rc != EOK) {
     195                usb_log_error("Failed to register interrupt handler: %s.\n",
     196                    str_error(rc));
     197                goto error;
     198        }
     199
     200        ih_registered = true;
    118201
    119202        /* Try to enable interrupts */
    120203        bool interrupts = false;
    121         ret = enable_interrupts(device);
    122         if (ret != EOK) {
     204        rc = enable_interrupts(device);
     205        if (rc != EOK) {
    123206                usb_log_warning("Failed to enable interrupts: %s."
    124                     " Falling back to polling\n", str_error(ret));
     207                    " Falling back to polling\n", str_error(rc));
    125208                /* We don't need that handler */
    126209                unregister_interrupt_handler(device, irq);
     210                ih_registered = false;
    127211        } else {
    128212                usb_log_debug("Hw interrupts enabled.\n");
     
    130214        }
    131215
    132         /* Initialize generic HCD driver */
    133         ret = hcd_ddf_setup_hc(device, USB_SPEED_FULL,
    134             BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
    135         if (ret != EOK) {
     216        rc = hc_init(&instance->hc, &regs, interrupts);
     217        if (rc != EOK) {
     218                usb_log_error("Failed to init ohci_hcd: %s.\n", str_error(rc));
     219                goto error;
     220        }
     221
     222        hc_inited = true;
     223
     224        rc = ddf_fun_bind(instance->hc_fun);
     225        if (rc != EOK) {
     226                usb_log_error("Failed to bind OHCI device function: %s.\n",
     227                    str_error(rc));
     228                goto error;
     229        }
     230
     231        rc = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
     232        if (rc != EOK) {
     233                usb_log_error("Failed to add OHCI to HC category: %s.\n",
     234                    str_error(rc));
     235                goto error;
     236        }
     237
     238        rc = hc_register_hub(&instance->hc, instance->rh_fun);
     239        if (rc != EOK) {
     240                usb_log_error("Failed to register OHCI root hub: %s.\n",
     241                    str_error(rc));
     242                goto error;
     243        }
     244
     245        return EOK;
     246
     247error:
     248        if (hc_inited)
     249                hc_fini(&instance->hc);
     250        if (ih_registered)
    136251                unregister_interrupt_handler(device, irq);
    137                 return ret;
    138         }
    139 
    140 // TODO: Undo hcd_setup_device
    141 #define CHECK_RET_CLEAN_RETURN(ret, message...) \
    142 if (ret != EOK) { \
    143         unregister_interrupt_handler(device, irq); \
    144         CHECK_RET_RETURN(ret, message); \
    145 } else (void)0
    146 
    147         hc_t *hc_impl = malloc(sizeof(hc_t));
    148         ret = hc_impl ? EOK : ENOMEM;
    149         CHECK_RET_CLEAN_RETURN(ret, "Failed to allocate driver structure.\n");
    150 
    151         /* Initialize OHCI HC */
    152         ret = hc_init(hc_impl, reg_base, reg_size, interrupts);
    153         CHECK_RET_CLEAN_RETURN(ret, "Failed to init hc: %s.\n", str_error(ret));
    154 
    155         /* Connect OHCI to generic HCD */
    156         hcd_set_implementation(dev_to_hcd(device), hc_impl,
    157             hc_schedule, ohci_endpoint_init, ohci_endpoint_fini);
    158 
    159         /* HC should be running OK. We can add root hub */
    160         ret = hcd_ddf_setup_root_hub(device);
    161         CHECK_RET_CLEAN_RETURN(ret,
    162             "Failed to register OHCI root hub: %s.\n", str_error(ret));
    163 
    164         return ret;
     252        if (instance->hc_fun != NULL)
     253                ddf_fun_destroy(instance->hc_fun);
     254        if (instance->rh_fun != NULL)
     255                ddf_fun_destroy(instance->rh_fun);
     256        return rc;
    165257}
    166258/**
Note: See TracChangeset for help on using the changeset viewer.