Ignore:
File:
1 edited

Legend:

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

    r952bc66 r5b89d43b  
    3434 */
    3535
    36 #include <assert.h>
    37 #include <ddf/driver.h>
    38 #include <ddf/interrupt.h>
    39 #include <device/hw_res_parsed.h>
    40 #include <device/pci.h>
    41 #include <devman.h>
     36/* XXX Fix this */
     37#define _DDF_DATA_IMPLANT
     38
    4239#include <errno.h>
    4340#include <stdbool.h>
    44 #include <stdlib.h>
    4541#include <str_error.h>
    46 #include <sys/types.h>
    47 
     42#include <ddf/interrupt.h>
     43#include <usb_iface.h>
     44#include <usb/ddfiface.h>
    4845#include <usb/debug.h>
    49 #include <usb/usb.h>
    50 #include <usb/host/ddf_helpers.h>
    51 #include <usb/host/hcd.h>
    52 #include <usb/host/usb_bus.h>
    5346
    5447#include "uhci.h"
    5548
     49#include "res.h"
    5650#include "hc.h"
    57 
     51#include "root_hub.h"
     52
     53/** Structure representing both functions of UHCI hc, USB host controller
     54 * and USB root hub */
     55typedef struct uhci {
     56        /** Pointer to DDF representation of UHCI host controller */
     57        ddf_fun_t *hc_fun;
     58        /** Pointer to DDF representation of UHCI root hub */
     59        ddf_fun_t *rh_fun;
     60
     61        /** Internal driver's representation of UHCI host controller */
     62        hc_t hc;
     63        /** Internal driver's representation of UHCI root hub */
     64        rh_t rh;
     65} uhci_t;
     66
     67static inline uhci_t *dev_to_uhci(ddf_dev_t *dev)
     68{
     69        return ddf_dev_data_get(dev);
     70}
    5871
    5972/** IRQ handling callback, forward status from call to diver structure.
     
    6679{
    6780        assert(dev);
    68         hcd_t *hcd = dev_to_hcd(dev);
    69         if (!hcd || !hcd->driver.data) {
     81        uhci_t *uhci = dev_to_uhci(dev);
     82        if (!uhci) {
    7083                usb_log_error("Interrupt on not yet initialized device.\n");
    7184                return;
    7285        }
    7386        const uint16_t status = IPC_GET_ARG1(*call);
    74         hc_interrupt(hcd->driver.data, status);
    75 }
    76 
    77 /** Call the PCI driver with a request to clear legacy support register
    78  *
    79  * @param[in] device Device asking to disable interrupts
     87        hc_interrupt(&uhci->hc, status);
     88}
     89
     90/** Operations supported by the HC driver */
     91static ddf_dev_ops_t hc_ops = {
     92        .interfaces[USBHC_DEV_IFACE] = &hcd_iface, /* see iface.h/c */
     93};
     94
     95/** Gets handle of the respective hc.
     96 *
     97 * @param[in] fun DDF function of uhci device.
     98 * @param[out] handle Host cotnroller handle.
    8099 * @return Error code.
    81100 */
    82 static int disable_legacy(ddf_dev_t *device)
    83 {
    84         assert(device);
    85 
    86         async_sess_t *parent_sess = devman_parent_device_connect(
    87             EXCHANGE_SERIALIZE, ddf_dev_get_handle(device), IPC_FLAG_BLOCKING);
    88         if (!parent_sess)
    89                 return ENOMEM;
    90 
    91         /* See UHCI design guide page 45 for these values.
    92          * Write all WC bits in USB legacy register */
    93         const int rc = pci_config_space_write_16(parent_sess, 0xc0, 0xaf00);
    94 
    95         async_hangup(parent_sess);
    96         return rc;
    97 }
     101static int usb_iface_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
     102{
     103        ddf_fun_t *hc_fun = dev_to_uhci(ddf_fun_get_dev(fun))->hc_fun;
     104        assert(hc_fun);
     105
     106        if (handle != NULL)
     107                *handle = ddf_fun_get_handle(hc_fun);
     108        return EOK;
     109}
     110
     111/** USB interface implementation used by RH */
     112static usb_iface_t usb_iface = {
     113        .get_hc_handle = usb_iface_get_hc_handle,
     114};
     115
     116/** Get root hub hw resources (I/O registers).
     117 *
     118 * @param[in] fun Root hub function.
     119 * @return Pointer to the resource list used by the root hub.
     120 */
     121static hw_resource_list_t *get_resource_list(ddf_fun_t *fun)
     122{
     123        rh_t *rh = ddf_fun_data_get(fun);
     124        assert(rh);
     125        return &rh->resource_list;
     126}
     127
     128/** Interface to provide the root hub driver with hw info */
     129static hw_res_ops_t hw_res_iface = {
     130        .get_resource_list = get_resource_list,
     131        .enable_interrupt = NULL,
     132};
     133
     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
     147/** RH function support for uhci_rhd */
     148static ddf_dev_ops_t rh_ops = {
     149        .interfaces[USB_DEV_IFACE] = &usb_iface,
     150        .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface,
     151        .interfaces[PIO_WINDOW_DEV_IFACE] = &pio_window_iface
     152};
    98153
    99154/** Initialize hc and rh DDF structures and their respective drivers.
     
    109164int device_setup_uhci(ddf_dev_t *device)
    110165{
    111         assert(device);
    112 
    113         hw_res_list_parsed_t hw_res;
    114         int ret = hcd_ddf_get_registers(device, &hw_res);
    115         if (ret != EOK ||
    116             hw_res.irqs.count != 1 || hw_res.io_ranges.count != 1) {
    117                 usb_log_error("Failed to get register memory addresses "
    118                     "for %" PRIun ": %s.\n", ddf_dev_get_handle(device),
    119                     str_error(ret));
    120                 return ret;
    121         }
    122         addr_range_t regs = hw_res.io_ranges.ranges[0];
    123         const int irq = hw_res.irqs.irqs[0];
    124         hw_res_list_parsed_clean(&hw_res);
    125 
     166        bool ih_registered = false;
     167        bool hc_inited = false;
     168        bool fun_bound = false;
     169        int rc;
     170
     171        if (!device)
     172                return EBADMEM;
     173
     174        uhci_t *instance = ddf_dev_data_alloc(device, sizeof(uhci_t));
     175        if (instance == NULL) {
     176                usb_log_error("Failed to allocate OHCI driver.\n");
     177                return ENOMEM;
     178        }
     179
     180        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
     187        ddf_fun_set_ops(instance->hc_fun, &hc_ops);
     188        ddf_fun_data_implant(instance->hc_fun, &instance->hc.generic);
     189
     190        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
     197        ddf_fun_set_ops(instance->rh_fun, &rh_ops);
     198        ddf_fun_data_implant(instance->rh_fun, &instance->rh);
     199
     200        addr_range_t regs;
     201        int irq = 0;
     202
     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        }
    126209        usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
    127210            RNGABSPTR(regs), RNGSZ(regs), irq);
    128211
    129         ret = hcd_ddf_setup_hc(device, USB_SPEED_FULL,
    130             BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
    131         if (ret != EOK) {
    132                 usb_log_error("Failed to setup generic HCD.\n");
    133                 return ret;
    134         }
    135 
    136         hc_t *hc = malloc(sizeof(hc_t));
    137         if (!hc) {
    138                 usb_log_error("Failed to allocate UHCI HC structure.\n");
    139                 ret = ENOMEM;
    140                 goto ddf_hc_clean;
    141         }
     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;
    142227
    143228        bool interrupts = false;
    144         ret = hcd_ddf_setup_interrupts(device, &regs, irq, irq_handler,
    145             hc_gen_irq_code);
    146         if (ret != EOK) {
     229        rc = enable_interrupts(device);
     230        if (rc != EOK) {
    147231                usb_log_warning("Failed to enable interrupts: %s."
    148                     " Falling back to polling.\n", str_error(ret));
     232                    " Falling back to polling.\n", str_error(rc));
    149233        } else {
    150234                usb_log_debug("Hw interrupts enabled.\n");
     
    152236        }
    153237
    154         ret = disable_legacy(device);
    155         if (ret != EOK) {
    156                 usb_log_error("Failed to disable legacy USB: %s.\n",
    157                     str_error(ret));
    158                 goto irq_unregister;
    159         }
    160 
    161         ret = hc_init(hc, &regs, interrupts);
    162         if (ret != EOK) {
    163                 usb_log_error("Failed to init uhci_hcd: %s.\n", str_error(ret));
    164                 goto irq_unregister;
    165                 // TODO This is unfortunate, we have neither legacy nor real USB
    166         }
    167 
    168         hcd_set_implementation(dev_to_hcd(device), hc, hc_schedule, NULL, NULL);
    169 
    170         /*
    171          * Creating root hub registers a new USB device so HC
    172          * needs to be ready at this time.
    173          */
    174         ret = hcd_ddf_setup_root_hub(device);
    175         if (ret != EOK) {
     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) {
    176264                usb_log_error("Failed to setup UHCI root hub: %s.\n",
    177                     str_error(ret));
    178                 hc_fini(hc);
    179 irq_unregister:
     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        }
     275
     276        return EOK;
     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)
    180284                unregister_interrupt_handler(device, irq);
    181                 free(hc);
    182 ddf_hc_clean:
    183                 hcd_ddf_clean_hc(device);
    184         }
    185         return ret;
     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;
    186291}
    187292/**
Note: See TracChangeset for help on using the changeset viewer.