Changes in uspace/drv/bus/usb/uhci/uhci.c [952bc66:5b89d43b] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/uhci.c
r952bc66 r5b89d43b 34 34 */ 35 35 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 42 39 #include <errno.h> 43 40 #include <stdbool.h> 44 #include <stdlib.h>45 41 #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> 48 45 #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>53 46 54 47 #include "uhci.h" 55 48 49 #include "res.h" 56 50 #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 */ 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 } 58 71 59 72 /** IRQ handling callback, forward status from call to diver structure. … … 66 79 { 67 80 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) { 70 83 usb_log_error("Interrupt on not yet initialized device.\n"); 71 84 return; 72 85 } 73 86 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 */ 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. 80 99 * @return Error code. 81 100 */ 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 } 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 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 }; 98 153 99 154 /** Initialize hc and rh DDF structures and their respective drivers. … … 109 164 int device_setup_uhci(ddf_dev_t *device) 110 165 { 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, ®s, &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 } 126 209 usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n", 127 210 RNGABSPTR(regs), RNGSZ(regs), irq); 128 211 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, ®s, 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; 142 227 143 228 bool interrupts = false; 144 ret = hcd_ddf_setup_interrupts(device, ®s, irq, irq_handler, 145 hc_gen_irq_code); 146 if (ret != EOK) { 229 rc = enable_interrupts(device); 230 if (rc != EOK) { 147 231 usb_log_warning("Failed to enable interrupts: %s." 148 " Falling back to polling.\n", str_error(r et));232 " Falling back to polling.\n", str_error(rc)); 149 233 } else { 150 234 usb_log_debug("Hw interrupts enabled.\n"); … … 152 236 } 153 237 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, ®s, 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, ®s, 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, ®s, 0x10, 4); 263 if (rc != EOK) { 176 264 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 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) 180 284 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; 186 291 } 187 292 /**
Note:
See TracChangeset
for help on using the changeset viewer.