Changes in uspace/drv/bus/usb/uhci/hc.c [68e5406:f3ae58b] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
r68e5406 rf3ae58b 50 50 #include <usb/usb.h> 51 51 #include <usb/host/utils/malloc32.h> 52 #include <usb/host/bandwidth.h> 53 #include <usb/host/utility.h> 52 54 53 55 #include "uhci_batch.h" 56 #include "transfer_list.h" 54 57 #include "hc.h" 55 58 … … 103 106 * @param[out] code IRQ code structure. 104 107 * @param[in] hw_res Device's resources. 105 * @param[out] irq106 108 * 107 109 * @return Error code. 108 110 */ 109 int uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res, int *irq)111 int hc_gen_irq_code(irq_code_t *code, hc_device_t *hcd, const hw_res_list_parsed_t *hw_res) 110 112 { 111 113 assert(code); … … 140 142 code->cmds[3].addr = (void*)®isters->usbsts; 141 143 142 usb_log_debug("I/O regs at %p (size %zu), IRQ %d. \n",144 usb_log_debug("I/O regs at %p (size %zu), IRQ %d.", 143 145 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 144 146 145 *irq = hw_res->irqs.irqs[0]; 146 return EOK; 147 return hw_res->irqs.irqs[0]; 147 148 } 148 149 … … 157 158 * - resume from suspend state (not implemented) 158 159 */ 159 void uhci_hc_interrupt(hcd_t *hcd, uint32_t status) 160 { 161 assert(hcd); 162 hc_t *instance = hcd_get_driver_data(hcd); 163 assert(instance); 160 static void hc_interrupt(bus_t *bus, uint32_t status) 161 { 162 hc_t *instance = bus_to_hc(bus); 163 164 164 /* Lower 2 bits are transaction error and transaction complete */ 165 165 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 166 LIST_INITIALIZE(done); 167 transfer_list_remove_finished( 168 &instance->transfers_interrupt, &done); 169 transfer_list_remove_finished( 170 &instance->transfers_control_slow, &done); 171 transfer_list_remove_finished( 172 &instance->transfers_control_full, &done); 173 transfer_list_remove_finished( 174 &instance->transfers_bulk_full, &done); 175 176 list_foreach_safe(done, current, next) { 177 list_remove(current); 178 uhci_transfer_batch_t *batch = 179 uhci_transfer_batch_from_link(current); 180 uhci_transfer_batch_finish_dispose(batch); 181 } 182 } 166 transfer_list_check_finished(&instance->transfers_interrupt); 167 transfer_list_check_finished(&instance->transfers_control_slow); 168 transfer_list_check_finished(&instance->transfers_control_full); 169 transfer_list_check_finished(&instance->transfers_bulk_full); 170 } 171 183 172 /* Resume interrupts are not supported */ 184 173 if (status & UHCI_STATUS_RESUME) { 185 usb_log_error("Resume interrupt! \n");174 usb_log_error("Resume interrupt!"); 186 175 } 187 176 188 177 /* Bits 4 and 5 indicate hc error */ 189 178 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 190 usb_log_error("UHCI hardware failure!. \n");179 usb_log_error("UHCI hardware failure!."); 191 180 ++instance->hw_failures; 192 181 transfer_list_abort_all(&instance->transfers_interrupt); … … 199 188 hc_init_hw(instance); 200 189 } else { 201 usb_log_fatal("Too many UHCI hardware failures!. \n");202 hc_ fini(instance);190 usb_log_fatal("Too many UHCI hardware failures!."); 191 hc_gone(&instance->base); 203 192 } 204 193 } … … 216 205 * interrupt fibrils. 217 206 */ 218 int hc_ init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)219 { 220 assert(instance);207 int hc_add(hc_device_t *hcd, const hw_res_list_parsed_t *hw_res) 208 { 209 hc_t *instance = hcd_to_hc(hcd); 221 210 assert(hw_res); 222 211 if (hw_res->io_ranges.count != 1 || … … 224 213 return EINVAL; 225 214 226 instance->hw_interrupts = interrupts;227 215 instance->hw_failures = 0; 228 216 … … 231 219 (void **) &instance->registers); 232 220 if (ret != EOK) { 233 usb_log_error("Failed to gain access to registers: %s. \n",221 usb_log_error("Failed to gain access to registers: %s.", 234 222 str_error(ret)); 235 223 return ret; 236 224 } 237 225 238 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible. \n",226 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.", 239 227 hw_res->io_ranges.ranges[0].address.absolute, 240 228 hw_res->io_ranges.ranges[0].size); … … 242 230 ret = hc_init_mem_structures(instance); 243 231 if (ret != EOK) { 244 usb_log_error("Failed to init UHCI memory structures: %s. \n",232 usb_log_error("Failed to init UHCI memory structures: %s.", 245 233 str_error(ret)); 246 234 // TODO: we should disable pio here … … 248 236 } 249 237 238 return EOK; 239 } 240 241 int hc_start(hc_device_t *hcd) 242 { 243 hc_t *instance = hcd_to_hc(hcd); 250 244 hc_init_hw(instance); 251 245 (void)hc_debug_checker; 252 246 253 uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 254 255 return EOK; 247 return uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 248 } 249 250 int hc_setup_roothub(hc_device_t *hcd) 251 { 252 return hc_setup_virtual_root_hub(hcd, USB_SPEED_FULL); 256 253 } 257 254 … … 260 257 * @param[in] instance Host controller structure to use. 261 258 */ 262 void hc_fini(hc_t *instance)259 int hc_gone(hc_device_t *instance) 263 260 { 264 261 assert(instance); 265 262 //TODO Implement 263 return ENOTSUP; 266 264 } 267 265 … … 293 291 pio_write_32(®isters->flbaseadd, pa); 294 292 295 if (instance-> hw_interrupts) {293 if (instance->base.irq_cap >= 0) { 296 294 /* Enable all interrupts, but resume interrupt */ 297 295 pio_write_16(&instance->registers->usbintr, … … 301 299 const uint16_t cmd = pio_read_16(®isters->usbcmd); 302 300 if (cmd != 0) 303 usb_log_warning("Previous command value: %x. \n", cmd);301 usb_log_warning("Previous command value: %x.", cmd); 304 302 305 303 /* Start the hc with large(64B) packet FSBR */ … … 308 306 } 309 307 308 static usb_transfer_batch_t *create_transfer_batch(endpoint_t *ep) 309 { 310 uhci_transfer_batch_t *batch = uhci_transfer_batch_create(ep); 311 return &batch->base; 312 } 313 314 static void destroy_transfer_batch(usb_transfer_batch_t *batch) 315 { 316 uhci_transfer_batch_destroy(uhci_transfer_batch_get(batch)); 317 } 318 319 static endpoint_t *endpoint_create(device_t *device, const usb_endpoint_descriptors_t *desc) 320 { 321 endpoint_t *ep = calloc(1, sizeof(uhci_endpoint_t)); 322 if (ep) 323 endpoint_init(ep, device, desc); 324 return ep; 325 } 326 327 static int endpoint_register(endpoint_t *ep) 328 { 329 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep)); 330 331 const int err = usb2_bus_endpoint_register(&hc->bus_helper, ep); 332 if (err) 333 return err; 334 335 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type]; 336 if (!list) 337 /* 338 * We don't support this combination (e.g. isochronous). Do not 339 * fail early, because that would block any device with these 340 * endpoints from connecting. Instead, make sure these transfers 341 * are denied soon enough with ENOTSUP not to fail on asserts. 342 */ 343 return EOK; 344 345 endpoint_set_online(ep, &list->guard); 346 return EOK; 347 } 348 349 static void endpoint_unregister(endpoint_t *ep) 350 { 351 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep)); 352 usb2_bus_endpoint_unregister(&hc->bus_helper, ep); 353 354 // Check for the roothub, as it does not schedule into lists 355 if (ep->device->address == uhci_rh_get_address(&hc->rh)) { 356 // FIXME: We shall check the roothub for active transfer. But 357 // as it is polling, there is no way to make it stop doing so. 358 // Return after rewriting uhci rh. 359 return; 360 } 361 362 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type]; 363 if (!list) 364 /* 365 * We don't support this combination (e.g. isochronous), 366 * so no transfer can be active. 367 */ 368 return; 369 370 fibril_mutex_lock(&list->guard); 371 372 endpoint_set_offline_locked(ep); 373 /* From now on, no other transfer will be scheduled. */ 374 375 if (!ep->active_batch) { 376 fibril_mutex_unlock(&list->guard); 377 return; 378 } 379 380 /* First, offer the batch a short chance to be finished. */ 381 endpoint_wait_timeout_locked(ep, 10000); 382 383 if (!ep->active_batch) { 384 fibril_mutex_unlock(&list->guard); 385 return; 386 } 387 388 uhci_transfer_batch_t * const batch = 389 uhci_transfer_batch_get(ep->active_batch); 390 391 /* Remove the batch from the schedule to stop it from being finished. */ 392 endpoint_deactivate_locked(ep); 393 transfer_list_remove_batch(list, batch); 394 395 fibril_mutex_unlock(&list->guard); 396 397 /* 398 * We removed the batch from software schedule only, it's still possible 399 * that HC has it in its caches. Better wait a while before we release 400 * the buffers. 401 */ 402 async_usleep(20000); 403 batch->base.error = EINTR; 404 batch->base.transferred_size = 0; 405 usb_transfer_batch_finish(&batch->base); 406 } 407 408 static int device_enumerate(device_t *dev) 409 { 410 hc_t * const hc = bus_to_hc(dev->bus); 411 return usb2_bus_device_enumerate(&hc->bus_helper, dev); 412 } 413 414 static void device_gone(device_t *dev) 415 { 416 hc_t * const hc = bus_to_hc(dev->bus); 417 usb2_bus_device_gone(&hc->bus_helper, dev); 418 } 419 420 static int hc_status(bus_t *, uint32_t *); 421 static int hc_schedule(usb_transfer_batch_t *); 422 423 static const bus_ops_t uhci_bus_ops = { 424 .interrupt = hc_interrupt, 425 .status = hc_status, 426 427 .device_enumerate = device_enumerate, 428 .device_gone = device_gone, 429 430 .endpoint_create = endpoint_create, 431 .endpoint_register = endpoint_register, 432 .endpoint_unregister = endpoint_unregister, 433 434 .batch_create = create_transfer_batch, 435 .batch_schedule = hc_schedule, 436 .batch_destroy = destroy_transfer_batch, 437 }; 438 310 439 /** Initialize UHCI hc memory structures. 311 440 * … … 321 450 { 322 451 assert(instance); 452 453 usb2_bus_helper_init(&instance->bus_helper, &bandwidth_accounting_usb11); 454 455 bus_init(&instance->bus, sizeof(device_t)); 456 instance->bus.ops = &uhci_bus_ops; 457 458 hc_device_setup(&instance->base, &instance->bus); 323 459 324 460 /* Init USB frame list page */ … … 327 463 return ENOMEM; 328 464 } 329 usb_log_debug("Initialized frame list at %p. \n", instance->frame_list);465 usb_log_debug("Initialized frame list at %p.", instance->frame_list); 330 466 331 467 /* Init transfer lists */ 332 468 int ret = hc_init_transfer_lists(instance); 333 469 if (ret != EOK) { 334 usb_log_error("Failed to initialize transfer lists. \n");470 usb_log_error("Failed to initialize transfer lists."); 335 471 return_page(instance->frame_list); 336 472 return ENOMEM; 337 473 } 338 usb_log_debug("Initialized transfer lists.\n"); 474 list_initialize(&instance->pending_endpoints); 475 usb_log_debug("Initialized transfer lists."); 339 476 340 477 … … 366 503 int ret = transfer_list_init(&instance->transfers_##type, name); \ 367 504 if (ret != EOK) { \ 368 usb_log_error("Failed to setup %s transfer list: %s. \n", \505 usb_log_error("Failed to setup %s transfer list: %s.", \ 369 506 name, str_error(ret)); \ 370 507 transfer_list_fini(&instance->transfers_bulk_full); \ … … 411 548 } 412 549 413 int uhci_hc_status(hcd_t *hcd, uint32_t *status)414 { 415 assert(hcd);550 static int hc_status(bus_t *bus, uint32_t *status) 551 { 552 hc_t *instance = bus_to_hc(bus); 416 553 assert(status); 417 hc_t *instance = hcd_get_driver_data(hcd);418 assert(instance);419 554 420 555 *status = 0; … … 427 562 } 428 563 429 /** Schedule batch for execution. 564 /** 565 * Schedule batch for execution. 430 566 * 431 567 * @param[in] instance UHCI structure to use. 432 568 * @param[in] batch Transfer batch to schedule. 433 569 * @return Error code 434 * 435 * Checks for bandwidth availability and appends the batch to the proper queue. 436 */ 437 int uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 438 { 439 assert(hcd); 440 hc_t *instance = hcd_get_driver_data(hcd); 441 assert(instance); 442 assert(batch); 443 444 if (batch->ep->address == uhci_rh_get_address(&instance->rh)) 445 return uhci_rh_schedule(&instance->rh, batch); 446 570 */ 571 static int hc_schedule(usb_transfer_batch_t *batch) 572 { 447 573 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch); 448 if (!uhci_batch) { 449 usb_log_error("Failed to create UHCI transfer structures.\n"); 450 return ENOMEM; 451 } 452 453 transfer_list_t *list = 454 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 455 assert(list); 456 transfer_list_add_batch(list, uhci_batch); 457 458 return EOK; 574 endpoint_t *ep = batch->ep; 575 hc_t *hc = bus_to_hc(endpoint_get_bus(ep)); 576 577 if (batch->target.address == uhci_rh_get_address(&hc->rh)) 578 return uhci_rh_schedule(&hc->rh, batch); 579 580 transfer_list_t * const list = 581 hc->transfers[ep->device->speed][ep->transfer_type]; 582 583 if (!list) 584 return ENOTSUP; 585 586 int err; 587 if ((err = uhci_transfer_batch_prepare(uhci_batch))) 588 return err; 589 590 return transfer_list_add_batch(list, uhci_batch); 459 591 } 460 592 … … 479 611 480 612 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) { 481 usb_log_debug2("Command: %X Status: %X Intr: %x \n",613 usb_log_debug2("Command: %X Status: %X Intr: %x", 482 614 cmd, sts, intr); 483 615 } … … 486 618 pio_read_32(&instance->registers->flbaseadd) & ~0xfff; 487 619 if (frame_list != addr_to_phys(instance->frame_list)) { 488 usb_log_debug("Framelist address: %p vs. %p. \n",620 usb_log_debug("Framelist address: %p vs. %p.", 489 621 (void *) frame_list, 490 622 (void *) addr_to_phys(instance->frame_list)); … … 497 629 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 498 630 if (expected_pa != real_pa) { 499 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p. \n",631 usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.", 500 632 (void *) expected_pa, frnum, (void *) real_pa); 501 633 } … … 504 636 real_pa = addr_to_phys(QH(control_slow)); 505 637 if (expected_pa != real_pa) { 506 usb_log_debug("Control Slow QH: %p vs. %p. \n",638 usb_log_debug("Control Slow QH: %p vs. %p.", 507 639 (void *) expected_pa, (void *) real_pa); 508 640 } … … 511 643 real_pa = addr_to_phys(QH(control_full)); 512 644 if (expected_pa != real_pa) { 513 usb_log_debug("Control Full QH: %p vs. %p. \n",645 usb_log_debug("Control Full QH: %p vs. %p.", 514 646 (void *) expected_pa, (void *) real_pa); 515 647 } … … 518 650 real_pa = addr_to_phys(QH(bulk_full)); 519 651 if (expected_pa != real_pa ) { 520 usb_log_debug("Bulk QH: %p vs. %p. \n",652 usb_log_debug("Bulk QH: %p vs. %p.", 521 653 (void *) expected_pa, (void *) real_pa); 522 654 }
Note:
See TracChangeset
for help on using the changeset viewer.