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