Changeset fb154e13 in mainline
- Timestamp:
- 2018-01-12T22:48:57Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 0e7380f
- Parents:
- 7242ba21
- Location:
- uspace/drv/bus/usb/xhci
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/xhci/hc.c
r7242ba21 rfb154e13 476 476 * not cause an interrupt. 477 477 */ 478 xhci_rh_handle_port_change(&hc->rh); 478 for (uint8_t port = 1; port <= hc->rh.max_ports; ++port) 479 xhci_rh_handle_port_change(&hc->rh, port); 479 480 480 481 return EOK; … … 508 509 } 509 510 511 static int handle_port_status_change_event(xhci_hc_t *hc, xhci_trb_t *trb) 512 { 513 uint8_t port_id = XHCI_QWORD_EXTRACT(trb->parameter, 31, 24); 514 usb_log_debug("Port status change event detected for port %u.", port_id); 515 xhci_rh_handle_port_change(&hc->rh, port_id); 516 return EOK; 517 } 518 510 519 typedef int (*event_handler) (xhci_hc_t *, xhci_trb_t *trb); 511 520 512 521 static event_handler event_handlers [] = { 513 522 [XHCI_TRB_TYPE_COMMAND_COMPLETION_EVENT] = &xhci_handle_command_completion, 514 [XHCI_TRB_TYPE_PORT_STATUS_CHANGE_EVENT] = & xhci_rh_handle_port_status_change_event,523 [XHCI_TRB_TYPE_PORT_STATUS_CHANGE_EVENT] = &handle_port_status_change_event, 515 524 [XHCI_TRB_TYPE_TRANSFER_EVENT] = &xhci_handle_transfer_event, 516 525 [XHCI_TRB_TYPE_MFINDEX_WRAP_EVENT] = &xhci_handle_mfindex_wrap_event, … … 578 587 status = xhci2host(32, status); 579 588 580 if (status & XHCI_REG_MASK(XHCI_OP_PCD)) {581 usb_log_debug2("Root hub interrupt.");582 xhci_rh_handle_port_change(&hc->rh);583 status &= ~XHCI_REG_MASK(XHCI_OP_PCD);584 }585 586 589 if (status & XHCI_REG_MASK(XHCI_OP_HSE)) { 587 590 usb_log_error("Host controller error occured. Bad things gonna happen..."); … … 599 602 status &= ~XHCI_REG_MASK(XHCI_OP_SRE); 600 603 } 604 605 /* According to Note on p. 302, we may safely ignore the PCD bit. */ 606 status &= ~XHCI_REG_MASK(XHCI_OP_PCD); 601 607 602 608 if (status) { -
uspace/drv/bus/usb/xhci/rh.c
r7242ba21 rfb154e13 98 98 } 99 99 100 static int rh_event_wait_timeout(xhci_rh_t *rh, suseconds_t timeout) 101 { 100 static int rh_event_wait_timeout(xhci_rh_t *rh, uint8_t port_id, uint32_t mask, suseconds_t timeout) 101 { 102 int r; 102 103 assert(fibril_mutex_is_locked(&rh->event_guard)); 103 104 104 105 ++rh->event_readers_waiting; 105 const int r = fibril_condvar_wait_timeout(&rh->event_ready, &rh->event_guard, timeout); 106 107 do { 108 r = fibril_condvar_wait_timeout(&rh->event_ready, &rh->event_guard, timeout); 109 if (r != EOK) 110 break; 111 } while (rh->event.port_id != port_id || (rh->event.events & mask) != mask); 112 113 if (r == EOK) 114 rh->event.events &= ~mask; 115 106 116 --rh->event_readers_waiting; 107 117 if (--rh->event_readers_to_go == 0) 108 118 fibril_condvar_broadcast(&rh->event_handled); 119 109 120 return r; 110 121 } … … 112 123 static void rh_event_run_handlers(xhci_rh_t *rh) 113 124 { 114 fibril_mutex_lock(&rh->event_guard);125 assert(fibril_mutex_is_locked(&rh->event_guard)); 115 126 assert(rh->event_readers_to_go == 0); 116 127 … … 119 130 while (rh->event_readers_to_go) 120 131 fibril_condvar_wait(&rh->event_handled, &rh->event_guard); 121 fibril_mutex_unlock(&rh->event_guard);122 132 } 123 133 … … 178 188 static int rh_port_reset_sync(xhci_rh_t *rh, uint8_t port_id) 179 189 { 180 int r;181 190 xhci_port_regs_t *regs = &rh->hc->op_regs->portrs[port_id - 1]; 182 191 183 192 fibril_mutex_lock(&rh->event_guard); 184 193 XHCI_REG_SET(regs, XHCI_PORT_PR, 1); 185 186 while (true) { 187 r = rh_event_wait_timeout(rh, 0); 188 if (r != EOK) 189 break; 190 if (rh->event.port_id == port_id 191 && rh->event.events & XHCI_REG_MASK(XHCI_PORT_PRC)) 192 break; 193 } 194 const int r = rh_event_wait_timeout(rh, port_id, XHCI_REG_MASK(XHCI_PORT_PRC), 0); 194 195 fibril_mutex_unlock(&rh->event_guard); 195 196 … … 261 262 /* Remove device from XHCI bus. */ 262 263 bus_device_gone(&dev->base); 263 264 return EOK;265 }266 267 /**268 * Handle an incoming Port Change Detected Event.269 */270 int xhci_rh_handle_port_status_change_event(xhci_hc_t *hc, xhci_trb_t *trb)271 {272 uint8_t port_id = XHCI_QWORD_EXTRACT(trb->parameter, 31, 24);273 usb_log_debug("Port status change event detected for port %u.", port_id);274 275 /**276 * We can't be sure that the port change this event announces is the277 * only port change that happened (see section 4.19.2 of the xHCI278 * specification). Therefore, we just check all ports for changes.279 */280 xhci_rh_handle_port_change(&hc->rh);281 264 282 265 return EOK; … … 317 300 318 301 /** 319 * Handle all changes on all ports.320 */ 321 void xhci_rh_handle_port_change(xhci_rh_t *rh )322 { 323 f or (uint8_t i = 1; i <= rh->max_ports; ++i) {324 xhci_port_regs_t *regs = &rh->hc->op_regs->portrs[i- 1];325 326 uint32_t events = XHCI_REG_RD_FIELD(®s->portsc, 32);327 XHCI_REG_WR_FIELD(®s->portsc, events, 32); 328 329 events &= port_change_mask;302 * Handle all changes on specified port. 303 */ 304 void xhci_rh_handle_port_change(xhci_rh_t *rh, uint8_t port_id) 305 { 306 fibril_mutex_lock(&rh->event_guard); 307 xhci_port_regs_t * const regs = &rh->hc->op_regs->portrs[port_id - 1]; 308 309 uint32_t events = XHCI_REG_RD_FIELD(®s->portsc, 32) & port_change_mask; 310 311 while (events) { 312 XHCI_REG_SET_FIELD(®s->portsc, events, 32); 330 313 331 314 if (events & XHCI_REG_MASK(XHCI_PORT_CSC)) { 332 usb_log_info("Connected state changed on port %u.", i);315 usb_log_info("Connected state changed on port %u.", port_id); 333 316 events &= ~XHCI_REG_MASK(XHCI_PORT_CSC); 334 317 335 318 bool connected = XHCI_REG_RD(regs, XHCI_PORT_CCS); 336 319 if (connected) { 337 handle_in_fibril(rh, i, handle_connected_device);320 handle_in_fibril(rh, port_id, handle_connected_device); 338 321 } else { 339 handle_in_fibril(rh, i, handle_disconnected_device);322 handle_in_fibril(rh, port_id, handle_disconnected_device); 340 323 } 341 324 } 342 325 343 326 if (events != 0) { 344 rh->event.port_id = i;327 rh->event.port_id = port_id; 345 328 rh->event.events = events; 346 329 rh_event_run_handlers(rh); 347 330 } 348 } 349 350 /** 351 * Theory: 352 * 353 * Although more events could have happened while processing, the PCD 354 * bit in USBSTS will be set on every change. Because the PCD is 355 * cleared even before the interrupt is cleared, it is safe to assume 356 * that this handler will be called again. 357 * 358 * But because we could have handled the event in previous run of this 359 * handler, it is not an error when no event is detected. 360 * 361 * Reality: 362 * 363 * The PCD bit is never set. TODO Check why the interrupt never carries 364 * the PCD flag. Possibly repeat the checking until we're sure the 365 * PSCEG is 0 - check section 4.19.2 of the xHCI spec. 366 */ 331 332 if (rh->event.events != 0) 333 usb_log_debug("RH port %u change not handled: 0x%x", port_id, rh->event.events); 334 335 /* Make sure that PSCEG is 0 before exiting the loop. */ 336 events = XHCI_REG_RD_FIELD(®s->portsc, 32) & port_change_mask; 337 } 338 339 fibril_mutex_unlock(&rh->event_guard); 367 340 } 368 341 -
uspace/drv/bus/usb/xhci/rh.h
r7242ba21 rfb154e13 90 90 const xhci_port_speed_t *xhci_rh_get_port_speed(xhci_rh_t *, uint8_t); 91 91 92 int xhci_rh_handle_port_status_change_event(xhci_hc_t *, xhci_trb_t *); 93 void xhci_rh_handle_port_change(xhci_rh_t *); 94 95 int xhci_rh_address_device(xhci_rh_t *rh, device_t *dev, xhci_bus_t *bus); 92 void xhci_rh_handle_port_change(xhci_rh_t *, uint8_t); 96 93 97 94 #endif
Note:
See TracChangeset
for help on using the changeset viewer.