Changes in uspace/drv/bus/usb/usbhub/port.c [c4f7bf6:58563585] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/port.c
rc4f7bf6 r58563585 27 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 28 */ 29 29 30 /** @addtogroup drvusbhub 30 31 * @{ … … 41 42 42 43 #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_ port_status_t status);58 usb_hub_dev_t *hub, 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);61 60 static int add_device_phase1_worker_fibril(void *arg); 62 61 static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub, … … 66 65 { 67 66 assert(port); 68 if (port-> attached_device.fun)67 if (port->device_attached) 69 68 return usb_hub_port_device_gone(port, hub); 70 69 return EOK; … … 124 123 assert(port); 125 124 fibril_mutex_lock(&port->mutex); 126 port->reset_completed = true;127 port->reset_okay = false;125 if (port->reset_status == IN_RESET) 126 port->reset_status = RESET_FAIL; 128 127 fibril_condvar_broadcast(&port->reset_cv); 129 128 fibril_mutex_unlock(&port->mutex); … … 141 140 assert(port); 142 141 assert(hub); 143 usb_log_debug ("Interrupt at port %zu\n", port->port_number);142 usb_log_debug2("(%p-%u): Interrupt.\n", hub, port->port_number); 144 143 145 144 usb_port_status_t status = 0; 146 145 const int opResult = get_port_status(port, &status); 147 146 if (opResult != EOK) { 148 usb_log_error(" Failed to get port %zu status: %s.\n",147 usb_log_error("(%p-%u): Failed to get port status: %s.\n", hub, 149 148 port->port_number, str_error(opResult)); 150 149 return; … … 155 154 const bool connected = 156 155 (status & USB_HUB_PORT_STATUS_CONNECTION) != 0; 157 usb_log_debug(" Connection change on port %zu: device %s.\n",156 usb_log_debug("(%p-%u): Connection change: device %s.\n", hub, 158 157 port->port_number, connected ? "attached" : "removed"); 159 158 … … 162 161 USB_HUB_FEATURE_C_PORT_CONNECTION); 163 162 if (opResult != EOK) { 164 usb_log_warning("Failed to clear port-change-connection" 165 " flag: %s.\n", str_error(opResult)); 163 usb_log_warning("(%p-%u): Failed to clear " 164 "port-change-connection flag: %s.\n", hub, 165 port->port_number, str_error(opResult)); 166 166 } 167 167 … … 170 170 usb_port_speed(status)); 171 171 if (opResult != EOK) { 172 usb_log_error( 173 "Cannot handle change on port %zu: %s.\n",174 port->port_number,str_error(opResult));172 usb_log_error("(%p-%u): Cannot handle change on" 173 " port: %s.\n", hub, port->port_number, 174 str_error(opResult)); 175 175 } 176 176 } else { 177 /* Handle the case we were in reset */ 178 // FIXME: usb_hub_port_reset_fail(port); 177 179 /* If enabled change was reported leave the removal 178 180 * to that handler, it shall ACK the change too. */ … … 185 187 /* Enable change, ports are automatically disabled on errors. */ 186 188 if (status & USB_HUB_PORT_C_STATUS_ENABLED) { 187 usb_log_info("Port %zu, disabled because of errors.\n", 189 // TODO: maybe HS reset failed? 190 usb_log_info("(%p-%u): Port disabled because of errors.\n", hub, 188 191 port->port_number); 189 192 usb_hub_port_device_gone(port, hub); … … 191 194 USB_HUB_FEATURE_C_PORT_ENABLE); 192 195 if (rc != EOK) { 193 usb_log_error( 194 " Failed to clear port %zu enable change feature: "195 "%s.\n", port->port_number,str_error(rc));196 usb_log_error("(%p-%u): Failed to clear port enable " 197 "change feature: %s.", hub, port->port_number, 198 str_error(rc)); 196 199 } 197 200 … … 200 203 /* Suspend change */ 201 204 if (status & USB_HUB_PORT_C_STATUS_SUSPEND) { 202 usb_log_error(" Port %zuwent to suspend state, this should"203 " NOT happen as we do not support suspend state!",205 usb_log_error("(%p-%u): Port went to suspend state, this should" 206 " NOT happen as we do not support suspend state!", hub, 204 207 port->port_number); 205 208 const int rc = usb_hub_port_clear_feature(port, 206 209 USB_HUB_FEATURE_C_PORT_SUSPEND); 207 210 if (rc != EOK) { 208 usb_log_error( 209 " Failed to clear port %zu suspend change feature: "210 "%s.\n", port->port_number,str_error(rc));211 usb_log_error("(%p-%u): Failed to clear port suspend " 212 "change feature: %s.", hub, port->port_number, 213 str_error(rc)); 211 214 } 212 215 } … … 214 217 /* Over current */ 215 218 if (status & USB_HUB_PORT_C_STATUS_OC) { 219 usb_log_debug("(%p-%u): Port OC reported!.", hub, 220 port->port_number); 216 221 /* According to the USB specs: 217 222 * 11.13.5 Over-current Reporting and Recovery … … 222 227 USB_HUB_FEATURE_C_PORT_OVER_CURRENT); 223 228 if (rc != EOK) { 224 usb_log_error( 225 " Failed to clear port %zu OC change feature: %s.\n",226 port->port_number,str_error(rc));229 usb_log_error("(%p-%u): Failed to clear port OC change " 230 "feature: %s.\n", hub, port->port_number, 231 str_error(rc)); 227 232 } 228 233 if (!(status & ~USB_HUB_PORT_STATUS_OC)) { … … 230 235 port, USB_HUB_FEATURE_PORT_POWER); 231 236 if (rc != EOK) { 232 usb_log_error( 233 " Failed to set port %zu power after OC:"234 " %s.\n",port->port_number, str_error(rc));237 usb_log_error("(%p-%u): Failed to set port " 238 "power after OC: %s.", hub, 239 port->port_number, str_error(rc)); 235 240 } 236 241 } … … 239 244 /* Port reset, set on port reset complete. */ 240 245 if (status & USB_HUB_PORT_C_STATUS_RESET) { 241 usb_hub_port_reset_completed(port, status);242 } 243 244 usb_log_debug ("Port %zu status 0x%08" PRIx32 "\n",246 usb_hub_port_reset_completed(port, hub, status); 247 } 248 249 usb_log_debug2("(%p-%u): Port status %#08" PRIx32, hub, 245 250 port->port_number, status); 246 251 } … … 259 264 assert(port); 260 265 assert(hub); 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; 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 300 275 } 301 276 … … 308 283 * @param status Port status mask 309 284 */ 310 void usb_hub_port_reset_completed(usb_hub_port_t *port, 285 void usb_hub_port_reset_completed(usb_hub_port_t *port, usb_hub_dev_t *hub, 311 286 usb_port_status_t status) 312 287 { 313 288 assert(port); 314 289 fibril_mutex_lock(&port->mutex); 290 const bool enabled = (status & USB_HUB_PORT_STATUS_ENABLED) != 0; 315 291 /* Finalize device adding. */ 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);292 293 if (enabled) { 294 port->reset_status = RESET_OK; 295 usb_log_debug("(%p-%u): Port reset complete.\n", hub, 296 port->port_number); 321 297 } else { 322 usb_log_warning(323 "Port %zu reset complete but port not enabled.\n",324 port->port_number);298 port->reset_status = RESET_FAIL; 299 usb_log_warning("(%p-%u): Port reset complete but port not " 300 "enabled.", hub, port->port_number); 325 301 } 326 302 fibril_condvar_broadcast(&port->reset_cv); … … 330 306 int rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET); 331 307 if (rc != EOK) { 332 usb_log_error( 333 "Failed to clear port %zu reset change feature: %s.\n", 334 port->port_number, str_error(rc)); 308 usb_log_error("(%p-%u): Failed to clear port reset change: %s.", 309 hub, port->port_number, str_error(rc)); 335 310 } 336 311 } … … 376 351 } 377 352 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));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); 395 370 return rc; 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; 371 } else { 372 return usb_hub_port_clear_feature(port, 373 USB_HUB_FEATURE_PORT_ENABLE); 374 } 408 375 } 409 376 … … 418 385 int add_device_phase1_worker_fibril(void *arg) 419 386 { 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 const int rc = usb_hc_new_device_wrapper(data->hub->usb_device->ddf_dev, 427 &data->hub->usb_device->hc_conn, data->speed, enable_port_callback, 428 data->port, &new_address, NULL, NULL, &child_fun); 429 430 if (rc == EOK) { 431 fibril_mutex_lock(&data->port->mutex); 432 data->port->attached_device.fun = child_fun; 433 data->port->attached_device.address = new_address; 434 fibril_mutex_unlock(&data->port->mutex); 435 436 usb_log_info("Detected new device on `%s' (port %zu), " 437 "address %d (handle %" PRIun ").\n", 438 ddf_dev_get_name(data->hub->usb_device->ddf_dev), 439 data->port->port_number, new_address, 440 ddf_fun_get_handle(child_fun)); 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; 394 free(arg); 395 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 } 441 448 } else { 442 usb_log_error("Failed registering device on port %zu: %s.\n", 443 data->port->port_number, str_error(rc)); 444 } 445 446 447 fibril_mutex_lock(&data->hub->pending_ops_mutex); 448 assert(data->hub->pending_ops_count > 0); 449 --data->hub->pending_ops_count; 450 fibril_condvar_signal(&data->hub->pending_ops_cv); 451 fibril_mutex_unlock(&data->hub->pending_ops_mutex); 452 453 free(arg); 454 455 return rc; 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; 456 466 } 457 467 … … 479 489 data->speed = speed; 480 490 481 fibril_mutex_lock(&port->mutex);482 port->reset_completed = false;483 fibril_mutex_unlock(&port->mutex);484 485 491 fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data); 486 492 if (fibril == 0) {
Note:
See TracChangeset
for help on using the changeset viewer.