Changes in uspace/drv/bus/usb/usbhub/port.c [58563585:ffa96c2] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/port.c
r58563585 rffa96c2 27 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 28 */ 29 30 29 /** @addtogroup drvusbhub 31 30 * @{ … … 42 41 43 42 #include <usb/debug.h> 43 #include <usb/dev/hub.h> 44 44 45 45 #include "port.h" … … 56 56 static int usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub); 57 57 static void usb_hub_port_reset_completed(usb_hub_port_t *port, 58 usb_ hub_dev_t *hub, usb_port_status_t status);58 usb_port_status_t status); 59 59 static int get_port_status(usb_hub_port_t *port, usb_port_status_t *status); 60 static int enable_port_callback(void *arg); 60 61 static int add_device_phase1_worker_fibril(void *arg); 61 62 static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub, … … 65 66 { 66 67 assert(port); 67 if (port-> device_attached)68 if (port->attached_device.fun) 68 69 return usb_hub_port_device_gone(port, hub); 69 70 return EOK; … … 123 124 assert(port); 124 125 fibril_mutex_lock(&port->mutex); 125 if (port->reset_status == IN_RESET)126 port->reset_status = RESET_FAIL;126 port->reset_completed = true; 127 port->reset_okay = false; 127 128 fibril_condvar_broadcast(&port->reset_cv); 128 129 fibril_mutex_unlock(&port->mutex); … … 140 141 assert(port); 141 142 assert(hub); 142 usb_log_debug 2("(%p-%u): Interrupt.\n", hub, port->port_number);143 usb_log_debug("Interrupt at port %zu\n", port->port_number); 143 144 144 145 usb_port_status_t status = 0; 145 146 const int opResult = get_port_status(port, &status); 146 147 if (opResult != EOK) { 147 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", 148 149 port->port_number, str_error(opResult)); 149 150 return; … … 154 155 const bool connected = 155 156 (status & USB_HUB_PORT_STATUS_CONNECTION) != 0; 156 usb_log_debug(" (%p-%u): Connection change: device %s.\n", hub,157 usb_log_debug("Connection change on port %zu: device %s.\n", 157 158 port->port_number, connected ? "attached" : "removed"); 158 159 … … 161 162 USB_HUB_FEATURE_C_PORT_CONNECTION); 162 163 if (opResult != EOK) { 163 usb_log_warning("(%p-%u): Failed to clear " 164 "port-change-connection flag: %s.\n", hub, 165 port->port_number, str_error(opResult)); 164 usb_log_warning("Failed to clear port-change-connection" 165 " flag: %s.\n", str_error(opResult)); 166 166 } 167 167 … … 170 170 usb_port_speed(status)); 171 171 if (opResult != EOK) { 172 usb_log_error( "(%p-%u): Cannot handle change on"173 " port: %s.\n", hub, port->port_number,174 str_error(opResult));172 usb_log_error( 173 "Cannot handle change on port %zu: %s.\n", 174 port->port_number, str_error(opResult)); 175 175 } 176 176 } else { 177 /* Handle the case we were in reset */178 // FIXME: usb_hub_port_reset_fail(port);179 177 /* If enabled change was reported leave the removal 180 178 * to that handler, it shall ACK the change too. */ … … 187 185 /* Enable change, ports are automatically disabled on errors. */ 188 186 if (status & USB_HUB_PORT_C_STATUS_ENABLED) { 189 // TODO: maybe HS reset failed? 190 usb_log_info("(%p-%u): Port disabled because of errors.\n", hub, 187 usb_log_info("Port %zu, disabled because of errors.\n", 191 188 port->port_number); 192 189 usb_hub_port_device_gone(port, hub); … … 194 191 USB_HUB_FEATURE_C_PORT_ENABLE); 195 192 if (rc != EOK) { 196 usb_log_error( "(%p-%u): Failed to clear port enable "197 " change feature: %s.", hub, port->port_number,198 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)); 199 196 } 200 197 … … 203 200 /* Suspend change */ 204 201 if (status & USB_HUB_PORT_C_STATUS_SUSPEND) { 205 usb_log_error(" (%p-%u): Portwent to suspend state, this should"206 " 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!", 207 204 port->port_number); 208 205 const int rc = usb_hub_port_clear_feature(port, 209 206 USB_HUB_FEATURE_C_PORT_SUSPEND); 210 207 if (rc != EOK) { 211 usb_log_error( "(%p-%u): Failed to clear port suspend "212 " change feature: %s.", hub, port->port_number,213 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)); 214 211 } 215 212 } … … 217 214 /* Over current */ 218 215 if (status & USB_HUB_PORT_C_STATUS_OC) { 219 usb_log_debug("(%p-%u): Port OC reported!.", hub,220 port->port_number);221 216 /* According to the USB specs: 222 217 * 11.13.5 Over-current Reporting and Recovery … … 227 222 USB_HUB_FEATURE_C_PORT_OVER_CURRENT); 228 223 if (rc != EOK) { 229 usb_log_error( "(%p-%u): Failed to clear port OC change "230 " feature: %s.\n", hub, port->port_number,231 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)); 232 227 } 233 228 if (!(status & ~USB_HUB_PORT_STATUS_OC)) { … … 235 230 port, USB_HUB_FEATURE_PORT_POWER); 236 231 if (rc != EOK) { 237 usb_log_error( "(%p-%u): Failed to set port "238 " power after OC: %s.", hub,239 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)); 240 235 } 241 236 } … … 244 239 /* Port reset, set on port reset complete. */ 245 240 if (status & USB_HUB_PORT_C_STATUS_RESET) { 246 usb_hub_port_reset_completed(port, hub,status);247 } 248 249 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", 250 245 port->port_number, status); 251 246 } … … 264 259 assert(port); 265 260 assert(hub); 266 async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device); 267 if (!exch) 268 return ENOMEM; 269 const int rc = usb_device_remove(exch, port->port_number); 270 usb_device_bus_exchange_end(exch); 271 if (rc == EOK) 272 port->device_attached = false; 273 return rc; 274 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; 275 300 } 276 301 … … 283 308 * @param status Port status mask 284 309 */ 285 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, 286 311 usb_port_status_t status) 287 312 { 288 313 assert(port); 289 314 fibril_mutex_lock(&port->mutex); 290 const bool enabled = (status & USB_HUB_PORT_STATUS_ENABLED) != 0;291 315 /* Finalize device adding. */ 292 293 if (enabled) { 294 port->reset_status = RESET_OK; 295 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", 296 324 port->port_number); 297 } else {298 port->reset_status = RESET_FAIL;299 usb_log_warning("(%p-%u): Port reset complete but port not "300 "enabled.", hub, port->port_number);301 325 } 302 326 fibril_condvar_broadcast(&port->reset_cv); … … 306 330 int rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET); 307 331 if (rc != EOK) { 308 usb_log_error("(%p-%u): Failed to clear port reset change: %s.", 309 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)); 310 335 } 311 336 } … … 351 376 } 352 377 353 static int port_enable(usb_hub_port_t *port, usb_hub_dev_t *hub, bool enable) 354 { 355 if (enable) { 356 int rc = 357 usb_hub_port_set_feature(port, USB_HUB_FEATURE_PORT_RESET); 358 if (rc != EOK) { 359 usb_log_error("(%p-%u): Port reset request failed: %s.", 360 hub, port->port_number, str_error(rc)); 361 return rc; 362 } 363 /* Wait until reset completes. */ 364 fibril_mutex_lock(&port->mutex);365 port->reset_status = IN_RESET;366 while (port->reset_status == IN_RESET)367 fibril_condvar_wait(&port->reset_cv, &port->mutex);368 rc = port->reset_status == RESET_OK ? EOK : ESTALL;369 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)); 370 395 return rc; 371 } else { 372 return usb_hub_port_clear_feature(port, 373 USB_HUB_FEATURE_PORT_ENABLE); 374 } 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; 375 408 } 376 409 … … 385 418 int add_device_phase1_worker_fibril(void *arg) 386 419 { 387 struct add_device_phase1 *params = arg; 388 assert(params); 389 390 int ret = EOK; 391 usb_hub_dev_t *hub = params->hub; 392 usb_hub_port_t *port = params->port; 393 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 394 459 free(arg); 395 460 396 usb_log_debug("(%p-%u): New device sequence.", hub, port->port_number); 397 398 async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device); 399 if (!exch) { 400 usb_log_error("(%p-%u): Failed to begin bus exchange.", hub, 401 port->port_number); 402 ret = ENOMEM; 403 goto out; 404 } 405 406 /* Reserve default address */ 407 while ((ret = usb_reserve_default_address(exch, speed)) == ENOENT) { 408 async_usleep(1000000); 409 } 410 if (ret != EOK) { 411 usb_log_error("(%p-%u): Failed to reserve default address: %s", 412 hub, port->port_number, str_error(ret)); 413 goto out; 414 } 415 416 usb_log_debug("(%p-%u): Got default address reseting port.", hub, 417 port->port_number); 418 /* Reset port */ 419 ret = port_enable(port, hub, true); 420 if (ret != EOK) { 421 usb_log_error("(%p-%u): Failed to reset port.", hub, 422 port->port_number); 423 if (usb_release_default_address(exch) != EOK) 424 usb_log_warning("(%p-%u): Failed to release default " 425 "address.", hub, port->port_number); 426 ret = EIO; 427 goto out; 428 } 429 usb_log_debug("(%p-%u): Port reset, enumerating device", hub, 430 port->port_number); 431 432 ret = usb_device_enumerate(exch, port->port_number); 433 if (ret != EOK) { 434 usb_log_error("(%p-%u): Failed to enumerate device: %s", hub, 435 port->port_number, str_error(ret)); 436 const int ret = port_enable(port, hub, false); 437 if (ret != EOK) { 438 usb_log_warning("(%p-%u)Failed to disable port (%s), " 439 "NOT releasing default address.", hub, 440 port->port_number, str_error(ret)); 441 } else { 442 const int ret = usb_release_default_address(exch); 443 if (ret != EOK) 444 usb_log_warning("(%p-%u): Failed to release " 445 "default address: %s", hub, 446 port->port_number, str_error(ret)); 447 } 448 } else { 449 usb_log_debug("(%p-%u): Device enumerated", hub, 450 port->port_number); 451 port->device_attached = true; 452 if (usb_release_default_address(exch) != EOK) 453 usb_log_warning("(%p-%u): Failed to release default " 454 "address", hub, port->port_number); 455 } 456 out: 457 usb_device_bus_exchange_end(exch); 458 459 fibril_mutex_lock(&hub->pending_ops_mutex); 460 assert(hub->pending_ops_count > 0); 461 --hub->pending_ops_count; 462 fibril_condvar_signal(&hub->pending_ops_cv); 463 fibril_mutex_unlock(&hub->pending_ops_mutex); 464 465 return ret; 461 return rc; 466 462 } 467 463 … … 489 485 data->speed = speed; 490 486 487 fibril_mutex_lock(&port->mutex); 488 port->reset_completed = false; 489 fibril_mutex_unlock(&port->mutex); 490 491 491 fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data); 492 492 if (fibril == 0) {
Note:
See TracChangeset
for help on using the changeset viewer.