Changes in uspace/drv/uhci-hcd/hc.c [8986412:4c28d17] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-hcd/hc.c
r8986412 r4c28d17 44 44 #include "hc.h" 45 45 46 #define UHCI_INTR_ALLOW_INTERRUPTS \ 47 (UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET) 48 #define UHCI_STATUS_USED_INTERRUPTS \ 49 (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT) 50 51 46 static irq_cmd_t uhci_cmds[] = { 47 { 48 .cmd = CMD_PIO_READ_16, 49 .addr = NULL, /* patched for every instance */ 50 .dstarg = 1 51 }, 52 { 53 .cmd = CMD_PIO_WRITE_16, 54 .addr = NULL, /* pathed for every instance */ 55 .value = 0x1f 56 }, 57 { 58 .cmd = CMD_ACCEPT 59 } 60 }; 61 /*----------------------------------------------------------------------------*/ 52 62 static int hc_init_transfer_lists(hc_t *instance); 53 63 static int hc_init_mem_structures(hc_t *instance); … … 56 66 static int hc_interrupt_emulator(void *arg); 57 67 static int hc_debug_checker(void *arg); 68 #if 0 69 static bool usb_is_allowed( 70 bool low_speed, usb_transfer_type_t transfer, size_t size); 71 #endif 58 72 /*----------------------------------------------------------------------------*/ 59 73 /** Initialize UHCI hcd driver structure … … 75 89 int ret; 76 90 77 #define CHECK_RET_ RETURN(ret, message...) \91 #define CHECK_RET_DEST_FUN_RETURN(ret, message...) \ 78 92 if (ret != EOK) { \ 79 93 usb_log_error(message); \ 94 if (instance->ddf_instance) \ 95 ddf_fun_destroy(instance->ddf_instance); \ 80 96 return ret; \ 81 97 } else (void) 0 … … 83 99 instance->hw_interrupts = interrupts; 84 100 instance->hw_failures = 0; 101 102 /* Setup UHCI function. */ 103 instance->ddf_instance = fun; 85 104 86 105 /* allow access to hc control registers */ 87 106 regs_t *io; 88 107 ret = pio_enable(regs, reg_size, (void**)&io); 89 CHECK_RET_ RETURN(ret,108 CHECK_RET_DEST_FUN_RETURN(ret, 90 109 "Failed(%d) to gain access to registers at %p: %s.\n", 91 ret, io, str_error(ret));110 ret, str_error(ret), io); 92 111 instance->registers = io; 93 usb_log_debug("Device registers at %p (%zuB) accessible.\n",112 usb_log_debug("Device registers at %p(%u) accessible.\n", 94 113 io, reg_size); 95 114 96 115 ret = hc_init_mem_structures(instance); 97 CHECK_RET_RETURN(ret, 98 "Failed(%d) to initialize UHCI memory structures: %s.\n", 99 ret, str_error(ret)); 116 CHECK_RET_DEST_FUN_RETURN(ret, 117 "Failed to initialize UHCI memory structures.\n"); 100 118 101 119 hc_init_hw(instance); 102 120 if (!interrupts) { 103 instance-> interrupt_emulator =121 instance->cleaner = 104 122 fibril_create(hc_interrupt_emulator, instance); 105 fibril_add_ready(instance->interrupt_emulator); 106 } 107 (void)hc_debug_checker; 123 fibril_add_ready(instance->cleaner); 124 } else { 125 /* TODO: enable interrupts here */ 126 } 127 128 instance->debug_checker = 129 fibril_create(hc_debug_checker, instance); 130 // fibril_add_ready(instance->debug_checker); 108 131 109 132 return EOK; … … 141 164 /* Enable all interrupts, but resume interrupt */ 142 165 pio_write_16(&instance->registers->usbintr, 143 UHCI_INTR_ ALLOW_INTERRUPTS);166 UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET); 144 167 } 145 168 … … 167 190 { 168 191 assert(instance); 169 #define CHECK_RET_ RETURN(ret, message...) \192 #define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \ 170 193 if (ret != EOK) { \ 171 194 usb_log_error(message); \ 195 if (instance->interrupt_code.cmds != NULL) \ 196 free(instance->interrupt_code.cmds); \ 172 197 return ret; \ 173 198 } else (void) 0 174 199 175 200 /* Init interrupt code */ 176 instance->interrupt_code.cmds = instance->interrupt_commands; 201 instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds)); 202 int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK; 203 CHECK_RET_DEST_CMDS_RETURN(ret, 204 "Failed to allocate interrupt cmds space.\n"); 205 177 206 { 178 /* Read status register */ 179 instance->interrupt_commands[0].cmd = CMD_PIO_READ_16; 180 instance->interrupt_commands[0].dstarg = 1; 181 instance->interrupt_commands[0].addr = 182 &instance->registers->usbsts; 183 184 /* Test whether we are the interrupt cause */ 185 instance->interrupt_commands[1].cmd = CMD_BTEST; 186 instance->interrupt_commands[1].value = 187 UHCI_STATUS_USED_INTERRUPTS | UHCI_STATUS_NM_INTERRUPTS; 188 instance->interrupt_commands[1].srcarg = 1; 189 instance->interrupt_commands[1].dstarg = 2; 190 191 /* Predicate cleaning and accepting */ 192 instance->interrupt_commands[2].cmd = CMD_PREDICATE; 193 instance->interrupt_commands[2].value = 2; 194 instance->interrupt_commands[2].srcarg = 2; 195 196 /* Write clean status register */ 197 instance->interrupt_commands[3].cmd = CMD_PIO_WRITE_A_16; 198 instance->interrupt_commands[3].srcarg = 1; 199 instance->interrupt_commands[3].addr = 200 &instance->registers->usbsts; 201 202 /* Accept interrupt */ 203 instance->interrupt_commands[4].cmd = CMD_ACCEPT; 204 205 instance->interrupt_code.cmdcount = UHCI_NEEDED_IRQ_COMMANDS; 207 irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds; 208 memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds)); 209 interrupt_commands[0].addr = 210 (void*)&instance->registers->usbsts; 211 interrupt_commands[1].addr = 212 (void*)&instance->registers->usbsts; 213 instance->interrupt_code.cmdcount = 214 sizeof(uhci_cmds) / sizeof(irq_cmd_t); 206 215 } 207 216 208 217 /* Init transfer lists */ 209 intret = hc_init_transfer_lists(instance);210 CHECK_RET_ RETURN(ret, "Failed to init transfer lists.\n");218 ret = hc_init_transfer_lists(instance); 219 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to init transfer lists.\n"); 211 220 usb_log_debug("Initialized transfer lists.\n"); 212 221 … … 214 223 instance->frame_list = get_page(); 215 224 ret = instance ? EOK : ENOMEM; 216 CHECK_RET_ RETURN(ret, "Failed to get frame list page.\n");225 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n"); 217 226 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list); 218 227 219 228 /* Set all frames to point to the first queue head */ 220 const uint32_t queue = LINK_POINTER_QH( 221 addr_to_phys(instance->transfers_interrupt.queue_head)); 229 const uint32_t queue = 230 instance->transfers_interrupt.queue_head_pa 231 | LINK_POINTER_QUEUE_HEAD_FLAG; 222 232 223 233 unsigned i = 0; … … 226 236 } 227 237 228 /* Init device keeper 238 /* Init device keeper*/ 229 239 usb_device_keeper_init(&instance->manager); 230 240 usb_log_debug("Initialized device manager.\n"); … … 232 242 ret = usb_endpoint_manager_init(&instance->ep_manager, 233 243 BANDWIDTH_AVAILABLE_USB11); 234 CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n", 235 str_error(ret)); 244 assert(ret == EOK); 236 245 237 246 return EOK; 238 #undef CHECK_RET_ RETURN247 #undef CHECK_RET_DEST_CMDS_RETURN 239 248 } 240 249 /*----------------------------------------------------------------------------*/ … … 251 260 { 252 261 assert(instance); 253 #define SETUP_TRANSFER_LIST(type, name) \ 254 do { \ 255 int ret = transfer_list_init(&instance->transfers_##type, name); \ 262 #define CHECK_RET_CLEAR_RETURN(ret, message...) \ 256 263 if (ret != EOK) { \ 257 usb_log_error("Failed(%d) to setup %s transfer list: %s.\n", \ 258 ret, name, str_error(ret)); \ 264 usb_log_error(message); \ 259 265 transfer_list_fini(&instance->transfers_bulk_full); \ 260 266 transfer_list_fini(&instance->transfers_control_full); \ … … 262 268 transfer_list_fini(&instance->transfers_interrupt); \ 263 269 return ret; \ 264 } \ 265 } while (0) 266 267 SETUP_TRANSFER_LIST(bulk_full, "BULK FULL"); 268 SETUP_TRANSFER_LIST(control_full, "CONTROL FULL"); 269 SETUP_TRANSFER_LIST(control_slow, "CONTROL LOW"); 270 SETUP_TRANSFER_LIST(interrupt, "INTERRUPT"); 271 #undef SETUP_TRANSFER_LIST 272 /* Connect lists into one schedule */ 270 } else (void) 0 271 272 /* initialize TODO: check errors */ 273 int ret; 274 ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL"); 275 CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list."); 276 277 ret = transfer_list_init( 278 &instance->transfers_control_full, "CONTROL_FULL"); 279 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list."); 280 281 ret = transfer_list_init( 282 &instance->transfers_control_slow, "CONTROL_SLOW"); 283 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list."); 284 285 ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT"); 286 CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list."); 287 273 288 transfer_list_set_next(&instance->transfers_control_full, 274 289 &instance->transfers_bulk_full); … … 281 296 #ifdef FSBR 282 297 transfer_list_set_next(&instance->transfers_bulk_full, 283 298 &instance->transfers_control_full); 284 299 #endif 285 300 … … 314 329 315 330 transfer_list_t *list = 316 instance->transfers[batch-> ep->speed][batch->ep->transfer_type];331 instance->transfers[batch->speed][batch->transfer_type]; 317 332 assert(list); 318 333 transfer_list_add_batch(list, batch); … … 334 349 { 335 350 assert(instance); 351 // status |= 1; //Uncomment to work around qemu hang 352 /* TODO: Resume interrupts are not supported */ 336 353 /* Lower 2 bits are transaction error and transaction complete */ 337 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {354 if (status & 0x3) { 338 355 LIST_INITIALIZE(done); 339 356 transfer_list_remove_finished( … … 354 371 } 355 372 } 356 /* Resume interrupts are not supported */ 357 if (status & UHCI_STATUS_RESUME) { 358 usb_log_error("Resume interrupt!\n"); 359 } 360 361 /* Bits 4 and 5 indicate hc error */ 362 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 373 /* bits 4 and 5 indicate hc error */ 374 if (status & 0x18) { 363 375 usb_log_error("UHCI hardware failure!.\n"); 364 376 ++instance->hw_failures; … … 386 398 { 387 399 usb_log_debug("Started interrupt emulator.\n"); 388 hc_t *instance = arg;400 hc_t *instance = (hc_t*)arg; 389 401 assert(instance); 390 402 391 403 while (1) { 392 /* Read and clear status register*/404 /* read and ack interrupts */ 393 405 uint16_t status = pio_read_16(&instance->registers->usbsts); 394 pio_write_16(&instance->registers->usbsts, status);406 pio_write_16(&instance->registers->usbsts, 0x1f); 395 407 if (status != 0) 396 408 usb_log_debug2("UHCI status: %x.\n", status); 397 // Qemu fails to report stalled communication398 // see https://bugs.launchpad.net/qemu/+bug/757654399 // This is a simple workaround to force queue processing every time400 // status |= 1;401 409 hc_interrupt(instance, status); 402 async_usleep(UHCI_ INT_EMULATOR_TIMEOUT);410 async_usleep(UHCI_CLEANER_TIMEOUT); 403 411 } 404 412 return EOK; … … 412 420 int hc_debug_checker(void *arg) 413 421 { 414 hc_t *instance = arg;422 hc_t *instance = (hc_t*)arg; 415 423 assert(instance); 416 424 … … 433 441 if (frame_list != addr_to_phys(instance->frame_list)) { 434 442 usb_log_debug("Framelist address: %p vs. %p.\n", 435 (void *) frame_list, 436 (void *) addr_to_phys(instance->frame_list)); 443 frame_list, addr_to_phys(instance->frame_list)); 437 444 } 438 445 … … 443 450 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 444 451 if (expected_pa != real_pa) { 445 usb_log_debug("Interrupt QH: %p (frame%d) vs. %p.\n",446 (void *) expected_pa, frnum, (void *)real_pa);452 usb_log_debug("Interrupt QH: %p(frame: %d) vs. %p.\n", 453 expected_pa, frnum, real_pa); 447 454 } 448 455 … … 451 458 if (expected_pa != real_pa) { 452 459 usb_log_debug("Control Slow QH: %p vs. %p.\n", 453 (void *) expected_pa, (void *)real_pa);460 expected_pa, real_pa); 454 461 } 455 462 … … 458 465 if (expected_pa != real_pa) { 459 466 usb_log_debug("Control Full QH: %p vs. %p.\n", 460 (void *) expected_pa, (void *)real_pa);467 expected_pa, real_pa); 461 468 } 462 469 … … 465 472 if (expected_pa != real_pa ) { 466 473 usb_log_debug("Bulk QH: %p vs. %p.\n", 467 (void *) expected_pa, (void *)real_pa);474 expected_pa, real_pa); 468 475 } 469 476 async_usleep(UHCI_DEBUGER_TIMEOUT); … … 472 479 #undef QH 473 480 } 481 /*----------------------------------------------------------------------------*/ 482 /** Check transfers for USB validity 483 * 484 * @param[in] low_speed Transfer speed. 485 * @param[in] transfer Transer type 486 * @param[in] size Size of data packets 487 * @return True if transaction is allowed by USB specs, false otherwise 488 */ 489 #if 0 490 bool usb_is_allowed( 491 bool low_speed, usb_transfer_type_t transfer, size_t size) 492 { 493 /* see USB specification chapter 5.5-5.8 for magic numbers used here */ 494 switch(transfer) 495 { 496 case USB_TRANSFER_ISOCHRONOUS: 497 return (!low_speed && size < 1024); 498 case USB_TRANSFER_INTERRUPT: 499 return size <= (low_speed ? 8 : 64); 500 case USB_TRANSFER_CONTROL: /* device specifies its own max size */ 501 return (size <= (low_speed ? 8 : 64)); 502 case USB_TRANSFER_BULK: /* device specifies its own max size */ 503 return (!low_speed && size <= 64); 504 } 505 return false; 506 } 507 #endif 474 508 /** 475 509 * @}
Note:
See TracChangeset
for help on using the changeset viewer.