Changes in uspace/drv/bus/usb/uhci/hc.c [933b0d7:26858040] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
r933b0d7 r26858040 41 41 42 42 #include "hc.h" 43 #include "uhci_batch.h"44 43 45 44 #define UHCI_INTR_ALLOW_INTERRUPTS \ … … 47 46 #define UHCI_STATUS_USED_INTERRUPTS \ 48 47 (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT) 49 50 48 51 49 static const irq_cmd_t uhci_irq_commands[] = … … 59 57 }; 60 58 61 static void hc_init_hw(consthc_t *instance);59 static int hc_init_transfer_lists(hc_t *instance); 62 60 static int hc_init_mem_structures(hc_t *instance); 63 static int hc_init_transfer_lists(hc_t *instance); 64 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 61 static void hc_init_hw(hc_t *instance); 65 62 66 63 static int hc_interrupt_emulator(void *arg); … … 98 95 cmds[3].addr = (void*)®isters->usbsts; 99 96 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 error109 * - some kind of device error110 * - 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 }157 97 } 158 98 /*----------------------------------------------------------------------------*/ … … 192 132 "Device registers at %p (%zuB) accessible.\n", io, reg_size); 193 133 194 ret = hc d_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,195 bandwidth_count_usb11);196 CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n",134 ret = hc_init_mem_structures(instance); 135 CHECK_RET_RETURN(ret, 136 "Failed to initialize UHCI memory structures: %s.\n", 197 137 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_RETURN204 205 ret = hc_init_mem_structures(instance);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 }213 138 214 139 hc_init_hw(instance); … … 221 146 222 147 return EOK; 148 #undef CHECK_RET_DEST_FUN_RETURN 223 149 } 224 150 /*----------------------------------------------------------------------------*/ … … 228 154 * For magic values see UHCI Design Guide 229 155 */ 230 void hc_init_hw( consthc_t *instance)156 void hc_init_hw(hc_t *instance) 231 157 { 232 158 assert(instance); … … 272 198 * 273 199 * Structures: 200 * - interrupt code (I/O addressses are customized per instance) 274 201 * - transfer lists (queue heads need to be accessible by the hw) 275 202 * - frame list page (needs to be one UHCI hw accessible 4K page) … … 278 205 { 279 206 assert(instance); 280 281 /* Init USB frame list page */ 207 #define CHECK_RET_RETURN(ret, message...) \ 208 if (ret != EOK) { \ 209 usb_log_error(message); \ 210 return ret; \ 211 } else (void) 0 212 213 /* Init transfer lists */ 214 int ret = hc_init_transfer_lists(instance); 215 CHECK_RET_RETURN(ret, "Failed to initialize transfer lists.\n"); 216 usb_log_debug("Initialized transfer lists.\n"); 217 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*/ 282 228 instance->frame_list = get_page(); 283 229 if (!instance->frame_list) { 230 usb_log_error("Failed to get frame list page.\n"); 231 usb_endpoint_manager_destroy(&instance->ep_manager); 284 232 return ENOMEM; 285 233 } 286 234 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list); 287 288 /* Init transfer lists */289 int ret = hc_init_transfer_lists(instance);290 if (ret != EOK) {291 usb_log_error("Failed to initialize transfer lists.\n");292 return_page(instance->frame_list);293 return ENOMEM;294 }295 usb_log_debug("Initialized transfer lists.\n");296 297 235 298 236 /* Set all frames to point to the first queue head */ … … 305 243 306 244 return EOK; 245 #undef CHECK_RET_RETURN 307 246 } 308 247 /*----------------------------------------------------------------------------*/ … … 377 316 * Checks for bandwidth availability and appends the batch to the proper queue. 378 317 */ 379 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 380 { 381 assert(hcd); 382 hc_t *instance = hcd->private_data; 318 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch) 319 { 383 320 assert(instance); 384 321 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 }390 322 391 323 transfer_list_t *list = 392 324 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 393 325 assert(list); 394 transfer_list_add_batch(list, uhci_batch); 395 396 return EOK; 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 } 397 386 } 398 387 /*----------------------------------------------------------------------------*/ … … 414 403 if (status != 0) 415 404 usb_log_debug2("UHCI status: %x.\n", status); 405 // Qemu fails to report stalled communication 406 // see https://bugs.launchpad.net/qemu/+bug/757654 407 // This is a simple workaround to force queue processing every time 408 // status |= 1; 416 409 hc_interrupt(instance, status); 417 410 async_usleep(UHCI_INT_EMULATOR_TIMEOUT); … … 419 412 return EOK; 420 413 } 421 /*--------------------------------------------------------------------------- -*/414 /*---------------------------------------------------------------------------*/ 422 415 /** Debug function, checks consistency of memory structures. 423 416 *
Note:
See TracChangeset
for help on using the changeset viewer.