Ignore:
File:
1 edited

Legend:

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

    r5b89d43b r952bc66  
    3434 */
    3535
    36 /* XXX Fix this */
    37 #define _DDF_DATA_IMPLANT
    38 
     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>
    3942#include <errno.h>
    4043#include <stdbool.h>
     44#include <stdlib.h>
    4145#include <str_error.h>
    42 #include <ddf/interrupt.h>
    43 #include <usb_iface.h>
    44 #include <usb/ddfiface.h>
     46#include <sys/types.h>
     47
    4548#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>
    4653
    4754#include "uhci.h"
    4855
    49 #include "res.h"
    5056#include "hc.h"
    51 #include "root_hub.h"
    5257
    53 /** Structure representing both functions of UHCI hc, USB host controller
    54  * and USB root hub */
    55 typedef 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 
    67 static inline uhci_t *dev_to_uhci(ddf_dev_t *dev)
    68 {
    69         return ddf_dev_data_get(dev);
    70 }
    7158
    7259/** IRQ handling callback, forward status from call to diver structure.
     
    7966{
    8067        assert(dev);
    81         uhci_t *uhci = dev_to_uhci(dev);
    82         if (!uhci) {
     68        hcd_t *hcd = dev_to_hcd(dev);
     69        if (!hcd || !hcd->driver.data) {
    8370                usb_log_error("Interrupt on not yet initialized device.\n");
    8471                return;
    8572        }
    8673        const uint16_t status = IPC_GET_ARG1(*call);
    87         hc_interrupt(&uhci->hc, status);
     74        hc_interrupt(hcd->driver.data, status);
    8875}
    8976
    90 /** Operations supported by the HC driver */
    91 static 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.
     77/** Call the PCI driver with a request to clear legacy support register
    9678 *
    97  * @param[in] fun DDF function of uhci device.
    98  * @param[out] handle Host cotnroller handle.
     79 * @param[in] device Device asking to disable interrupts
    9980 * @return Error code.
    10081 */
    101 static int usb_iface_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
     82static int disable_legacy(ddf_dev_t *device)
    10283{
    103         ddf_fun_t *hc_fun = dev_to_uhci(ddf_fun_get_dev(fun))->hc_fun;
    104         assert(hc_fun);
     84        assert(device);
    10585
    106         if (handle != NULL)
    107                 *handle = ddf_fun_get_handle(hc_fun);
    108         return EOK;
     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;
    10997}
    110 
    111 /** USB interface implementation used by RH */
    112 static 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  */
    121 static 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 */
    129 static hw_res_ops_t hw_res_iface = {
    130         .get_resource_list = get_resource_list,
    131         .enable_interrupt = NULL,
    132 };
    133 
    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 
    147 /** RH function support for uhci_rhd */
    148 static 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 };
    15398
    15499/** Initialize hc and rh DDF structures and their respective drivers.
     
    164109int device_setup_uhci(ddf_dev_t *device)
    165110{
    166         bool ih_registered = false;
    167         bool hc_inited = false;
    168         bool fun_bound = false;
    169         int rc;
     111        assert(device);
    170112
    171         if (!device)
    172                 return EBADMEM;
     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);
    173125
    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         }
    209126        usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
    210127            RNGABSPTR(regs), RNGSZ(regs), irq);
    211128
    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;
     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;
    217134        }
    218135
    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;
     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;
    224141        }
    225142
    226         ih_registered = true;
    227 
    228143        bool interrupts = false;
    229         rc = enable_interrupts(device);
    230         if (rc != EOK) {
     144        ret = hcd_ddf_setup_interrupts(device, &regs, irq, irq_handler,
     145            hc_gen_irq_code);
     146        if (ret != EOK) {
    231147                usb_log_warning("Failed to enable interrupts: %s."
    232                     " Falling back to polling.\n", str_error(rc));
     148                    " Falling back to polling.\n", str_error(ret));
    233149        } else {
    234150                usb_log_debug("Hw interrupts enabled.\n");
     
    236152        }
    237153
    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;
     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;
    242159        }
    243160
    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;
     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
    251166        }
    252167
    253         fun_bound = true;
     168        hcd_set_implementation(dev_to_hcd(device), hc, hc_schedule, NULL, NULL);
    254169
    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;
     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) {
     176                usb_log_error("Failed to setup UHCI root hub: %s.\n",
     177                    str_error(ret));
     178                hc_fini(hc);
     179irq_unregister:
     180                unregister_interrupt_handler(device, irq);
     181                free(hc);
     182ddf_hc_clean:
     183                hcd_ddf_clean_hc(device);
    260184        }
    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         }
    275 
    276         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;
     185        return ret;
    291186}
    292187/**
Note: See TracChangeset for help on using the changeset viewer.