Changes in uspace/drv/bus/usb/uhci/uhci.c [5b89d43b:952bc66] in mainline
- File:
-
- 1 edited
-
uspace/drv/bus/usb/uhci/uhci.c (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/uhci.c
r5b89d43b r952bc66 34 34 */ 35 35 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> 39 42 #include <errno.h> 40 43 #include <stdbool.h> 44 #include <stdlib.h> 41 45 #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 45 48 #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> 46 53 47 54 #include "uhci.h" 48 55 49 #include "res.h"50 56 #include "hc.h" 51 #include "root_hub.h"52 57 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 58 72 59 /** IRQ handling callback, forward status from call to diver structure. … … 79 66 { 80 67 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) { 83 70 usb_log_error("Interrupt on not yet initialized device.\n"); 84 71 return; 85 72 } 86 73 const uint16_t status = IPC_GET_ARG1(*call); 87 hc_interrupt( &uhci->hc, status);74 hc_interrupt(hcd->driver.data, status); 88 75 } 89 76 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 96 78 * 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 99 80 * @return Error code. 100 81 */ 101 static int usb_iface_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)82 static int disable_legacy(ddf_dev_t *device) 102 83 { 103 ddf_fun_t *hc_fun = dev_to_uhci(ddf_fun_get_dev(fun))->hc_fun; 104 assert(hc_fun); 84 assert(device); 105 85 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; 109 97 } 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_window145 };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_iface152 };153 98 154 99 /** Initialize hc and rh DDF structures and their respective drivers. … … 164 109 int device_setup_uhci(ddf_dev_t *device) 165 110 { 166 bool ih_registered = false; 167 bool hc_inited = false; 168 bool fun_bound = false; 169 int rc; 111 assert(device); 170 112 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); 173 125 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 }209 126 usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n", 210 127 RNGABSPTR(regs), RNGSZ(regs), irq); 211 128 212 r c = 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; 217 134 } 218 135 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;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; 224 141 } 225 142 226 ih_registered = true;227 228 143 bool interrupts = false; 229 rc = enable_interrupts(device); 230 if (rc != EOK) { 144 ret = hcd_ddf_setup_interrupts(device, ®s, irq, irq_handler, 145 hc_gen_irq_code); 146 if (ret != EOK) { 231 147 usb_log_warning("Failed to enable interrupts: %s." 232 " Falling back to polling.\n", str_error(r c));148 " Falling back to polling.\n", str_error(ret)); 233 149 } else { 234 150 usb_log_debug("Hw interrupts enabled.\n"); … … 236 152 } 237 153 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; 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; 242 159 } 243 160 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, ®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 251 166 } 252 167 253 fun_bound = true;168 hcd_set_implementation(dev_to_hcd(device), hc, hc_schedule, NULL, NULL); 254 169 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); 179 irq_unregister: 180 unregister_interrupt_handler(device, irq); 181 free(hc); 182 ddf_hc_clean: 183 hcd_ddf_clean_hc(device); 260 184 } 261 262 rc = rh_init(&instance->rh, instance->rh_fun, ®s, 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; 291 186 } 292 187 /**
Note:
See TracChangeset
for help on using the changeset viewer.
