Ignore:
File:
1 edited

Legend:

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

    rc53007f r795448f  
    3333 * @brief UHCI driver
    3434 */
    35 
    36 /* XXX Fix this */
    37 #define _DDF_DATA_IMPLANT
    38 
    3935#include <errno.h>
    40 #include <stdbool.h>
    4136#include <str_error.h>
    4237#include <ddf/interrupt.h>
     
    6560} uhci_t;
    6661
    67 static inline uhci_t *dev_to_uhci(ddf_dev_t *dev)
    68 {
    69         return ddf_dev_data_get(dev);
    70 }
    71 
     62static inline uhci_t * dev_to_uhci(const ddf_dev_t *dev)
     63{
     64        assert(dev);
     65        return dev->driver_data;
     66}
     67/*----------------------------------------------------------------------------*/
    7268/** IRQ handling callback, forward status from call to diver structure.
    7369 *
     
    8783        hc_interrupt(&uhci->hc, status);
    8884}
    89 
     85/*----------------------------------------------------------------------------*/
    9086/** Operations supported by the HC driver */
    9187static ddf_dev_ops_t hc_ops = {
    9288        .interfaces[USBHC_DEV_IFACE] = &hcd_iface, /* see iface.h/c */
    9389};
    94 
     90/*----------------------------------------------------------------------------*/
    9591/** Gets handle of the respective hc.
    9692 *
     
    10197static int usb_iface_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
    10298{
    103         ddf_fun_t *hc_fun = dev_to_uhci(ddf_fun_get_dev(fun))->hc_fun;
     99        assert(fun);
     100        ddf_fun_t *hc_fun = dev_to_uhci(fun->dev)->hc_fun;
    104101        assert(hc_fun);
    105102
    106103        if (handle != NULL)
    107                 *handle = ddf_fun_get_handle(hc_fun);
     104                *handle = hc_fun->handle;
    108105        return EOK;
    109106}
    110 
     107/*----------------------------------------------------------------------------*/
    111108/** USB interface implementation used by RH */
    112109static usb_iface_t usb_iface = {
    113110        .get_hc_handle = usb_iface_get_hc_handle,
    114111};
    115 
     112/*----------------------------------------------------------------------------*/
    116113/** Get root hub hw resources (I/O registers).
    117114 *
     
    121118static hw_resource_list_t *get_resource_list(ddf_fun_t *fun)
    122119{
    123         rh_t *rh = ddf_fun_data_get(fun);
     120        assert(fun);
     121        rh_t *rh = fun->driver_data;
    124122        assert(rh);
    125123        return &rh->resource_list;
    126124}
    127 
     125/*----------------------------------------------------------------------------*/
    128126/** Interface to provide the root hub driver with hw info */
    129127static hw_res_ops_t hw_res_iface = {
     
    131129        .enable_interrupt = NULL,
    132130};
    133 
     131/*----------------------------------------------------------------------------*/
    134132/** RH function support for uhci_rhd */
    135133static ddf_dev_ops_t rh_ops = {
     
    137135        .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface
    138136};
    139 
     137/*----------------------------------------------------------------------------*/
    140138/** Initialize hc and rh DDF structures and their respective drivers.
    141139 *
     
    150148int device_setup_uhci(ddf_dev_t *device)
    151149{
    152         bool ih_registered = false;
    153         bool hc_inited = false;
    154         bool fun_bound = false;
    155         int rc;
    156 
    157150        if (!device)
    158151                return EBADMEM;
     
    164157        }
    165158
     159#define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
     160if (ret != EOK) { \
     161        if (instance->hc_fun) \
     162                instance->hc_fun->driver_data = NULL; \
     163                ddf_fun_destroy(instance->hc_fun); \
     164        if (instance->rh_fun) {\
     165                instance->rh_fun->driver_data = NULL; \
     166                ddf_fun_destroy(instance->rh_fun); \
     167        } \
     168        usb_log_error(message); \
     169        return ret; \
     170} else (void)0
     171
     172        instance->rh_fun = NULL;
    166173        instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci_hc");
    167         if (instance->hc_fun == NULL) {
    168                 usb_log_error("Failed to create UHCI HC function.\n");
    169                 rc = ENOMEM;
    170                 goto error;
    171         }
    172 
    173         ddf_fun_set_ops(instance->hc_fun, &hc_ops);
    174         ddf_fun_data_implant(instance->hc_fun, &instance->hc.generic);
     174        int ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
     175        CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create UHCI HC function.\n");
     176        instance->hc_fun->ops = &hc_ops;
     177        instance->hc_fun->driver_data = &instance->hc.generic;
    175178
    176179        instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci_rh");
    177         if (instance->rh_fun == NULL) {
    178                 usb_log_error("Failed to create UHCI RH function.\n");
    179                 rc = ENOMEM;
    180                 goto error;
    181         }
    182 
    183         ddf_fun_set_ops(instance->rh_fun, &rh_ops);
    184         ddf_fun_data_implant(instance->rh_fun, &instance->rh);
     180        ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
     181        CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create UHCI RH function.\n");
     182        instance->rh_fun->ops = &rh_ops;
     183        instance->rh_fun->driver_data = &instance->rh;
    185184
    186185        uintptr_t reg_base = 0;
     
    188187        int irq = 0;
    189188
    190         rc = get_my_registers(device, &reg_base, &reg_size, &irq);
    191         if (rc != EOK) {
    192                 usb_log_error("Failed to get I/O addresses for %" PRIun ": %s.\n",
    193                     ddf_dev_get_handle(device), str_error(rc));
    194                 goto error;
    195         }
     189        ret = get_my_registers(device, &reg_base, &reg_size, &irq);
     190        CHECK_RET_DEST_FREE_RETURN(ret,
     191            "Failed to get I/O addresses for %" PRIun ": %s.\n",
     192            device->handle, str_error(ret));
    196193        usb_log_debug("I/O regs at 0x%p (size %zu), IRQ %d.\n",
    197194            (void *) reg_base, reg_size, irq);
    198195
    199         rc = disable_legacy(device);
    200         if (rc != EOK) {
    201                 usb_log_error("Failed to disable legacy USB: %s.\n",
    202                     str_error(rc));
    203                 goto error;
    204         }
    205 
    206         rc = hc_register_irq_handler(device, reg_base, reg_size, irq, irq_handler);
    207         if (rc != EOK) {
    208                 usb_log_error("Failed to register interrupt handler: %s.\n",
    209                     str_error(rc));
    210                 goto error;
    211         }
    212 
    213         ih_registered = true;
     196        ret = disable_legacy(device);
     197        CHECK_RET_DEST_FREE_RETURN(ret,
     198            "Failed to disable legacy USB: %s.\n", str_error(ret));
     199
     200        const size_t ranges_count = hc_irq_pio_range_count();
     201        const size_t cmds_count = hc_irq_cmd_count();
     202        irq_pio_range_t irq_ranges[ranges_count];
     203        irq_cmd_t irq_cmds[cmds_count];
     204        ret = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds,
     205            sizeof(irq_cmds), reg_base, reg_size);
     206        CHECK_RET_DEST_FREE_RETURN(ret,
     207            "Failed to generate IRQ commands: %s.\n", str_error(ret));
     208
     209        irq_code_t irq_code = {
     210                .rangecount = ranges_count,
     211                .ranges = irq_ranges,
     212                .cmdcount = cmds_count,
     213                .cmds = irq_cmds
     214        };
     215
     216        /* Register handler to avoid interrupt lockup */
     217        ret = register_interrupt_handler(device, irq, irq_handler, &irq_code);
     218        CHECK_RET_DEST_FREE_RETURN(ret,
     219            "Failed to register interrupt handler: %s.\n", str_error(ret));
    214220
    215221        bool interrupts = false;
    216         rc = enable_interrupts(device);
    217         if (rc != EOK) {
     222        ret = enable_interrupts(device);
     223        if (ret != EOK) {
    218224                usb_log_warning("Failed to enable interrupts: %s."
    219                     " Falling back to polling.\n", str_error(rc));
     225                    " Falling back to polling.\n", str_error(ret));
    220226        } else {
    221227                usb_log_debug("Hw interrupts enabled.\n");
     
    223229        }
    224230
    225         rc = hc_init(&instance->hc, (void*)reg_base, reg_size, interrupts);
    226         if (rc != EOK) {
    227                 usb_log_error("Failed to init uhci_hcd: %s.\n", str_error(rc));
    228                 goto error;
    229         }
    230 
    231         hc_inited = true;
    232 
    233         rc = ddf_fun_bind(instance->hc_fun);
    234         if (rc != EOK) {
    235                 usb_log_error("Failed to bind UHCI device function: %s.\n",
    236                     str_error(rc));
    237                 goto error;
    238         }
    239 
    240         fun_bound = true;
    241 
    242         rc = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
    243         if (rc != EOK) {
    244                 usb_log_error("Failed to add UHCI to HC class: %s.\n",
    245                     str_error(rc));
    246                 goto error;
    247         }
    248 
    249         rc = rh_init(&instance->rh, instance->rh_fun,
     231        ret = hc_init(&instance->hc, (void*)reg_base, reg_size, interrupts);
     232        CHECK_RET_DEST_FREE_RETURN(ret,
     233            "Failed to init uhci_hcd: %s.\n", str_error(ret));
     234
     235#define CHECK_RET_FINI_RETURN(ret, message...) \
     236if (ret != EOK) { \
     237        hc_fini(&instance->hc); \
     238        CHECK_RET_DEST_FREE_RETURN(ret, message); \
     239        return ret; \
     240} else (void)0
     241
     242        ret = ddf_fun_bind(instance->hc_fun);
     243        CHECK_RET_FINI_RETURN(ret, "Failed to bind UHCI device function: %s.\n",
     244            str_error(ret));
     245
     246        ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
     247        CHECK_RET_FINI_RETURN(ret,
     248            "Failed to add UHCI to HC class: %s.\n", str_error(ret));
     249
     250        ret = rh_init(&instance->rh, instance->rh_fun,
    250251            (uintptr_t)instance->hc.registers + 0x10, 4);
    251         if (rc != EOK) {
    252                 usb_log_error("Failed to setup UHCI root hub: %s.\n",
    253                     str_error(rc));
    254                 goto error;
    255         }
    256 
    257         rc = ddf_fun_bind(instance->rh_fun);
    258         if (rc != EOK) {
    259                 usb_log_error("Failed to register UHCI root hub: %s.\n",
    260                     str_error(rc));
    261                 goto error;
    262         }
     252        CHECK_RET_FINI_RETURN(ret,
     253            "Failed to setup UHCI root hub: %s.\n", str_error(ret));
     254
     255        ret = ddf_fun_bind(instance->rh_fun);
     256        CHECK_RET_FINI_RETURN(ret,
     257            "Failed to register UHCI root hub: %s.\n", str_error(ret));
    263258
    264259        return EOK;
    265 
    266 error:
    267         if (fun_bound)
    268                 ddf_fun_unbind(instance->hc_fun);
    269         if (hc_inited)
    270                 hc_fini(&instance->hc);
    271         if (ih_registered)
    272                 unregister_interrupt_handler(device, irq);
    273         if (instance->hc_fun != NULL)
    274                 ddf_fun_destroy(instance->hc_fun);
    275         if (instance->rh_fun != NULL) {
    276                 ddf_fun_destroy(instance->rh_fun);
    277         }
    278         return rc;
     260#undef CHECK_RET_FINI_RETURN
    279261}
    280262/**
Note: See TracChangeset for help on using the changeset viewer.