Changes in uspace/drv/bus/usb/usbhub/port.c [8351f9a4:ffa96c2] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/port.c
r8351f9a4 rffa96c2 41 41 42 42 #include <usb/debug.h> 43 #include <usb/dev/hub.h> 43 44 44 45 #include "port.h" … … 55 56 static int usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub); 56 57 static void usb_hub_port_reset_completed(usb_hub_port_t *port, 57 usb_ hub_dev_t *hub, usb_port_status_t status);58 usb_port_status_t status); 58 59 static int get_port_status(usb_hub_port_t *port, usb_port_status_t *status); 60 static int enable_port_callback(void *arg); 59 61 static int add_device_phase1_worker_fibril(void *arg); 60 62 static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub, … … 64 66 { 65 67 assert(port); 66 if (port-> device_attached)68 if (port->attached_device.fun) 67 69 return usb_hub_port_device_gone(port, hub); 68 70 return EOK; … … 122 124 assert(port); 123 125 fibril_mutex_lock(&port->mutex); 124 if (port->reset_status == IN_RESET)125 port->reset_status = RESET_FAIL;126 port->reset_completed = true; 127 port->reset_okay = false; 126 128 fibril_condvar_broadcast(&port->reset_cv); 127 129 fibril_mutex_unlock(&port->mutex); … … 139 141 assert(port); 140 142 assert(hub); 141 usb_log_debug 2("(%p-%u): Interrupt.\n", hub, port->port_number);143 usb_log_debug("Interrupt at port %zu\n", port->port_number); 142 144 143 145 usb_port_status_t status = 0; 144 146 const int opResult = get_port_status(port, &status); 145 147 if (opResult != EOK) { 146 usb_log_error(" (%p-%u): Failed to get port status: %s.\n", hub,148 usb_log_error("Failed to get port %zu status: %s.\n", 147 149 port->port_number, str_error(opResult)); 148 150 return; … … 153 155 const bool connected = 154 156 (status & USB_HUB_PORT_STATUS_CONNECTION) != 0; 155 usb_log_debug(" (%p-%u): Connection change: device %s.\n", hub,157 usb_log_debug("Connection change on port %zu: device %s.\n", 156 158 port->port_number, connected ? "attached" : "removed"); 157 159 … … 160 162 USB_HUB_FEATURE_C_PORT_CONNECTION); 161 163 if (opResult != EOK) { 162 usb_log_warning("(%p-%u): Failed to clear " 163 "port-change-connection flag: %s.\n", hub, 164 port->port_number, str_error(opResult)); 164 usb_log_warning("Failed to clear port-change-connection" 165 " flag: %s.\n", str_error(opResult)); 165 166 } 166 167 … … 169 170 usb_port_speed(status)); 170 171 if (opResult != EOK) { 171 usb_log_error( "(%p-%u): Cannot handle change on"172 " port: %s.\n", hub, port->port_number,173 str_error(opResult));172 usb_log_error( 173 "Cannot handle change on port %zu: %s.\n", 174 port->port_number, str_error(opResult)); 174 175 } 175 176 } else { 176 /* Handle the case we were in reset */177 //usb_hub_port_reset_fail(port);178 177 /* If enabled change was reported leave the removal 179 178 * to that handler, it shall ACK the change too. */ … … 186 185 /* Enable change, ports are automatically disabled on errors. */ 187 186 if (status & USB_HUB_PORT_C_STATUS_ENABLED) { 188 //TODO: maybe HS reset failed? 189 usb_log_info("(%p-%u): Port disabled because of errors.\n", hub, 187 usb_log_info("Port %zu, disabled because of errors.\n", 190 188 port->port_number); 191 189 usb_hub_port_device_gone(port, hub); … … 193 191 USB_HUB_FEATURE_C_PORT_ENABLE); 194 192 if (rc != EOK) { 195 usb_log_error( "(%p-%u): Failed to clear port enable "196 " change feature: %s.", hub, port->port_number,197 str_error(rc));193 usb_log_error( 194 "Failed to clear port %zu enable change feature: " 195 "%s.\n", port->port_number, str_error(rc)); 198 196 } 199 197 … … 202 200 /* Suspend change */ 203 201 if (status & USB_HUB_PORT_C_STATUS_SUSPEND) { 204 usb_log_error(" (%p-%u): Portwent to suspend state, this should"205 " NOT happen as we do not support suspend state!", hub,202 usb_log_error("Port %zu went to suspend state, this should" 203 "NOT happen as we do not support suspend state!", 206 204 port->port_number); 207 205 const int rc = usb_hub_port_clear_feature(port, 208 206 USB_HUB_FEATURE_C_PORT_SUSPEND); 209 207 if (rc != EOK) { 210 usb_log_error( "(%p-%u): Failed to clear port suspend "211 " change feature: %s.", hub, port->port_number,212 str_error(rc));208 usb_log_error( 209 "Failed to clear port %zu suspend change feature: " 210 "%s.\n", port->port_number, str_error(rc)); 213 211 } 214 212 } … … 216 214 /* Over current */ 217 215 if (status & USB_HUB_PORT_C_STATUS_OC) { 218 usb_log_debug("(%p-%u): Port OC reported!.", hub,219 port->port_number);220 216 /* According to the USB specs: 221 217 * 11.13.5 Over-current Reporting and Recovery … … 226 222 USB_HUB_FEATURE_C_PORT_OVER_CURRENT); 227 223 if (rc != EOK) { 228 usb_log_error( "(%p-%u): Failed to clear port OC change "229 " feature: %s.\n", hub, port->port_number,230 str_error(rc));224 usb_log_error( 225 "Failed to clear port %zu OC change feature: %s.\n", 226 port->port_number, str_error(rc)); 231 227 } 232 228 if (!(status & ~USB_HUB_PORT_STATUS_OC)) { … … 234 230 port, USB_HUB_FEATURE_PORT_POWER); 235 231 if (rc != EOK) { 236 usb_log_error( "(%p-%u): Failed to set port "237 " power after OC: %s.", hub,238 port->port_number, str_error(rc));232 usb_log_error( 233 "Failed to set port %zu power after OC:" 234 " %s.\n", port->port_number, str_error(rc)); 239 235 } 240 236 } … … 243 239 /* Port reset, set on port reset complete. */ 244 240 if (status & USB_HUB_PORT_C_STATUS_RESET) { 245 usb_hub_port_reset_completed(port, hub,status);246 } 247 248 usb_log_debug 2("(%p-%u): Port status %#08" PRIx32, hub,241 usb_hub_port_reset_completed(port, status); 242 } 243 244 usb_log_debug("Port %zu status 0x%08" PRIx32 "\n", 249 245 port->port_number, status); 250 246 } … … 263 259 assert(port); 264 260 assert(hub); 265 async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device); 266 if (!exch) 267 return ENOMEM; 268 const int rc = usb_device_remove(exch, port->port_number); 269 usb_device_bus_exchange_end(exch); 270 if (rc == EOK) 271 port->device_attached = false; 272 return rc; 273 261 if (port->attached_device.address < 0) { 262 usb_log_warning( 263 "Device on port %zu removed before being registered.\n", 264 port->port_number); 265 266 /* 267 * Device was removed before port reset completed. 268 * We will announce a failed port reset to unblock the 269 * port reset callback from new device wrapper. 270 */ 271 usb_hub_port_reset_fail(port); 272 return EOK; 273 } 274 275 fibril_mutex_lock(&port->mutex); 276 assert(port->attached_device.fun); 277 usb_log_debug("Removing device on port %zu.\n", port->port_number); 278 int ret = ddf_fun_unbind(port->attached_device.fun); 279 if (ret != EOK) { 280 usb_log_error("Failed to unbind child function on port" 281 " %zu: %s.\n", port->port_number, str_error(ret)); 282 fibril_mutex_unlock(&port->mutex); 283 return ret; 284 } 285 286 ddf_fun_destroy(port->attached_device.fun); 287 port->attached_device.fun = NULL; 288 289 ret = usb_hub_unregister_device(&hub->usb_device->hc_conn, 290 &port->attached_device); 291 if (ret != EOK) { 292 usb_log_warning("Failed to unregister address of the " 293 "removed device: %s.\n", str_error(ret)); 294 } 295 296 port->attached_device.address = -1; 297 fibril_mutex_unlock(&port->mutex); 298 usb_log_info("Removed device on port %zu.\n", port->port_number); 299 return EOK; 274 300 } 275 301 … … 282 308 * @param status Port status mask 283 309 */ 284 void usb_hub_port_reset_completed(usb_hub_port_t *port, usb_hub_dev_t *hub,310 void usb_hub_port_reset_completed(usb_hub_port_t *port, 285 311 usb_port_status_t status) 286 312 { 287 313 assert(port); 288 314 fibril_mutex_lock(&port->mutex); 289 const bool enabled = (status & USB_HUB_PORT_STATUS_ENABLED) != 0;290 315 /* Finalize device adding. */ 291 292 if (enabled) { 293 port->reset_status = RESET_OK; 294 usb_log_debug("(%p-%u): Port reset complete.\n", hub, 316 port->reset_completed = true; 317 port->reset_okay = (status & USB_HUB_PORT_STATUS_ENABLED) != 0; 318 319 if (port->reset_okay) { 320 usb_log_debug("Port %zu reset complete.\n", port->port_number); 321 } else { 322 usb_log_warning( 323 "Port %zu reset complete but port not enabled.\n", 295 324 port->port_number); 296 } else {297 port->reset_status = RESET_FAIL;298 usb_log_warning("(%p-%u): Port reset complete but port not "299 "enabled.", hub, port->port_number);300 325 } 301 326 fibril_condvar_broadcast(&port->reset_cv); … … 305 330 int rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET); 306 331 if (rc != EOK) { 307 usb_log_error("(%p-%u): Failed to clear port reset change: %s.", 308 hub, port->port_number, str_error(rc)); 332 usb_log_error( 333 "Failed to clear port %zu reset change feature: %s.\n", 334 port->port_number, str_error(rc)); 309 335 } 310 336 } … … 350 376 } 351 377 352 static int port_enable(usb_hub_port_t *port, usb_hub_dev_t *hub, bool enable) 353 { 354 if (enable) { 355 int rc = 356 usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET); 357 if (rc != EOK) { 358 usb_log_error("(%p-%u): Port reset request failed: %s.", 359 hub, port->port_number, str_error(rc)); 360 return rc; 361 } 362 /* Wait until reset completes. */ 363 fibril_mutex_lock(&port->mutex);364 port->reset_status = IN_RESET;365 while (port->reset_status == IN_RESET)366 fibril_condvar_wait(&port->reset_cv, &port->mutex);367 rc = port->reset_status == RESET_OK ? EOK : ESTALL;368 fibril_mutex_unlock(&port->mutex);378 /** Callback for enabling a specific port. 379 * 380 * We wait on a CV until port is reseted. 381 * That is announced via change on interrupt pipe. 382 * 383 * @param port_no Port number (starting at 1). 384 * @param arg Custom argument, points to @c usb_hub_dev_t. 385 * @return Error code. 386 */ 387 static int enable_port_callback(void *arg) 388 { 389 usb_hub_port_t *port = arg; 390 assert(port); 391 const int rc = 392 usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET); 393 if (rc != EOK) { 394 usb_log_warning("Port reset failed: %s.\n", str_error(rc)); 369 395 return rc; 370 } else { 371 return usb_hub_port_clear_feature(port, 372 USB_HUB_FEATURE_PORT_ENABLE); 373 } 396 } 397 398 /* 399 * Wait until reset completes. 400 */ 401 fibril_mutex_lock(&port->mutex); 402 while (!port->reset_completed) { 403 fibril_condvar_wait(&port->reset_cv, &port->mutex); 404 } 405 fibril_mutex_unlock(&port->mutex); 406 407 return port->reset_okay ? EOK : ESTALL; 374 408 } 375 409 … … 384 418 int add_device_phase1_worker_fibril(void *arg) 385 419 { 386 struct add_device_phase1 *params = arg; 387 assert(params); 388 389 int ret = EOK; 390 usb_hub_dev_t *hub = params->hub; 391 usb_hub_port_t *port = params->port; 392 const usb_speed_t speed = params->speed; 420 struct add_device_phase1 *data = arg; 421 assert(data); 422 423 usb_address_t new_address; 424 ddf_fun_t *child_fun; 425 426 child_fun = ddf_fun_create(data->hub->usb_device->ddf_dev, 427 fun_inner, NULL); 428 if (child_fun == NULL) 429 return ENOMEM; 430 431 const int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev, 432 child_fun, &data->hub->usb_device->hc_conn, data->speed, 433 enable_port_callback, data->port, &new_address, NULL); 434 435 if (rc == EOK) { 436 fibril_mutex_lock(&data->port->mutex); 437 data->port->attached_device.fun = child_fun; 438 data->port->attached_device.address = new_address; 439 fibril_mutex_unlock(&data->port->mutex); 440 441 usb_log_info("Detected new device on `%s' (port %zu), " 442 "address %d (handle %" PRIun ").\n", 443 ddf_dev_get_name(data->hub->usb_device->ddf_dev), 444 data->port->port_number, new_address, 445 ddf_fun_get_handle(child_fun)); 446 } else { 447 ddf_fun_destroy(child_fun); 448 usb_log_error("Failed registering device on port %zu: %s.\n", 449 data->port->port_number, str_error(rc)); 450 } 451 452 453 fibril_mutex_lock(&data->hub->pending_ops_mutex); 454 assert(data->hub->pending_ops_count > 0); 455 --data->hub->pending_ops_count; 456 fibril_condvar_signal(&data->hub->pending_ops_cv); 457 fibril_mutex_unlock(&data->hub->pending_ops_mutex); 458 393 459 free(arg); 394 460 395 usb_log_debug("(%p-%u): New device sequence.", hub, port->port_number); 396 397 async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device); 398 if (!exch) { 399 usb_log_error("(%p-%u): Failed to begin bus exchange.", hub, 400 port->port_number); 401 ret = ENOMEM; 402 goto out; 403 } 404 405 /* Reserve default address */ 406 while ((ret = usb_reserve_default_address(exch, speed)) == ENOENT) { 407 async_usleep(1000000); 408 } 409 if (ret != EOK) { 410 usb_log_error("(%p-%u): Failed to reserve default address: %s", 411 hub, port->port_number, str_error(ret)); 412 goto out; 413 } 414 415 usb_log_debug("(%p-%u): Got default address reseting port.", hub, 416 port->port_number); 417 /* Reset port */ 418 ret = port_enable(port, hub, true); 419 if (ret != EOK) { 420 usb_log_error("(%p-%u): Failed to reset port.", hub, 421 port->port_number); 422 if (usb_release_default_address(exch) != EOK) 423 usb_log_warning("(%p-%u): Failed to release default " 424 "address.", hub, port->port_number); 425 ret = EIO; 426 goto out; 427 } 428 usb_log_debug("(%p-%u): Port reset, enumerating device", hub, 429 port->port_number); 430 431 ret = usb_device_enumerate(exch, port->port_number); 432 if (ret != EOK) { 433 usb_log_error("(%p-%u): Failed to enumerate device: %s", hub, 434 port->port_number, str_error(ret)); 435 const int ret = port_enable(port, hub, false); 436 if (ret != EOK) { 437 usb_log_warning("(%p-%u)Failed to disable port (%s), " 438 "NOT releasing default address.", hub, 439 port->port_number, str_error(ret)); 440 } else { 441 const int ret = usb_release_default_address(exch); 442 if (ret != EOK) 443 usb_log_warning("(%p-%u): Failed to release " 444 "default address: %s", hub, 445 port->port_number, str_error(ret)); 446 } 447 } else { 448 usb_log_debug("(%p-%u): Device enumerated", hub, 449 port->port_number); 450 port->device_attached = true; 451 if (usb_release_default_address(exch) != EOK) 452 usb_log_warning("(%p-%u): Failed to release default " 453 "address", hub, port->port_number); 454 } 455 out: 456 usb_device_bus_exchange_end(exch); 457 458 fibril_mutex_lock(&hub->pending_ops_mutex); 459 assert(hub->pending_ops_count > 0); 460 --hub->pending_ops_count; 461 fibril_condvar_signal(&hub->pending_ops_cv); 462 fibril_mutex_unlock(&hub->pending_ops_mutex); 463 464 return ret; 461 return rc; 465 462 } 466 463 … … 488 485 data->speed = speed; 489 486 487 fibril_mutex_lock(&port->mutex); 488 port->reset_completed = false; 489 fibril_mutex_unlock(&port->mutex); 490 490 491 fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data); 491 492 if (fibril == 0) {
Note:
See TracChangeset
for help on using the changeset viewer.