00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <errno.h>
00036 #include <str_error.h>
00037 #include <ddf/interrupt.h>
00038 #include <usb_iface.h>
00039 #include <usb/usb.h>
00040 #include <usb/ddfiface.h>
00041 #include <usb/debug.h>
00042
00043 #include "ohci.h"
00044 #include "iface.h"
00045 #include "pci.h"
00046 #include "hc.h"
00047 #include "root_hub.h"
00048
00049 typedef struct ohci {
00050 ddf_fun_t *hc_fun;
00051 ddf_fun_t *rh_fun;
00052
00053 hc_t hc;
00054 rh_t rh;
00055 } ohci_t;
00056
00057 static inline ohci_t * dev_to_ohci(ddf_dev_t *dev)
00058 {
00059 assert(dev);
00060 assert(dev->driver_data);
00061 return dev->driver_data;
00062 }
00063
00070 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call)
00071 {
00072 hc_t *hc = &dev_to_ohci(dev)->hc;
00073 assert(hc);
00074 const uint16_t status = IPC_GET_ARG1(*call);
00075 hc_interrupt(hc, status);
00076 }
00077
00084 static int usb_iface_get_address(
00085 ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address)
00086 {
00087 assert(fun);
00088 usb_device_keeper_t *manager = &dev_to_ohci(fun->dev)->hc.manager;
00089
00090 usb_address_t addr = usb_device_keeper_find(manager, handle);
00091 if (addr < 0) {
00092 return addr;
00093 }
00094
00095 if (address != NULL) {
00096 *address = addr;
00097 }
00098
00099 return EOK;
00100 }
00101
00108 static int usb_iface_get_hc_handle(
00109 ddf_fun_t *fun, devman_handle_t *handle)
00110 {
00111 assert(fun);
00112 ddf_fun_t *hc_fun = dev_to_ohci(fun->dev)->hc_fun;
00113 assert(hc_fun);
00114
00115 if (handle != NULL)
00116 *handle = hc_fun->handle;
00117 return EOK;
00118 }
00119
00121 static usb_iface_t usb_iface = {
00122 .get_hc_handle = usb_iface_get_hc_handle,
00123 .get_address = usb_iface_get_address
00124 };
00125
00127 static ddf_dev_ops_t hc_ops = {
00128 .interfaces[USBHC_DEV_IFACE] = &hc_iface,
00129 };
00130
00132 static ddf_dev_ops_t rh_ops = {
00133 .interfaces[USB_DEV_IFACE] = &usb_iface,
00134 };
00135
00147 int device_setup_ohci(ddf_dev_t *device)
00148 {
00149 ohci_t *instance = malloc(sizeof(ohci_t));
00150 if (instance == NULL) {
00151 usb_log_error("Failed to allocate OHCI driver.\n");
00152 return ENOMEM;
00153 }
00154
00155 #define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
00156 if (ret != EOK) { \
00157 if (instance->hc_fun) { \
00158 instance->hc_fun->ops = NULL; \
00159 instance->hc_fun->driver_data = NULL; \
00160 ddf_fun_destroy(instance->hc_fun); \
00161 } \
00162 if (instance->rh_fun) { \
00163 instance->rh_fun->ops = NULL; \
00164 instance->rh_fun->driver_data = NULL; \
00165 ddf_fun_destroy(instance->rh_fun); \
00166 } \
00167 free(instance); \
00168 usb_log_error(message); \
00169 return ret; \
00170 } else (void)0
00171
00172 instance->rh_fun = NULL;
00173 instance->hc_fun = ddf_fun_create(device, fun_exposed, "ohci-hc");
00174 int ret = instance->hc_fun ? EOK : ENOMEM;
00175 CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create OHCI HC function.\n");
00176 instance->hc_fun->ops = &hc_ops;
00177 instance->hc_fun->driver_data = &instance->hc;
00178
00179 instance->rh_fun = ddf_fun_create(device, fun_inner, "ohci-rh");
00180 ret = instance->rh_fun ? EOK : ENOMEM;
00181 CHECK_RET_DEST_FREE_RETURN(ret, "Failed to create OHCI RH function.\n");
00182 instance->rh_fun->ops = &rh_ops;
00183
00184 uintptr_t reg_base = 0;
00185 size_t reg_size = 0;
00186 int irq = 0;
00187
00188 ret = pci_get_my_registers(device, ®_base, ®_size, &irq);
00189 CHECK_RET_DEST_FREE_RETURN(ret,
00190 "Failed to get memory addresses for %" PRIun ": %s.\n",
00191 device->handle, str_error(ret));
00192 usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
00193 (void *) reg_base, reg_size, irq);
00194
00195 bool interrupts = false;
00196 #ifdef CONFIG_USBHC_NO_INTERRUPTS
00197 usb_log_warning("Interrupts disabled in OS config, "
00198 "falling back to polling.\n");
00199 #else
00200 ret = pci_enable_interrupts(device);
00201 if (ret != EOK) {
00202 usb_log_warning("Failed to enable interrupts: %s.\n",
00203 str_error(ret));
00204 usb_log_info("HW interrupts not available, "
00205 "falling back to polling.\n");
00206 } else {
00207 usb_log_debug("Hw interrupts enabled.\n");
00208 interrupts = true;
00209 }
00210 #endif
00211
00212 ret = hc_init(&instance->hc, reg_base, reg_size, interrupts);
00213 CHECK_RET_DEST_FREE_RETURN(ret, "Failed(%d) to init ohci-hcd.\n", ret);
00214
00215 #define CHECK_RET_FINI_RETURN(ret, message...) \
00216 if (ret != EOK) { \
00217 hc_fini(&instance->hc); \
00218 CHECK_RET_DEST_FREE_RETURN(ret, message); \
00219 } else (void)0
00220
00221
00222 ret = register_interrupt_handler(device, irq, irq_handler,
00223 &instance->hc.interrupt_code);
00224 CHECK_RET_FINI_RETURN(ret,
00225 "Failed(%d) to register interrupt handler.\n", ret);
00226
00227 ret = ddf_fun_bind(instance->hc_fun);
00228 CHECK_RET_FINI_RETURN(ret,
00229 "Failed(%d) to bind OHCI device function: %s.\n",
00230 ret, str_error(ret));
00231
00232 ret = ddf_fun_add_to_class(instance->hc_fun, USB_HC_DDF_CLASS_NAME);
00233 CHECK_RET_FINI_RETURN(ret,
00234 "Failed to add OHCI to HC class: %s.\n", str_error(ret));
00235
00236 device->driver_data = instance;
00237
00238 hc_start_hw(&instance->hc);
00239 hc_register_hub(&instance->hc, instance->rh_fun);
00240 return EOK;
00241
00242 #undef CHECK_RET_DEST_FUN_RETURN
00243 #undef CHECK_RET_FINI_RETURN
00244 }