Changeset 925a21e in mainline for uspace/drv/bus/usb/uhci/hc.c
- Timestamp:
- 2011-09-24T14:20:29Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5bf76c1
- Parents:
- 867e2555 (diff), 1ab4aca (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
r867e2555 r925a21e 41 41 42 42 #include "hc.h" 43 #include "uhci_batch.h" 43 44 44 45 #define UHCI_INTR_ALLOW_INTERRUPTS \ … … 46 47 #define UHCI_STATUS_USED_INTERRUPTS \ 47 48 (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT) 49 48 50 49 51 static const irq_cmd_t uhci_irq_commands[] = … … 57 59 }; 58 60 61 static void hc_init_hw(const hc_t *instance); 62 static int hc_init_mem_structures(hc_t *instance); 59 63 static int hc_init_transfer_lists(hc_t *instance); 60 static int hc_init_mem_structures(hc_t *instance); 61 static void hc_init_hw(hc_t *instance); 64 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 62 65 63 66 static int hc_interrupt_emulator(void *arg); … … 95 98 cmds[3].addr = (void*)®isters->usbsts; 96 99 return EOK; 100 } 101 /*----------------------------------------------------------------------------*/ 102 /** Take action based on the interrupt cause. 103 * 104 * @param[in] instance UHCI structure to use. 105 * @param[in] status Value of the status register at the time of interrupt. 106 * 107 * Interrupt might indicate: 108 * - transaction completed, either by triggering IOC, SPD, or an error 109 * - some kind of device error 110 * - resume from suspend state (not implemented) 111 */ 112 void hc_interrupt(hc_t *instance, uint16_t status) 113 { 114 assert(instance); 115 /* Lower 2 bits are transaction error and transaction complete */ 116 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 117 LIST_INITIALIZE(done); 118 transfer_list_remove_finished( 119 &instance->transfers_interrupt, &done); 120 transfer_list_remove_finished( 121 &instance->transfers_control_slow, &done); 122 transfer_list_remove_finished( 123 &instance->transfers_control_full, &done); 124 transfer_list_remove_finished( 125 &instance->transfers_bulk_full, &done); 126 127 while (!list_empty(&done)) { 128 link_t *item = list_first(&done); 129 list_remove(item); 130 uhci_transfer_batch_t *batch = 131 uhci_transfer_batch_from_link(item); 132 uhci_transfer_batch_call_dispose(batch); 133 } 134 } 135 /* Resume interrupts are not supported */ 136 if (status & UHCI_STATUS_RESUME) { 137 usb_log_error("Resume interrupt!\n"); 138 } 139 140 /* Bits 4 and 5 indicate hc error */ 141 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 142 usb_log_error("UHCI hardware failure!.\n"); 143 ++instance->hw_failures; 144 transfer_list_abort_all(&instance->transfers_interrupt); 145 transfer_list_abort_all(&instance->transfers_control_slow); 146 transfer_list_abort_all(&instance->transfers_control_full); 147 transfer_list_abort_all(&instance->transfers_bulk_full); 148 149 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) { 150 /* reinitialize hw, this triggers virtual disconnect*/ 151 hc_init_hw(instance); 152 } else { 153 usb_log_fatal("Too many UHCI hardware failures!.\n"); 154 hc_fini(instance); 155 } 156 } 97 157 } 98 158 /*----------------------------------------------------------------------------*/ … … 132 192 "Device registers at %p (%zuB) accessible.\n", io, reg_size); 133 193 194 ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11, 195 bandwidth_count_usb11); 196 CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n", 197 str_error(ret)); 198 199 instance->generic.private_data = instance; 200 instance->generic.schedule = hc_schedule; 201 instance->generic.ep_add_hook = NULL; 202 203 #undef CHECK_RET_DEST_FUN_RETURN 204 134 205 ret = hc_init_mem_structures(instance); 135 CHECK_RET_RETURN(ret, 136 "Failed to initialize UHCI memory structures: %s.\n", 137 str_error(ret)); 206 if (ret != EOK) { 207 usb_log_error( 208 "Failed to initialize UHCI memory structures: %s.\n", 209 str_error(ret)); 210 hcd_destroy(&instance->generic); 211 return ret; 212 } 138 213 139 214 hc_init_hw(instance); … … 146 221 147 222 return EOK; 148 #undef CHECK_RET_DEST_FUN_RETURN149 223 } 150 224 /*----------------------------------------------------------------------------*/ … … 154 228 * For magic values see UHCI Design Guide 155 229 */ 156 void hc_init_hw( hc_t *instance)230 void hc_init_hw(const hc_t *instance) 157 231 { 158 232 assert(instance); … … 198 272 * 199 273 * Structures: 200 * - interrupt code (I/O addressses are customized per instance)201 274 * - transfer lists (queue heads need to be accessible by the hw) 202 275 * - frame list page (needs to be one UHCI hw accessible 4K page) … … 205 278 { 206 279 assert(instance); 207 #define CHECK_RET_RETURN(ret, message...) \ 208 if (ret != EOK) { \ 209 usb_log_error(message); \ 210 return ret; \ 211 } else (void) 0 280 281 /* Init USB frame list page */ 282 instance->frame_list = get_page(); 283 if (!instance->frame_list) { 284 return ENOMEM; 285 } 286 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list); 212 287 213 288 /* Init transfer lists */ 214 289 int ret = hc_init_transfer_lists(instance); 215 CHECK_RET_RETURN(ret, "Failed to initialize transfer lists.\n"); 290 if (ret != EOK) { 291 usb_log_error("Failed to initialize transfer lists.\n"); 292 return_page(instance->frame_list); 293 return ENOMEM; 294 } 216 295 usb_log_debug("Initialized transfer lists.\n"); 217 296 218 /* Init device keeper */219 usb_device_keeper_init(&instance->manager);220 usb_log_debug("Initialized device keeper.\n");221 222 ret = usb_endpoint_manager_init(&instance->ep_manager,223 BANDWIDTH_AVAILABLE_USB11);224 CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",225 str_error(ret));226 227 /* Init USB frame list page*/228 instance->frame_list = get_page();229 if (!instance->frame_list) {230 usb_log_error("Failed to get frame list page.\n");231 usb_endpoint_manager_destroy(&instance->ep_manager);232 return ENOMEM;233 }234 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);235 297 236 298 /* Set all frames to point to the first queue head */ … … 243 305 244 306 return EOK; 245 #undef CHECK_RET_RETURN246 307 } 247 308 /*----------------------------------------------------------------------------*/ … … 316 377 * Checks for bandwidth availability and appends the batch to the proper queue. 317 378 */ 318 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch) 319 { 379 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 380 { 381 assert(hcd); 382 hc_t *instance = hcd->private_data; 320 383 assert(instance); 321 384 assert(batch); 385 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch); 386 if (!uhci_batch) { 387 usb_log_error("Failed to create UHCI transfer structures.\n"); 388 return ENOMEM; 389 } 322 390 323 391 transfer_list_t *list = 324 392 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 325 393 assert(list); 326 transfer_list_add_batch(list, batch); 327 328 return EOK; 329 } 330 /*----------------------------------------------------------------------------*/ 331 /** Take action based on the interrupt cause. 332 * 333 * @param[in] instance UHCI structure to use. 334 * @param[in] status Value of the status register at the time of interrupt. 335 * 336 * Interrupt might indicate: 337 * - transaction completed, either by triggering IOC, SPD, or an error 338 * - some kind of device error 339 * - resume from suspend state (not implemented) 340 */ 341 void hc_interrupt(hc_t *instance, uint16_t status) 342 { 343 assert(instance); 344 /* Lower 2 bits are transaction error and transaction complete */ 345 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 346 LIST_INITIALIZE(done); 347 transfer_list_remove_finished( 348 &instance->transfers_interrupt, &done); 349 transfer_list_remove_finished( 350 &instance->transfers_control_slow, &done); 351 transfer_list_remove_finished( 352 &instance->transfers_control_full, &done); 353 transfer_list_remove_finished( 354 &instance->transfers_bulk_full, &done); 355 356 while (!list_empty(&done)) { 357 link_t *item = list_first(&done); 358 list_remove(item); 359 usb_transfer_batch_t *batch = 360 list_get_instance(item, usb_transfer_batch_t, link); 361 usb_transfer_batch_finish(batch); 362 } 363 } 364 /* Resume interrupts are not supported */ 365 if (status & UHCI_STATUS_RESUME) { 366 usb_log_error("Resume interrupt!\n"); 367 } 368 369 /* Bits 4 and 5 indicate hc error */ 370 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 371 usb_log_error("UHCI hardware failure!.\n"); 372 ++instance->hw_failures; 373 transfer_list_abort_all(&instance->transfers_interrupt); 374 transfer_list_abort_all(&instance->transfers_control_slow); 375 transfer_list_abort_all(&instance->transfers_control_full); 376 transfer_list_abort_all(&instance->transfers_bulk_full); 377 378 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) { 379 /* reinitialize hw, this triggers virtual disconnect*/ 380 hc_init_hw(instance); 381 } else { 382 usb_log_fatal("Too many UHCI hardware failures!.\n"); 383 hc_fini(instance); 384 } 385 } 394 transfer_list_add_batch(list, uhci_batch); 395 396 return EOK; 386 397 } 387 398 /*----------------------------------------------------------------------------*/ … … 403 414 if (status != 0) 404 415 usb_log_debug2("UHCI status: %x.\n", status); 405 // Qemu fails to report stalled communication406 // see https://bugs.launchpad.net/qemu/+bug/757654407 // This is a simple workaround to force queue processing every time408 // status |= 1;409 416 hc_interrupt(instance, status); 410 417 async_usleep(UHCI_INT_EMULATOR_TIMEOUT); … … 412 419 return EOK; 413 420 } 414 /*--------------------------------------------------------------------------- */421 /*----------------------------------------------------------------------------*/ 415 422 /** Debug function, checks consistency of memory structures. 416 423 *
Note:
See TracChangeset
for help on using the changeset viewer.