Changes in uspace/drv/bus/usb/ehci/hc.c [9dfb034:36795edf] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ehci/hc.c
r9dfb034 r36795edf 1 1 /* 2 * Copyright (c) 2025 Jiri Svoboda3 2 * Copyright (c) 2011 Jan Vesely 4 3 * Copyright (c) 2018 Ondrej Hlavaty … … 213 212 } 214 213 215 /** Quiesce host controller 216 * 217 * @param hcd Host controller device 218 */ 219 int hc_quiesce(hc_device_t *hcd) 214 void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep) 215 { 216 assert(instance); 217 assert(ep); 218 ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep); 219 usb_log_debug("HC(%p) enqueue EP(%d:%d:%s:%s)", instance, 220 ep->device->address, ep->endpoint, 221 usb_str_transfer_type_short(ep->transfer_type), 222 usb_str_direction(ep->direction)); 223 switch (ep->transfer_type) { 224 case USB_TRANSFER_CONTROL: 225 case USB_TRANSFER_BULK: 226 endpoint_list_append_ep(&instance->async_list, ehci_ep); 227 break; 228 case USB_TRANSFER_INTERRUPT: 229 endpoint_list_append_ep(&instance->int_list, ehci_ep); 230 break; 231 case USB_TRANSFER_ISOCHRONOUS: 232 /* NOT SUPPORTED */ 233 break; 234 } 235 } 236 237 void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep) 238 { 239 assert(instance); 240 assert(ep); 241 ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep); 242 usb_log_debug("HC(%p) dequeue EP(%d:%d:%s:%s)", instance, 243 ep->device->address, ep->endpoint, 244 usb_str_transfer_type_short(ep->transfer_type), 245 usb_str_direction(ep->direction)); 246 switch (ep->transfer_type) { 247 case USB_TRANSFER_INTERRUPT: 248 endpoint_list_remove_ep(&instance->int_list, ehci_ep); 249 /* Fall through */ 250 case USB_TRANSFER_ISOCHRONOUS: 251 /* NOT SUPPORTED */ 252 return; 253 case USB_TRANSFER_CONTROL: 254 case USB_TRANSFER_BULK: 255 endpoint_list_remove_ep(&instance->async_list, ehci_ep); 256 break; 257 } 258 fibril_mutex_lock(&instance->guard); 259 usb_log_debug("HC(%p): Waiting for doorbell", instance); 260 EHCI_SET(instance->registers->usbcmd, USB_CMD_IRQ_ASYNC_DOORBELL); 261 fibril_condvar_wait(&instance->async_doorbell, &instance->guard); 262 usb_log_debug2("HC(%p): Got doorbell", instance); 263 fibril_mutex_unlock(&instance->guard); 264 } 265 266 errno_t ehci_hc_status(bus_t *bus_base, uint32_t *status) 267 { 268 assert(bus_base); 269 assert(status); 270 271 ehci_bus_t *bus = (ehci_bus_t *) bus_base; 272 hc_t *hc = bus->hc; 273 assert(hc); 274 275 *status = 0; 276 if (hc->registers) { 277 *status = EHCI_RD(hc->registers->usbsts); 278 EHCI_WR(hc->registers->usbsts, *status); 279 } 280 usb_log_debug2("HC(%p): Read status: %x", hc, *status); 281 return EOK; 282 } 283 284 /** Add USB transfer to the schedule. 285 * 286 * @param[in] hcd HCD driver structure. 287 * @param[in] batch Batch representing the transfer. 288 * @return Error code. 289 */ 290 errno_t ehci_hc_schedule(usb_transfer_batch_t *batch) 291 { 292 assert(batch); 293 294 ehci_bus_t *bus = (ehci_bus_t *) endpoint_get_bus(batch->ep); 295 hc_t *hc = bus->hc; 296 assert(hc); 297 298 /* Check for root hub communication */ 299 if (batch->target.address == ehci_rh_get_address(&hc->rh)) { 300 usb_log_debug("HC(%p): Scheduling BATCH(%p) for RH(%p)", 301 hc, batch, &hc->rh); 302 return ehci_rh_schedule(&hc->rh, batch); 303 } 304 305 endpoint_t *const ep = batch->ep; 306 ehci_endpoint_t *const ehci_ep = ehci_endpoint_get(ep); 307 ehci_transfer_batch_t *ehci_batch = ehci_transfer_batch_get(batch); 308 309 int err; 310 311 if ((err = ehci_transfer_batch_prepare(ehci_batch))) 312 return err; 313 314 fibril_mutex_lock(&hc->guard); 315 316 if ((err = endpoint_activate_locked(ep, batch))) { 317 fibril_mutex_unlock(&hc->guard); 318 return err; 319 } 320 321 usb_log_debug("HC(%p): Committing BATCH(%p)", hc, batch); 322 ehci_transfer_batch_commit(ehci_batch); 323 324 /* Enqueue endpoint to the checked list */ 325 usb_log_debug2("HC(%p): Appending BATCH(%p)", hc, batch); 326 list_append(&ehci_ep->pending_link, &hc->pending_endpoints); 327 328 fibril_mutex_unlock(&hc->guard); 329 return EOK; 330 } 331 332 /** Interrupt handling routine 333 * 334 * @param[in] hcd HCD driver structure. 335 * @param[in] status Value of the status register at the time of interrupt. 336 */ 337 void ehci_hc_interrupt(bus_t *bus_base, uint32_t status) 338 { 339 assert(bus_base); 340 341 ehci_bus_t *bus = (ehci_bus_t *) bus_base; 342 hc_t *hc = bus->hc; 343 assert(hc); 344 345 usb_log_debug2("HC(%p): Interrupt: %" PRIx32, hc, status); 346 if (status & USB_STS_PORT_CHANGE_FLAG) { 347 ehci_rh_interrupt(&hc->rh); 348 } 349 350 if (status & USB_STS_IRQ_ASYNC_ADVANCE_FLAG) { 351 fibril_mutex_lock(&hc->guard); 352 usb_log_debug2("HC(%p): Signaling doorbell", hc); 353 fibril_condvar_broadcast(&hc->async_doorbell); 354 fibril_mutex_unlock(&hc->guard); 355 } 356 357 if (status & (USB_STS_IRQ_FLAG | USB_STS_ERR_IRQ_FLAG)) { 358 fibril_mutex_lock(&hc->guard); 359 360 usb_log_debug2("HC(%p): Scanning %zu pending endpoints", hc, 361 list_count(&hc->pending_endpoints)); 362 list_foreach_safe(hc->pending_endpoints, current, next) { 363 ehci_endpoint_t *ep = 364 list_get_instance(current, ehci_endpoint_t, pending_link); 365 366 ehci_transfer_batch_t *batch = 367 ehci_transfer_batch_get(ep->base.active_batch); 368 assert(batch); 369 370 if (ehci_transfer_batch_check_completed(batch)) { 371 endpoint_deactivate_locked(&ep->base); 372 list_remove(current); 373 hc_reset_toggles(&batch->base, &ehci_ep_toggle_reset); 374 usb_transfer_batch_finish(&batch->base); 375 } 376 } 377 fibril_mutex_unlock(&hc->guard); 378 379 } 380 381 if (status & USB_STS_HOST_ERROR_FLAG) { 382 usb_log_fatal("HCD(%p): HOST SYSTEM ERROR!", hc); 383 //TODO do something here 384 } 385 } 386 387 /** EHCI hw initialization routine. 388 * 389 * @param[in] instance EHCI hc driver structure. 390 */ 391 int hc_start(hc_device_t *hcd) 220 392 { 221 393 hc_t *instance = hcd_to_hc(hcd); 394 usb_log_debug("HC(%p): Starting HW.", instance); 222 395 223 396 /* … … 249 422 usb_log_debug("HC(%p): HW reset OK.", instance); 250 423 251 return EOK;252 }253 254 void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)255 {256 assert(instance);257 assert(ep);258 ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep);259 usb_log_debug("HC(%p) enqueue EP(%d:%d:%s:%s)", instance,260 ep->device->address, ep->endpoint,261 usb_str_transfer_type_short(ep->transfer_type),262 usb_str_direction(ep->direction));263 switch (ep->transfer_type) {264 case USB_TRANSFER_CONTROL:265 case USB_TRANSFER_BULK:266 endpoint_list_append_ep(&instance->async_list, ehci_ep);267 break;268 case USB_TRANSFER_INTERRUPT:269 endpoint_list_append_ep(&instance->int_list, ehci_ep);270 break;271 case USB_TRANSFER_ISOCHRONOUS:272 /* NOT SUPPORTED */273 break;274 }275 }276 277 void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep)278 {279 assert(instance);280 assert(ep);281 ehci_endpoint_t *ehci_ep = ehci_endpoint_get(ep);282 usb_log_debug("HC(%p) dequeue EP(%d:%d:%s:%s)", instance,283 ep->device->address, ep->endpoint,284 usb_str_transfer_type_short(ep->transfer_type),285 usb_str_direction(ep->direction));286 switch (ep->transfer_type) {287 case USB_TRANSFER_INTERRUPT:288 endpoint_list_remove_ep(&instance->int_list, ehci_ep);289 /* Fall through */290 case USB_TRANSFER_ISOCHRONOUS:291 /* NOT SUPPORTED */292 return;293 case USB_TRANSFER_CONTROL:294 case USB_TRANSFER_BULK:295 endpoint_list_remove_ep(&instance->async_list, ehci_ep);296 break;297 }298 fibril_mutex_lock(&instance->guard);299 usb_log_debug("HC(%p): Waiting for doorbell", instance);300 EHCI_SET(instance->registers->usbcmd, USB_CMD_IRQ_ASYNC_DOORBELL);301 fibril_condvar_wait(&instance->async_doorbell, &instance->guard);302 usb_log_debug2("HC(%p): Got doorbell", instance);303 fibril_mutex_unlock(&instance->guard);304 }305 306 errno_t ehci_hc_status(bus_t *bus_base, uint32_t *status)307 {308 assert(bus_base);309 assert(status);310 311 ehci_bus_t *bus = (ehci_bus_t *) bus_base;312 hc_t *hc = bus->hc;313 assert(hc);314 315 *status = 0;316 if (hc->registers) {317 *status = EHCI_RD(hc->registers->usbsts);318 EHCI_WR(hc->registers->usbsts, *status);319 }320 usb_log_debug2("HC(%p): Read status: %x", hc, *status);321 return EOK;322 }323 324 /** Add USB transfer to the schedule.325 *326 * @param[in] hcd HCD driver structure.327 * @param[in] batch Batch representing the transfer.328 * @return Error code.329 */330 errno_t ehci_hc_schedule(usb_transfer_batch_t *batch)331 {332 assert(batch);333 334 ehci_bus_t *bus = (ehci_bus_t *) endpoint_get_bus(batch->ep);335 hc_t *hc = bus->hc;336 assert(hc);337 338 /* Check for root hub communication */339 if (batch->target.address == ehci_rh_get_address(&hc->rh)) {340 usb_log_debug("HC(%p): Scheduling BATCH(%p) for RH(%p)",341 hc, batch, &hc->rh);342 return ehci_rh_schedule(&hc->rh, batch);343 }344 345 endpoint_t *const ep = batch->ep;346 ehci_endpoint_t *const ehci_ep = ehci_endpoint_get(ep);347 ehci_transfer_batch_t *ehci_batch = ehci_transfer_batch_get(batch);348 349 int err;350 351 if ((err = ehci_transfer_batch_prepare(ehci_batch)))352 return err;353 354 fibril_mutex_lock(&hc->guard);355 356 if ((err = endpoint_activate_locked(ep, batch))) {357 fibril_mutex_unlock(&hc->guard);358 return err;359 }360 361 usb_log_debug("HC(%p): Committing BATCH(%p)", hc, batch);362 ehci_transfer_batch_commit(ehci_batch);363 364 /* Enqueue endpoint to the checked list */365 usb_log_debug2("HC(%p): Appending BATCH(%p)", hc, batch);366 list_append(&ehci_ep->pending_link, &hc->pending_endpoints);367 368 fibril_mutex_unlock(&hc->guard);369 return EOK;370 }371 372 /** Interrupt handling routine373 *374 * @param[in] hcd HCD driver structure.375 * @param[in] status Value of the status register at the time of interrupt.376 */377 void ehci_hc_interrupt(bus_t *bus_base, uint32_t status)378 {379 assert(bus_base);380 381 ehci_bus_t *bus = (ehci_bus_t *) bus_base;382 hc_t *hc = bus->hc;383 assert(hc);384 385 usb_log_debug2("HC(%p): Interrupt: %" PRIx32, hc, status);386 if (status & USB_STS_PORT_CHANGE_FLAG) {387 ehci_rh_interrupt(&hc->rh);388 }389 390 if (status & USB_STS_IRQ_ASYNC_ADVANCE_FLAG) {391 fibril_mutex_lock(&hc->guard);392 usb_log_debug2("HC(%p): Signaling doorbell", hc);393 fibril_condvar_broadcast(&hc->async_doorbell);394 fibril_mutex_unlock(&hc->guard);395 }396 397 if (status & (USB_STS_IRQ_FLAG | USB_STS_ERR_IRQ_FLAG)) {398 fibril_mutex_lock(&hc->guard);399 400 usb_log_debug2("HC(%p): Scanning %zu pending endpoints", hc,401 list_count(&hc->pending_endpoints));402 list_foreach_safe(hc->pending_endpoints, current, next) {403 ehci_endpoint_t *ep =404 list_get_instance(current, ehci_endpoint_t, pending_link);405 406 ehci_transfer_batch_t *batch =407 ehci_transfer_batch_get(ep->base.active_batch);408 assert(batch);409 410 if (ehci_transfer_batch_check_completed(batch)) {411 endpoint_deactivate_locked(&ep->base);412 list_remove(current);413 hc_reset_toggles(&batch->base, &ehci_ep_toggle_reset);414 usb_transfer_batch_finish(&batch->base);415 }416 }417 fibril_mutex_unlock(&hc->guard);418 419 }420 421 if (status & USB_STS_HOST_ERROR_FLAG) {422 usb_log_fatal("HCD(%p): HOST SYSTEM ERROR!", hc);423 //TODO do something here424 }425 }426 427 /** EHCI hw initialization routine.428 *429 * @param[in] instance EHCI hc driver structure.430 */431 int hc_start(hc_device_t *hcd)432 {433 hc_t *instance = hcd_to_hc(hcd);434 usb_log_debug("HC(%p): Starting HW.", instance);435 436 /*437 * Turn off the HC if it's running, Reseting a running device is438 * undefined439 */440 if (!(EHCI_RD(instance->registers->usbsts) & USB_STS_HC_HALTED_FLAG)) {441 /* disable all interrupts */442 EHCI_WR(instance->registers->usbintr, 0);443 /* ack all interrupts */444 EHCI_WR(instance->registers->usbsts, 0x3f);445 /* Stop HC hw */446 EHCI_WR(instance->registers->usbcmd, 0);447 /* Wait until hc is halted */448 while ((EHCI_RD(instance->registers->usbsts) & USB_STS_HC_HALTED_FLAG) == 0) {449 fibril_usleep(1);450 }451 usb_log_info("HC(%p): EHCI turned off.", instance);452 } else {453 usb_log_info("HC(%p): EHCI was not running.", instance);454 }455 456 /* Hw initialization sequence, see page 53 (pdf 63) */457 EHCI_SET(instance->registers->usbcmd, USB_CMD_HC_RESET_FLAG);458 usb_log_info("HC(%p): Waiting for HW reset.", instance);459 while (EHCI_RD(instance->registers->usbcmd) & USB_CMD_HC_RESET_FLAG) {460 fibril_usleep(1);461 }462 usb_log_debug("HC(%p): HW reset OK.", instance);463 464 424 /* Use the lowest 4G segment */ 465 425 EHCI_WR(instance->registers->ctrldssegment, 0);
Note:
See TracChangeset
for help on using the changeset viewer.