Ignore:
File:
1 edited

Legend:

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

    r5b89d43b r56fd7cf  
    3838
    3939#include <errno.h>
    40 #include <stdbool.h>
    4140#include <str_error.h>
    4241#include <ddf/interrupt.h>
     
    132131};
    133132
    134 static 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 
    143 static pio_window_ops_t pio_window_iface = {
    144         .get_pio_window = get_pio_window
    145 };
    146 
    147133/** RH function support for uhci_rhd */
    148134static ddf_dev_ops_t rh_ops = {
    149135        .interfaces[USB_DEV_IFACE] = &usb_iface,
    150         .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface,
    151         .interfaces[PIO_WINDOW_DEV_IFACE] = &pio_window_iface
     136        .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface
    152137};
    153138
     
    164149int device_setup_uhci(ddf_dev_t *device)
    165150{
    166         bool ih_registered = false;
    167         bool hc_inited = false;
    168         bool fun_bound = false;
    169         int rc;
    170 
    171151        if (!device)
    172152                return EBADMEM;
     
    178158        }
    179159
     160#define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
     161if (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;
    180172        instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci_hc");
    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 
     173        int ret = (instance->hc_fun == NULL) ? ENOMEM : EOK;
     174        CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create UHCI HC function.\n");
    187175        ddf_fun_set_ops(instance->hc_fun, &hc_ops);
    188176        ddf_fun_data_implant(instance->hc_fun, &instance->hc.generic);
    189177
    190178        instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci_rh");
    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 
     179        ret = (instance->rh_fun == NULL) ? ENOMEM : EOK;
     180        CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create UHCI RH function.\n");
    197181        ddf_fun_set_ops(instance->rh_fun, &rh_ops);
    198182        ddf_fun_data_implant(instance->rh_fun, &instance->rh);
    199183
    200         addr_range_t regs;
     184        uintptr_t reg_base = 0;
     185        size_t reg_size = 0;
    201186        int irq = 0;
    202187
    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;
     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));
    227219
    228220        bool interrupts = false;
    229         rc = enable_interrupts(device);
    230         if (rc != EOK) {
     221        ret = enable_interrupts(device);
     222        if (ret != EOK) {
    231223                usb_log_warning("Failed to enable interrupts: %s."
    232                     " Falling back to polling.\n", str_error(rc));
     224                    " Falling back to polling.\n", str_error(ret));
    233225        } else {
    234226                usb_log_debug("Hw interrupts enabled.\n");
     
    236228        }
    237229
    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         }
     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...) \
     235if (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));
    275257
    276258        return EOK;
    277 
    278 error:
    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;
     259#undef CHECK_RET_FINI_RETURN
    291260}
    292261/**
Note: See TracChangeset for help on using the changeset viewer.