Changes in uspace/drv/bus/usb/uhci/uhci.c [7de1988c:e991937] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/uhci.c
r7de1988c re991937 34 34 */ 35 35 36 /* XXX Fix this */37 #define _DDF_DATA_IMPLANT38 39 36 #include <errno.h> 40 #include <stdbool.h>41 37 #include <str_error.h> 42 38 #include <ddf/interrupt.h> 43 #include <usb_iface.h>44 #include <usb/ddfiface.h>45 39 #include <usb/debug.h> 40 #include <usb/host/hcd.h> 41 #include <usb/host/ddf_helpers.h> 46 42 47 43 #include "uhci.h" … … 49 45 #include "res.h" 50 46 #include "hc.h" 51 #include "root_hub.h"52 47 53 /** Structure representing both functions of UHCI hc, USB host controller54 * 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 }71 48 72 49 /** IRQ handling callback, forward status from call to diver structure. … … 79 56 { 80 57 assert(dev); 81 uhci_t *uhci = dev_to_uhci(dev);82 if (! uhci) {58 hcd_t *hcd = dev_to_hcd(dev); 59 if (!hcd || !hcd->private_data) { 83 60 usb_log_error("Interrupt on not yet initialized device.\n"); 84 61 return; 85 62 } 86 63 const uint16_t status = IPC_GET_ARG1(*call); 87 hc_interrupt( &uhci->hc, status);64 hc_interrupt(hcd->private_data, status); 88 65 } 89 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.96 *97 * @param[in] fun DDF function of uhci device.98 * @param[out] handle Host cotnroller handle.99 * @return Error code.100 */101 static 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 */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 /** RH function support for uhci_rhd */135 static ddf_dev_ops_t rh_ops = {136 .interfaces[USB_DEV_IFACE] = &usb_iface,137 .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface138 };139 66 140 67 /** Initialize hc and rh DDF structures and their respective drivers. … … 150 77 int device_setup_uhci(ddf_dev_t *device) 151 78 { 152 bool ih_registered = false;153 bool hc_inited = false;154 bool fun_bound = false;155 int rc;156 157 79 if (!device) 158 80 return EBADMEM; 159 81 160 uhci_t *instance = ddf_dev_data_alloc(device, sizeof(uhci_t)); 161 if (instance == NULL) { 162 usb_log_error("Failed to allocate OHCI driver.\n");163 return ENOMEM;164 } 82 #define CHECK_RET_RETURN(ret, message...) \ 83 if (ret != EOK) { \ 84 usb_log_error(message); \ 85 return ret; \ 86 } else (void)0 165 87 166 instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci_hc"); 167 if (instance->hc_fun == NULL) { 168 usb_log_error("Failed to create UHCI HC function.\n"); 169 rc = ENOMEM; 170 goto error; 171 } 172 173 ddf_fun_set_ops(instance->hc_fun, &hc_ops); 174 ddf_fun_data_implant(instance->hc_fun, &instance->hc.generic); 175 176 instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci_rh"); 177 if (instance->rh_fun == NULL) { 178 usb_log_error("Failed to create UHCI RH function.\n"); 179 rc = ENOMEM; 180 goto error; 181 } 182 183 ddf_fun_set_ops(instance->rh_fun, &rh_ops); 184 ddf_fun_data_implant(instance->rh_fun, &instance->rh); 185 186 addr_range_t regs; 88 uintptr_t reg_base = 0; 89 size_t reg_size = 0; 187 90 int irq = 0; 188 91 189 rc = get_my_registers(device, ®s, &irq); 190 if (rc != EOK) { 191 usb_log_error("Failed to get I/O addresses for %" PRIun ": %s.\n", 192 ddf_dev_get_handle(device), str_error(rc)); 193 goto error; 194 } 195 usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n", 196 RNGABSPTR(regs), RNGSZ(regs), irq); 92 int ret = get_my_registers(device, ®_base, ®_size, &irq); 93 CHECK_RET_RETURN(ret, "Failed to get I/O region for %" PRIun ": %s.\n", 94 ddf_dev_get_handle(device), str_error(ret)); 95 usb_log_debug("I/O regs at 0x%p (size %zu), IRQ %d.\n", 96 (void *) reg_base, reg_size, irq); 197 97 198 rc = disable_legacy(device); 199 if (rc != EOK) { 200 usb_log_error("Failed to disable legacy USB: %s.\n", 201 str_error(rc)); 202 goto error; 203 } 98 const size_t ranges_count = hc_irq_pio_range_count(); 99 const size_t cmds_count = hc_irq_cmd_count(); 100 irq_pio_range_t irq_ranges[ranges_count]; 101 irq_cmd_t irq_cmds[cmds_count]; 102 ret = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds, 103 sizeof(irq_cmds), reg_base, reg_size); 104 CHECK_RET_RETURN(ret, "Failed to generate IRQ commands: %s.\n", 105 str_error(ret)); 204 106 205 rc = hc_register_irq_handler(device, ®s, irq, irq_handler);206 if (rc != EOK) {207 usb_log_error("Failed to register interrupt handler: %s.\n",208 str_error(rc));209 goto error;210 } 107 irq_code_t irq_code = { 108 .rangecount = ranges_count, 109 .ranges = irq_ranges, 110 .cmdcount = cmds_count, 111 .cmds = irq_cmds 112 }; 211 113 212 ih_registered = true; 114 /* Register handler to avoid interrupt lockup */ 115 ret = register_interrupt_handler(device, irq, irq_handler, &irq_code); 116 CHECK_RET_RETURN(ret, "Failed to register interrupt handler: %s.\n", 117 str_error(ret)); 118 119 ret = disable_legacy(device); 120 CHECK_RET_RETURN(ret, "Failed to disable legacy USB: %s.\n", 121 str_error(ret)); 213 122 214 123 bool interrupts = false; 215 r c= enable_interrupts(device);216 if (r c!= EOK) {124 ret = enable_interrupts(device); 125 if (ret != EOK) { 217 126 usb_log_warning("Failed to enable interrupts: %s." 218 " Falling back to polling.\n", str_error(r c));127 " Falling back to polling.\n", str_error(ret)); 219 128 } else { 220 129 usb_log_debug("Hw interrupts enabled.\n"); … … 222 131 } 223 132 224 rc = hc_init(&instance->hc, ®s, interrupts); 225 if (rc != EOK) { 226 usb_log_error("Failed to init uhci_hcd: %s.\n", str_error(rc)); 227 goto error; 228 } 133 ret = hcd_ddf_setup_hc(device, USB_SPEED_FULL, 134 BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11); 135 CHECK_RET_RETURN(ret, "Failed to setup UHCI HCD.\n"); 136 137 hc_t *hc = malloc(sizeof(hc_t)); 138 ret = hc ? EOK : ENOMEM; 139 CHECK_RET_RETURN(ret, "Failed to allocate UHCI HC structure.\n"); 229 140 230 hc_inited = true; 141 ret = hc_init(hc, (void*)reg_base, reg_size, interrupts); 142 CHECK_RET_RETURN(ret, 143 "Failed to init uhci_hcd: %s.\n", str_error(ret)); 231 144 232 rc = ddf_fun_bind(instance->hc_fun); 233 if (rc != EOK) { 234 usb_log_error("Failed to bind UHCI device function: %s.\n", 235 str_error(rc)); 236 goto error; 237 } 145 hcd_set_implementation(dev_to_hcd(device), hc, hc_schedule, NULL, NULL); 238 146 239 fun_bound = true; 240 241 rc = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY); 242 if (rc != EOK) { 243 usb_log_error("Failed to add UHCI to HC class: %s.\n", 244 str_error(rc)); 245 goto error; 246 } 247 248 rc = rh_init(&instance->rh, instance->rh_fun, 249 (uintptr_t)instance->hc.registers + 0x10, 4); 250 if (rc != EOK) { 251 usb_log_error("Failed to setup UHCI root hub: %s.\n", 252 str_error(rc)); 253 goto error; 254 } 255 256 rc = ddf_fun_bind(instance->rh_fun); 257 if (rc != EOK) { 258 usb_log_error("Failed to register UHCI root hub: %s.\n", 259 str_error(rc)); 260 goto error; 147 /* 148 * Creating root hub registers a new USB device so HC 149 * needs to be ready at this time. 150 */ 151 ret = hcd_ddf_setup_root_hub(device); 152 if (ret != EOK) { 153 // TODO: Undo hcd_setup_device 154 hc_fini(hc); 155 CHECK_RET_RETURN(ret, "Failed to setup UHCI root hub: %s.\n", 156 str_error(ret)); 157 return ret; 261 158 } 262 159 263 160 return EOK; 264 265 error:266 if (fun_bound)267 ddf_fun_unbind(instance->hc_fun);268 if (hc_inited)269 hc_fini(&instance->hc);270 if (ih_registered)271 unregister_interrupt_handler(device, irq);272 if (instance->hc_fun != NULL)273 ddf_fun_destroy(instance->hc_fun);274 if (instance->rh_fun != NULL) {275 ddf_fun_destroy(instance->rh_fun);276 }277 return rc;278 161 } 279 162 /**
Note:
See TracChangeset
for help on using the changeset viewer.