Changes in uspace/drv/bus/usb/ohci/ohci.c [e991937:7de1988c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/ohci.c
re991937 r7de1988c 34 34 */ 35 35 36 /* XXX Fix this */ 37 #define _DDF_DATA_IMPLANT 38 36 39 #include <errno.h> 37 40 #include <str_error.h> 38 41 #include <ddf/interrupt.h> 42 #include <usb_iface.h> 39 43 #include <usb/usb.h> 44 #include <usb/ddfiface.h> 40 45 #include <usb/debug.h> 41 42 #include <usb/host/ddf_helpers.h>43 46 44 47 #include "ohci.h" … … 46 49 #include "hc.h" 47 50 48 49 51 typedef struct ohci { 52 ddf_fun_t *hc_fun; 53 ddf_fun_t *rh_fun; 54 55 hc_t hc; 56 } ohci_t; 57 58 static inline ohci_t *dev_to_ohci(ddf_dev_t *dev) 59 { 60 return ddf_dev_data_get(dev); 61 } 50 62 /** IRQ handling callback, identifies device 51 63 * … … 57 69 { 58 70 assert(dev); 59 hcd_t *hcd = dev_to_hcd(dev); 60 if (!hcd || !hcd->private_data) { 71 72 ohci_t *ohci = dev_to_ohci(dev); 73 if (!ohci) { 61 74 usb_log_warning("Interrupt on device that is not ready.\n"); 62 75 return; 63 76 } 64 65 77 const uint16_t status = IPC_GET_ARG1(*call); 66 hc_interrupt(hcd->private_data, status); 67 } 78 hc_interrupt(&ohci->hc, status); 79 } 80 81 /** Get USB address assigned to root hub. 82 * 83 * @param[in] fun Root hub function. 84 * @param[out] address Store the address here. 85 * @return Error code. 86 */ 87 static int rh_get_my_address(ddf_fun_t *fun, usb_address_t *address) 88 { 89 assert(fun); 90 91 if (address != NULL) { 92 *address = dev_to_ohci(ddf_fun_get_dev(fun))->hc.rh.address; 93 } 94 95 return EOK; 96 } 97 98 /** Gets handle of the respective hc (this device, hc function). 99 * 100 * @param[in] root_hub_fun Root hub function seeking hc handle. 101 * @param[out] handle Place to write the handle. 102 * @return Error code. 103 */ 104 static int rh_get_hc_handle( 105 ddf_fun_t *fun, devman_handle_t *handle) 106 { 107 assert(fun); 108 ddf_fun_t *hc_fun = dev_to_ohci(ddf_fun_get_dev(fun))->hc_fun; 109 assert(hc_fun); 110 111 if (handle != NULL) 112 *handle = ddf_fun_get_handle(hc_fun); 113 return EOK; 114 } 115 116 /** Root hub USB interface */ 117 static usb_iface_t usb_iface = { 118 .get_hc_handle = rh_get_hc_handle, 119 .get_my_address = rh_get_my_address, 120 }; 121 122 /** Standard USB HC options (HC interface) */ 123 static ddf_dev_ops_t hc_ops = { 124 .interfaces[USBHC_DEV_IFACE] = &hcd_iface, 125 }; 126 127 /** Standard USB RH options (RH interface) */ 128 static ddf_dev_ops_t rh_ops = { 129 .interfaces[USB_DEV_IFACE] = &usb_iface, 130 }; 68 131 69 132 /** Initialize hc and rh ddf structures and their respective drivers. … … 80 143 int device_setup_ohci(ddf_dev_t *device) 81 144 { 82 #define CHECK_RET_RETURN(ret, message...) \ 83 if (ret != EOK) { \ 84 usb_log_error(message); \ 85 return ret; \ 86 } 87 88 uintptr_t reg_base = 0; 89 size_t reg_size = 0; 145 bool ih_registered = false; 146 bool hc_inited = false; 147 int rc; 148 149 if (device == NULL) 150 return EBADMEM; 151 152 ohci_t *instance = ddf_dev_data_alloc(device,sizeof(ohci_t)); 153 if (instance == NULL) { 154 usb_log_error("Failed to allocate OHCI driver.\n"); 155 return ENOMEM; 156 } 157 158 instance->hc_fun = ddf_fun_create(device, fun_exposed, "ohci_hc"); 159 if (instance->hc_fun == NULL) { 160 usb_log_error("Failed to create OHCI HC function: %s.\n", 161 str_error(ENOMEM)); 162 rc = ENOMEM; 163 goto error; 164 } 165 166 ddf_fun_set_ops(instance->hc_fun, &hc_ops); 167 ddf_fun_data_implant(instance->hc_fun, &instance->hc); 168 169 instance->rh_fun = ddf_fun_create(device, fun_inner, "ohci_rh"); 170 if (instance->rh_fun == NULL) { 171 usb_log_error("Failed to create OHCI RH function: %s.\n", 172 str_error(ENOMEM)); 173 rc = ENOMEM; 174 goto error; 175 } 176 177 ddf_fun_set_ops(instance->rh_fun, &rh_ops); 178 179 addr_range_t regs; 90 180 int irq = 0; 91 181 92 int ret = get_my_registers(device, ®_base, ®_size, &irq); 93 CHECK_RET_RETURN(ret, "Failed to get register memory addresses for %" 94 PRIun ": %s.\n", ddf_dev_get_handle(device), str_error(ret)); 182 rc = get_my_registers(device, ®s, &irq); 183 if (rc != EOK) { 184 usb_log_error("Failed to get register memory addresses " 185 "for %" PRIun ": %s.\n", ddf_dev_get_handle(device), 186 str_error(rc)); 187 goto error; 188 } 95 189 96 190 usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n", 97 (void *) reg_base, reg_size, irq); 98 99 const size_t ranges_count = hc_irq_pio_range_count(); 100 const size_t cmds_count = hc_irq_cmd_count(); 101 irq_pio_range_t irq_ranges[ranges_count]; 102 irq_cmd_t irq_cmds[cmds_count]; 103 irq_code_t irq_code = { 104 .rangecount = ranges_count, 105 .ranges = irq_ranges, 106 .cmdcount = cmds_count, 107 .cmds = irq_cmds 108 }; 109 110 ret = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds, 111 sizeof(irq_cmds), reg_base, reg_size); 112 CHECK_RET_RETURN(ret, "Failed to gen IRQ code: %s.\n", str_error(ret)); 113 114 /* Register handler to avoid interrupt lockup */ 115 ret = register_interrupt_handler(device, irq, irq_handler, &irq_code); 116 CHECK_RET_RETURN(ret, 117 "Failed to register irq handler: %s.\n", str_error(ret)); 191 RNGABSPTR(regs), RNGSZ(regs), irq); 192 193 rc = hc_register_irq_handler(device, ®s, irq, irq_handler); 194 if (rc != EOK) { 195 usb_log_error("Failed to register interrupt handler: %s.\n", 196 str_error(rc)); 197 goto error; 198 } 199 200 ih_registered = true; 118 201 119 202 /* Try to enable interrupts */ 120 203 bool interrupts = false; 121 r et= enable_interrupts(device);122 if (r et!= EOK) {204 rc = enable_interrupts(device); 205 if (rc != EOK) { 123 206 usb_log_warning("Failed to enable interrupts: %s." 124 " Falling back to polling\n", str_error(r et));207 " Falling back to polling\n", str_error(rc)); 125 208 /* We don't need that handler */ 126 209 unregister_interrupt_handler(device, irq); 210 ih_registered = false; 127 211 } else { 128 212 usb_log_debug("Hw interrupts enabled.\n"); … … 130 214 } 131 215 132 /* Initialize generic HCD driver */ 133 ret = hcd_ddf_setup_hc(device, USB_SPEED_FULL, 134 BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11); 135 if (ret != EOK) { 216 rc = hc_init(&instance->hc, ®s, interrupts); 217 if (rc != EOK) { 218 usb_log_error("Failed to init ohci_hcd: %s.\n", str_error(rc)); 219 goto error; 220 } 221 222 hc_inited = true; 223 224 rc = ddf_fun_bind(instance->hc_fun); 225 if (rc != EOK) { 226 usb_log_error("Failed to bind OHCI device function: %s.\n", 227 str_error(rc)); 228 goto error; 229 } 230 231 rc = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY); 232 if (rc != EOK) { 233 usb_log_error("Failed to add OHCI to HC category: %s.\n", 234 str_error(rc)); 235 goto error; 236 } 237 238 rc = hc_register_hub(&instance->hc, instance->rh_fun); 239 if (rc != EOK) { 240 usb_log_error("Failed to register OHCI root hub: %s.\n", 241 str_error(rc)); 242 goto error; 243 } 244 245 return EOK; 246 247 error: 248 if (hc_inited) 249 hc_fini(&instance->hc); 250 if (ih_registered) 136 251 unregister_interrupt_handler(device, irq); 137 return ret; 138 } 139 140 // TODO: Undo hcd_setup_device 141 #define CHECK_RET_CLEAN_RETURN(ret, message...) \ 142 if (ret != EOK) { \ 143 unregister_interrupt_handler(device, irq); \ 144 CHECK_RET_RETURN(ret, message); \ 145 } else (void)0 146 147 hc_t *hc_impl = malloc(sizeof(hc_t)); 148 ret = hc_impl ? EOK : ENOMEM; 149 CHECK_RET_CLEAN_RETURN(ret, "Failed to allocate driver structure.\n"); 150 151 /* Initialize OHCI HC */ 152 ret = hc_init(hc_impl, reg_base, reg_size, interrupts); 153 CHECK_RET_CLEAN_RETURN(ret, "Failed to init hc: %s.\n", str_error(ret)); 154 155 /* Connect OHCI to generic HCD */ 156 hcd_set_implementation(dev_to_hcd(device), hc_impl, 157 hc_schedule, ohci_endpoint_init, ohci_endpoint_fini); 158 159 /* HC should be running OK. We can add root hub */ 160 ret = hcd_ddf_setup_root_hub(device); 161 CHECK_RET_CLEAN_RETURN(ret, 162 "Failed to register OHCI root hub: %s.\n", str_error(ret)); 163 164 return ret; 252 if (instance->hc_fun != NULL) 253 ddf_fun_destroy(instance->hc_fun); 254 if (instance->rh_fun != NULL) 255 ddf_fun_destroy(instance->rh_fun); 256 return rc; 165 257 } 166 258 /**
Note:
See TracChangeset
for help on using the changeset viewer.