Ignore:
File:
1 edited

Legend:

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

    r56fd7cf r5b89d43b  
    3838
    3939#include <errno.h>
     40#include <stdbool.h>
    4041#include <str_error.h>
    4142#include <ddf/interrupt.h>
     
    131132};
    132133
     134static pio_window_t *get_pio_window(ddf_fun_t *fun)
     135{
     136        rh_t *rh = ddf_fun_data_get(fun);
     137       
     138        if (rh == NULL)
     139                return NULL;
     140        return &rh->pio_window;
     141}
     142
     143static pio_window_ops_t pio_window_iface = {
     144        .get_pio_window = get_pio_window
     145};
     146
    133147/** RH function support for uhci_rhd */
    134148static ddf_dev_ops_t rh_ops = {
    135149        .interfaces[USB_DEV_IFACE] = &usb_iface,
    136         .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface
     150        .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface,
     151        .interfaces[PIO_WINDOW_DEV_IFACE] = &pio_window_iface
    137152};
    138153
     
    149164int device_setup_uhci(ddf_dev_t *device)
    150165{
     166        bool ih_registered = false;
     167        bool hc_inited = false;
     168        bool fun_bound = false;
     169        int rc;
     170
    151171        if (!device)
    152172                return EBADMEM;
     
    158178        }
    159179
    160 #define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
    161 if (ret != EOK) { \
    162         if (instance->hc_fun) \
    163                 ddf_fun_destroy(instance->hc_fun); \
    164         if (instance->rh_fun) {\
    165                 ddf_fun_destroy(instance->rh_fun); \
    166         } \
    167         usb_log_error(message); \
    168         return ret; \
    169 } else (void)0
    170 
    171         instance->rh_fun = NULL;
    172180        instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci_hc");
    173         int ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
    174         CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create UHCI HC function.\n");
     181        if (instance->hc_fun == NULL) {
     182                usb_log_error("Failed to create UHCI HC function.\n");
     183                rc = ENOMEM;
     184                goto error;
     185        }
     186
    175187        ddf_fun_set_ops(instance->hc_fun, &hc_ops);
    176188        ddf_fun_data_implant(instance->hc_fun, &instance->hc.generic);
    177189
    178190        instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci_rh");
    179         ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
    180         CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create UHCI RH function.\n");
     191        if (instance->rh_fun == NULL) {
     192                usb_log_error("Failed to create UHCI RH function.\n");
     193                rc = ENOMEM;
     194                goto error;
     195        }
     196
    181197        ddf_fun_set_ops(instance->rh_fun, &rh_ops);
    182198        ddf_fun_data_implant(instance->rh_fun, &instance->rh);
    183199
    184         uintptr_t reg_base = 0;
    185         size_t reg_size = 0;
     200        addr_range_t regs;
    186201        int irq = 0;
    187202
    188         ret = get_my_registers(device, &reg_base, &reg_size, &irq);
    189         CHECK_RET_DEST_FREE_RETURN(ret,
    190             "Failed to get I/O addresses for %" PRIun ": %s.\n",
    191             ddf_dev_get_handle(device), str_error(ret));
    192         usb_log_debug("I/O regs at 0x%p (size %zu), IRQ %d.\n",
    193             (void *) reg_base, reg_size, irq);
    194 
    195         ret = disable_legacy(device);
    196         CHECK_RET_DEST_FREE_RETURN(ret,
    197             "Failed to disable legacy USB: %s.\n", str_error(ret));
    198 
    199         const size_t ranges_count = hc_irq_pio_range_count();
    200         const size_t cmds_count = hc_irq_cmd_count();
    201         irq_pio_range_t irq_ranges[ranges_count];
    202         irq_cmd_t irq_cmds[cmds_count];
    203         ret = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds,
    204             sizeof(irq_cmds), reg_base, reg_size);
    205         CHECK_RET_DEST_FREE_RETURN(ret,
    206             "Failed to generate IRQ commands: %s.\n", str_error(ret));
    207 
    208         irq_code_t irq_code = {
    209                 .rangecount = ranges_count,
    210                 .ranges = irq_ranges,
    211                 .cmdcount = cmds_count,
    212                 .cmds = irq_cmds
    213         };
    214 
    215         /* Register handler to avoid interrupt lockup */
    216         ret = register_interrupt_handler(device, irq, irq_handler, &irq_code);
    217         CHECK_RET_DEST_FREE_RETURN(ret,
    218             "Failed to register interrupt handler: %s.\n", str_error(ret));
     203        rc = get_my_registers(device, &regs, &irq);
     204        if (rc != EOK) {
     205                usb_log_error("Failed to get I/O addresses for %" PRIun ": %s.\n",
     206                    ddf_dev_get_handle(device), str_error(rc));
     207                goto error;
     208        }
     209        usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
     210            RNGABSPTR(regs), RNGSZ(regs), irq);
     211
     212        rc = disable_legacy(device);
     213        if (rc != EOK) {
     214                usb_log_error("Failed to disable legacy USB: %s.\n",
     215                    str_error(rc));
     216                goto error;
     217        }
     218
     219        rc = hc_register_irq_handler(device, &regs, irq, irq_handler);
     220        if (rc != EOK) {
     221                usb_log_error("Failed to register interrupt handler: %s.\n",
     222                    str_error(rc));
     223                goto error;
     224        }
     225
     226        ih_registered = true;
    219227
    220228        bool interrupts = false;
    221         ret = enable_interrupts(device);
    222         if (ret != EOK) {
     229        rc = enable_interrupts(device);
     230        if (rc != EOK) {
    223231                usb_log_warning("Failed to enable interrupts: %s."
    224                     " Falling back to polling.\n", str_error(ret));
     232                    " Falling back to polling.\n", str_error(rc));
    225233        } else {
    226234                usb_log_debug("Hw interrupts enabled.\n");
     
    228236        }
    229237
    230         ret = hc_init(&instance->hc, (void*)reg_base, reg_size, interrupts);
    231         CHECK_RET_DEST_FREE_RETURN(ret,
    232             "Failed to init uhci_hcd: %s.\n", str_error(ret));
    233 
    234 #define CHECK_RET_FINI_RETURN(ret, message...) \
    235 if (ret != EOK) { \
    236         hc_fini(&instance->hc); \
    237         CHECK_RET_DEST_FREE_RETURN(ret, message); \
    238         return ret; \
    239 } else (void)0
    240 
    241         ret = ddf_fun_bind(instance->hc_fun);
    242         CHECK_RET_FINI_RETURN(ret, "Failed to bind UHCI device function: %s.\n",
    243             str_error(ret));
    244 
    245         ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
    246         CHECK_RET_FINI_RETURN(ret,
    247             "Failed to add UHCI to HC class: %s.\n", str_error(ret));
    248 
    249         ret = rh_init(&instance->rh, instance->rh_fun,
    250             (uintptr_t)instance->hc.registers + 0x10, 4);
    251         CHECK_RET_FINI_RETURN(ret,
    252             "Failed to setup UHCI root hub: %s.\n", str_error(ret));
    253 
    254         ret = ddf_fun_bind(instance->rh_fun);
    255         CHECK_RET_FINI_RETURN(ret,
    256             "Failed to register UHCI root hub: %s.\n", str_error(ret));
     238        rc = hc_init(&instance->hc, &regs, interrupts);
     239        if (rc != EOK) {
     240                usb_log_error("Failed to init uhci_hcd: %s.\n", str_error(rc));
     241                goto error;
     242        }
     243
     244        hc_inited = true;
     245
     246        rc = ddf_fun_bind(instance->hc_fun);
     247        if (rc != EOK) {
     248                usb_log_error("Failed to bind UHCI device function: %s.\n",
     249                    str_error(rc));
     250                goto error;
     251        }
     252
     253        fun_bound = true;
     254
     255        rc = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
     256        if (rc != EOK) {
     257                usb_log_error("Failed to add UHCI to HC class: %s.\n",
     258                    str_error(rc));
     259                goto error;
     260        }
     261
     262        rc = rh_init(&instance->rh, instance->rh_fun, &regs, 0x10, 4);
     263        if (rc != EOK) {
     264                usb_log_error("Failed to setup UHCI root hub: %s.\n",
     265                    str_error(rc));
     266                goto error;
     267        }
     268
     269        rc = ddf_fun_bind(instance->rh_fun);
     270        if (rc != EOK) {
     271                usb_log_error("Failed to register UHCI root hub: %s.\n",
     272                    str_error(rc));
     273                goto error;
     274        }
    257275
    258276        return EOK;
    259 #undef CHECK_RET_FINI_RETURN
     277
     278error:
     279        if (fun_bound)
     280                ddf_fun_unbind(instance->hc_fun);
     281        if (hc_inited)
     282                hc_fini(&instance->hc);
     283        if (ih_registered)
     284                unregister_interrupt_handler(device, irq);
     285        if (instance->hc_fun != NULL)
     286                ddf_fun_destroy(instance->hc_fun);
     287        if (instance->rh_fun != NULL) {
     288                ddf_fun_destroy(instance->rh_fun);
     289        }
     290        return rc;
    260291}
    261292/**
Note: See TracChangeset for help on using the changeset viewer.