Changes in uspace/drv/bus/usb/ohci/hc.c [b5111c46:b5f813c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hc.c
rb5111c46 rb5f813c 34 34 */ 35 35 36 #include <assert.h> 37 #include <async.h> 36 38 #include <errno.h> 37 #include <stdbool.h> 39 #include <macros.h> 40 #include <mem.h> 41 #include <stdlib.h> 38 42 #include <str_error.h> 39 #include <adt/list.h> 40 #include <libarch/ddi.h> 43 #include <sys/types.h> 41 44 42 45 #include <usb/debug.h> 43 46 #include <usb/usb.h> 44 #include <usb/ddfiface.h> 47 48 #include "ohci_endpoint.h" 49 #include "ohci_batch.h" 45 50 46 51 #include "hc.h" 47 #include "ohci_endpoint.h"48 52 49 53 #define OHCI_USED_INTERRUPTS \ … … 84 88 }; 85 89 86 enum {87 /** Number of PIO ranges used in IRQ code */88 hc_irq_pio_range_count =89 sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t),90 91 /** Number of commands used in IRQ code */92 hc_irq_cmd_count =93 sizeof(ohci_irq_commands) / sizeof(irq_cmd_t)94 };95 96 90 static void hc_gain_control(hc_t *instance); 97 91 static void hc_start(hc_t *instance); 98 92 static int hc_init_transfer_lists(hc_t *instance); 99 93 static int hc_init_memory(hc_t *instance); 100 static int interrupt_emulator(hc_t *instance);101 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);102 94 103 95 /** Generate IRQ code. … … 106 98 * @param[out] cmds Commands buffer. 107 99 * @param[in] cmds_size Size of the commands buffer (bytes). 108 * @param[in] regs Device's register range.100 * @param[in] hw_res Device's resources. 109 101 * 110 102 * @return Error code. 111 103 */ 112 int 113 hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[], 114 size_t cmds_size, addr_range_t *regs) 115 { 116 if ((ranges_size < sizeof(ohci_pio_ranges)) || 117 (cmds_size < sizeof(ohci_irq_commands)) || 118 (RNGSZ(*regs) < sizeof(ohci_regs_t))) 104 int ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res) 105 { 106 assert(code); 107 assert(hw_res); 108 109 if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1) 110 return EINVAL; 111 112 const addr_range_t regs = hw_res->mem_ranges.ranges[0]; 113 114 if (RNGSZ(regs) < sizeof(ohci_regs_t)) 119 115 return EOVERFLOW; 120 116 121 memcpy(ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges)); 122 ranges[0].base = RNGABS(*regs); 123 124 memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands)); 125 ohci_regs_t *registers = (ohci_regs_t *) RNGABSPTR(*regs); 126 cmds[0].addr = (void *) ®isters->interrupt_status; 127 cmds[3].addr = (void *) ®isters->interrupt_status; 128 OHCI_WR(cmds[1].value, OHCI_USED_INTERRUPTS); 129 130 return EOK; 131 } 132 133 /** Register interrupt handler. 134 * 135 * @param[in] device Host controller DDF device 136 * @param[in] regs Register range 137 * @param[in] irq Interrupt number 138 * @paran[in] handler Interrupt handler 139 * 140 * @return EOK on success or negative error code 141 */ 142 int hc_register_irq_handler(ddf_dev_t *device, addr_range_t *regs, int irq, 143 interrupt_handler_t handler) 144 { 145 int rc; 146 147 irq_pio_range_t irq_ranges[hc_irq_pio_range_count]; 148 irq_cmd_t irq_cmds[hc_irq_cmd_count]; 149 150 irq_code_t irq_code = { 151 .rangecount = hc_irq_pio_range_count, 152 .ranges = irq_ranges, 153 .cmdcount = hc_irq_cmd_count, 154 .cmds = irq_cmds 155 }; 156 157 rc = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds, 158 sizeof(irq_cmds), regs); 159 if (rc != EOK) { 160 usb_log_error("Failed to generate IRQ code: %s.\n", 161 str_error(rc)); 162 return rc; 163 } 164 165 /* Register handler to avoid interrupt lockup */ 166 rc = register_interrupt_handler(device, irq, handler, &irq_code); 167 if (rc != EOK) { 168 usb_log_error("Failed to register interrupt handler: %s.\n", 169 str_error(rc)); 170 return rc; 171 } 172 173 return EOK; 174 } 175 176 /** Announce OHCI root hub to the DDF 177 * 178 * @param[in] instance OHCI driver intance 179 * @param[in] hub_fun DDF fuction representing OHCI root hub 180 * @return Error code 181 */ 182 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun) 183 { 184 bool addr_reqd = false; 185 bool ep_added = false; 186 bool fun_bound = false; 187 int rc; 188 189 assert(instance); 190 assert(hub_fun); 191 192 /* Try to get address 1 for root hub. */ 193 instance->rh.address = 1; 194 rc = usb_device_manager_request_address( 195 &instance->generic->dev_manager, &instance->rh.address, false, 196 USB_SPEED_FULL); 197 if (rc != EOK) { 198 usb_log_error("Failed to get OHCI root hub address: %s\n", 199 str_error(rc)); 200 goto error; 201 } 202 203 addr_reqd = true; 204 205 rc = usb_endpoint_manager_add_ep( 206 &instance->generic->ep_manager, instance->rh.address, 0, 207 USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64, 208 0, NULL, NULL); 209 if (rc != EOK) { 210 usb_log_error("Failed to register root hub control endpoint: %s.\n", 211 str_error(rc)); 212 goto error; 213 } 214 215 ep_added = true; 216 217 rc = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100); 218 if (rc != EOK) { 219 usb_log_error("Failed to add root hub match-id: %s.\n", 220 str_error(rc)); 221 goto error; 222 } 223 224 rc = ddf_fun_bind(hub_fun); 225 if (rc != EOK) { 226 usb_log_error("Failed to bind root hub function: %s.\n", 227 str_error(rc)); 228 goto error; 229 } 230 231 fun_bound = true; 232 233 rc = usb_device_manager_bind_address(&instance->generic->dev_manager, 234 instance->rh.address, ddf_fun_get_handle(hub_fun)); 235 if (rc != EOK) { 236 usb_log_warning("Failed to bind root hub address: %s.\n", 237 str_error(rc)); 238 } 239 240 return EOK; 241 error: 242 if (fun_bound) 243 ddf_fun_unbind(hub_fun); 244 if (ep_added) { 245 usb_endpoint_manager_remove_ep( 246 &instance->generic->ep_manager, instance->rh.address, 0, 247 USB_DIRECTION_BOTH, NULL, NULL); 248 } 249 if (addr_reqd) { 250 usb_device_manager_release_address( 251 &instance->generic->dev_manager, instance->rh.address); 252 } 253 return rc; 117 code->ranges = malloc(sizeof(ohci_pio_ranges)); 118 if (code->ranges == NULL) 119 return ENOMEM; 120 121 code->cmds = malloc(sizeof(ohci_irq_commands)); 122 if (code->cmds == NULL) { 123 free(code->ranges); 124 return ENOMEM; 125 } 126 127 code->rangecount = ARRAY_SIZE(ohci_pio_ranges); 128 code->cmdcount = ARRAY_SIZE(ohci_irq_commands); 129 130 memcpy(code->ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges)); 131 code->ranges[0].base = RNGABS(regs); 132 133 memcpy(code->cmds, ohci_irq_commands, sizeof(ohci_irq_commands)); 134 ohci_regs_t *registers = (ohci_regs_t *) RNGABSPTR(regs); 135 code->cmds[0].addr = (void *) ®isters->interrupt_status; 136 code->cmds[3].addr = (void *) ®isters->interrupt_status; 137 OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS); 138 139 usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n", 140 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 141 142 return hw_res->irqs.irqs[0]; 254 143 } 255 144 … … 257 146 * 258 147 * @param[in] instance Memory place for the structure. 259 * @param[in] HC function node 260 * @param[in] regs Device's I/O registers range. 148 * @param[in] regs Device's resources 261 149 * @param[in] interrupts True if w interrupts should be used 262 150 * @return Error code 263 151 */ 264 int hc_init(hc_t *instance, ddf_fun_t *fun, addr_range_t *regs, bool interrupts) 265 { 266 assert(instance); 267 268 int rc = pio_enable_range(regs, (void **) &instance->registers); 269 if (rc != EOK) { 270 usb_log_error("Failed to gain access to device registers: %s.\n", 271 str_error(rc)); 272 return rc; 273 } 152 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts) 153 { 154 assert(instance); 155 assert(hw_res); 156 if (hw_res->mem_ranges.count != 1 || 157 hw_res->mem_ranges.ranges[0].size < sizeof(ohci_regs_t)) 158 return EINVAL; 159 160 int ret = pio_enable_range(&hw_res->mem_ranges.ranges[0], 161 (void **) &instance->registers); 162 if (ret != EOK) { 163 usb_log_error("Failed to gain access to registers: %s.\n", 164 str_error(ret)); 165 return ret; 166 } 167 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n", 168 hw_res->mem_ranges.ranges[0].address.absolute, 169 hw_res->mem_ranges.ranges[0].size); 274 170 275 171 list_initialize(&instance->pending_batches); 276 277 instance->generic = ddf_fun_data_alloc(fun, sizeof(hcd_t)); 278 if (instance->generic == NULL) { 279 usb_log_error("Out of memory.\n"); 280 return ENOMEM; 281 } 282 283 hcd_init(instance->generic, USB_SPEED_FULL, 284 BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11); 285 instance->generic->private_data = instance; 286 instance->generic->schedule = hc_schedule; 287 instance->generic->ep_add_hook = ohci_endpoint_init; 288 instance->generic->ep_remove_hook = ohci_endpoint_fini; 289 290 rc = hc_init_memory(instance); 291 if (rc != EOK) { 172 fibril_mutex_initialize(&instance->guard); 173 instance->hw_interrupts = interrupts; 174 175 ret = hc_init_memory(instance); 176 if (ret != EOK) { 292 177 usb_log_error("Failed to create OHCI memory structures: %s.\n", 293 str_error(rc)); 294 return rc; 295 } 296 297 fibril_mutex_initialize(&instance->guard); 178 str_error(ret)); 179 //TODO: We should disable pio access here 180 return ret; 181 } 298 182 299 183 hc_gain_control(instance); 300 184 301 if (!interrupts) { 302 instance->interrupt_emulator = 303 fibril_create((int(*)(void*))interrupt_emulator, instance); 304 fibril_add_ready(instance->interrupt_emulator); 305 } 306 307 rh_init(&instance->rh, instance->registers); 185 ohci_rh_init(&instance->rh, instance->registers, "ohci rh"); 308 186 hc_start(instance); 309 187 310 188 return EOK; 311 189 } 190 191 /** Safely dispose host controller internal structures 192 * 193 * @param[in] instance Host controller structure to use. 194 */ 195 void hc_fini(hc_t *instance) 196 { 197 assert(instance); 198 /* TODO: implement*/ 199 }; 312 200 313 201 void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep) … … 379 267 } 380 268 269 int ohci_hc_status(hcd_t *hcd, uint32_t *status) 270 { 271 assert(hcd); 272 assert(status); 273 hc_t *instance = hcd_get_driver_data(hcd); 274 assert(instance); 275 276 if (instance->registers){ 277 *status = OHCI_RD(instance->registers->interrupt_status); 278 OHCI_WR(instance->registers->interrupt_status, *status); 279 } 280 return EOK; 281 } 282 381 283 /** Add USB transfer to the schedule. 382 284 * 383 * @param[in] instance OHCI hcdriver structure.285 * @param[in] hcd HCD driver structure. 384 286 * @param[in] batch Batch representing the transfer. 385 287 * @return Error code. 386 288 */ 387 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)289 int ohci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 388 290 { 389 291 assert(hcd); 390 hc_t *instance = hcd ->private_data;292 hc_t *instance = hcd_get_driver_data(hcd); 391 293 assert(instance); 392 294 393 295 /* Check for root hub communication */ 394 if (batch->ep->address == instance->rh.address) {296 if (batch->ep->address == ohci_rh_get_address(&instance->rh)) { 395 297 usb_log_debug("OHCI root hub request.\n"); 396 rh_request(&instance->rh, batch); 397 return EOK; 298 return ohci_rh_schedule(&instance->rh, batch); 398 299 } 399 300 ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch); … … 423 324 /** Interrupt handling routine 424 325 * 425 * @param[in] instance OHCI hcdriver structure.326 * @param[in] hcd HCD driver structure. 426 327 * @param[in] status Value of the status register at the time of interrupt. 427 328 */ 428 void hc_interrupt(hc_t *instance, uint32_t status) 429 { 329 void ohci_hc_interrupt(hcd_t *hcd, uint32_t status) 330 { 331 assert(hcd); 332 hc_t *instance = hcd_get_driver_data(hcd); 430 333 status = OHCI_RD(status); 431 334 assert(instance); … … 434 337 usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status); 435 338 if (status & I_RHSC) 436 rh_interrupt(&instance->rh);339 ohci_rh_interrupt(&instance->rh); 437 340 438 341 if (status & I_WDH) { … … 465 368 } 466 369 467 }468 469 /** Check status register regularly470 *471 * @param[in] instance OHCI hc driver structure.472 * @return Error code473 */474 int interrupt_emulator(hc_t *instance)475 {476 assert(instance);477 usb_log_info("Started interrupt emulator.\n");478 while (1) {479 const uint32_t status = instance->registers->interrupt_status;480 instance->registers->interrupt_status = status;481 hc_interrupt(instance, status);482 async_usleep(10000);483 }484 return EOK;485 370 } 486 371 … … 508 393 ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg)); 509 394 /* Zero everything but A20State */ 395 //TODO: should we ack interrupts before doing this? 510 396 OHCI_CLR(*ohci_emulation_reg, ~0x100); 511 397 usb_log_debug( … … 517 403 if (OHCI_RD(instance->registers->control) & C_IR) { 518 404 usb_log_debug("SMM driver: request ownership change.\n"); 405 //TODO: should we ack interrupts before doing this? 519 406 OHCI_SET(instance->registers->command_status, CS_OCR); 520 407 /* Hope that SMM actually knows its stuff or we can hang here */ 521 while (OHCI_RD(instance->registers->control & C_IR)) {408 while (OHCI_RD(instance->registers->control) & C_IR) { 522 409 async_usleep(1000); 523 410 } … … 603 490 604 491 /* Enable interrupts */ 605 OHCI_WR(instance->registers->interrupt_enable, OHCI_USED_INTERRUPTS); 606 usb_log_debug("Enabled interrupts: %x.\n", 607 OHCI_RD(instance->registers->interrupt_enable)); 608 OHCI_WR(instance->registers->interrupt_enable, I_MI); 492 if (instance->hw_interrupts) { 493 OHCI_WR(instance->registers->interrupt_enable, 494 OHCI_USED_INTERRUPTS); 495 usb_log_debug("Enabled interrupts: %x.\n", 496 OHCI_RD(instance->registers->interrupt_enable)); 497 OHCI_WR(instance->registers->interrupt_enable, I_MI); 498 } 609 499 610 500 /* Set periodic start to 90% */ … … 632 522 do { \ 633 523 const char *name = usb_str_transfer_type(type); \ 634 int ret = endpoint_list_init(&instance->lists[type], name); \524 const int ret = endpoint_list_init(&instance->lists[type], name); \ 635 525 if (ret != EOK) { \ 636 526 usb_log_error("Failed to setup %s endpoint list: %s.\n", \
Note:
See TracChangeset
for help on using the changeset viewer.