Changes in uspace/drv/bus/usb/usbhub/port.c [ffa96c2:8351f9a4] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/port.c
rffa96c2 r8351f9a4 41 41 42 42 #include <usb/debug.h> 43 #include <usb/dev/hub.h>44 43 45 44 #include "port.h" … … 56 55 static int usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub); 57 56 static void usb_hub_port_reset_completed(usb_hub_port_t *port, 58 usb_ port_status_t status);57 usb_hub_dev_t *hub, usb_port_status_t status); 59 58 static int get_port_status(usb_hub_port_t *port, usb_port_status_t *status); 60 static int enable_port_callback(void *arg);61 59 static int add_device_phase1_worker_fibril(void *arg); 62 60 static int create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub, … … 66 64 { 67 65 assert(port); 68 if (port-> attached_device.fun)66 if (port->device_attached) 69 67 return usb_hub_port_device_gone(port, hub); 70 68 return EOK; … … 124 122 assert(port); 125 123 fibril_mutex_lock(&port->mutex); 126 port->reset_completed = true;127 port->reset_okay = false;124 if (port->reset_status == IN_RESET) 125 port->reset_status = RESET_FAIL; 128 126 fibril_condvar_broadcast(&port->reset_cv); 129 127 fibril_mutex_unlock(&port->mutex); … … 141 139 assert(port); 142 140 assert(hub); 143 usb_log_debug ("Interrupt at port %zu\n", port->port_number);141 usb_log_debug2("(%p-%u): Interrupt.\n", hub, port->port_number); 144 142 145 143 usb_port_status_t status = 0; 146 144 const int opResult = get_port_status(port, &status); 147 145 if (opResult != EOK) { 148 usb_log_error(" Failed to get port %zu status: %s.\n",146 usb_log_error("(%p-%u): Failed to get port status: %s.\n", hub, 149 147 port->port_number, str_error(opResult)); 150 148 return; … … 155 153 const bool connected = 156 154 (status & USB_HUB_PORT_STATUS_CONNECTION) != 0; 157 usb_log_debug(" Connection change on port %zu: device %s.\n",155 usb_log_debug("(%p-%u): Connection change: device %s.\n", hub, 158 156 port->port_number, connected ? "attached" : "removed"); 159 157 … … 162 160 USB_HUB_FEATURE_C_PORT_CONNECTION); 163 161 if (opResult != EOK) { 164 usb_log_warning("Failed to clear port-change-connection" 165 " flag: %s.\n", str_error(opResult)); 162 usb_log_warning("(%p-%u): Failed to clear " 163 "port-change-connection flag: %s.\n", hub, 164 port->port_number, str_error(opResult)); 166 165 } 167 166 … … 170 169 usb_port_speed(status)); 171 170 if (opResult != EOK) { 172 usb_log_error( 173 "Cannot handle change on port %zu: %s.\n",174 port->port_number,str_error(opResult));171 usb_log_error("(%p-%u): Cannot handle change on" 172 " port: %s.\n", hub, port->port_number, 173 str_error(opResult)); 175 174 } 176 175 } else { 176 /* Handle the case we were in reset */ 177 //usb_hub_port_reset_fail(port); 177 178 /* If enabled change was reported leave the removal 178 179 * to that handler, it shall ACK the change too. */ … … 185 186 /* Enable change, ports are automatically disabled on errors. */ 186 187 if (status & USB_HUB_PORT_C_STATUS_ENABLED) { 187 usb_log_info("Port %zu, disabled because of errors.\n", 188 //TODO: maybe HS reset failed? 189 usb_log_info("(%p-%u): Port disabled because of errors.\n", hub, 188 190 port->port_number); 189 191 usb_hub_port_device_gone(port, hub); … … 191 193 USB_HUB_FEATURE_C_PORT_ENABLE); 192 194 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));195 usb_log_error("(%p-%u): Failed to clear port enable " 196 "change feature: %s.", hub, port->port_number, 197 str_error(rc)); 196 198 } 197 199 … … 200 202 /* Suspend change */ 201 203 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!",204 usb_log_error("(%p-%u): Port went to suspend state, this should" 205 " NOT happen as we do not support suspend state!", hub, 204 206 port->port_number); 205 207 const int rc = usb_hub_port_clear_feature(port, 206 208 USB_HUB_FEATURE_C_PORT_SUSPEND); 207 209 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));210 usb_log_error("(%p-%u): Failed to clear port suspend " 211 "change feature: %s.", hub, port->port_number, 212 str_error(rc)); 211 213 } 212 214 } … … 214 216 /* Over current */ 215 217 if (status & USB_HUB_PORT_C_STATUS_OC) { 218 usb_log_debug("(%p-%u): Port OC reported!.", hub, 219 port->port_number); 216 220 /* According to the USB specs: 217 221 * 11.13.5 Over-current Reporting and Recovery … … 222 226 USB_HUB_FEATURE_C_PORT_OVER_CURRENT); 223 227 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));228 usb_log_error("(%p-%u): Failed to clear port OC change " 229 "feature: %s.\n", hub, port->port_number, 230 str_error(rc)); 227 231 } 228 232 if (!(status & ~USB_HUB_PORT_STATUS_OC)) { … … 230 234 port, USB_HUB_FEATURE_PORT_POWER); 231 235 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));236 usb_log_error("(%p-%u): Failed to set port " 237 "power after OC: %s.", hub, 238 port->port_number, str_error(rc)); 235 239 } 236 240 } … … 239 243 /* Port reset, set on port reset complete. */ 240 244 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",245 usb_hub_port_reset_completed(port, hub, status); 246 } 247 248 usb_log_debug2("(%p-%u): Port status %#08" PRIx32, hub, 245 249 port->port_number, status); 246 250 } … … 259 263 assert(port); 260 264 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; 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 300 274 } 301 275 … … 308 282 * @param status Port status mask 309 283 */ 310 void usb_hub_port_reset_completed(usb_hub_port_t *port, 284 void usb_hub_port_reset_completed(usb_hub_port_t *port, usb_hub_dev_t *hub, 311 285 usb_port_status_t status) 312 286 { 313 287 assert(port); 314 288 fibril_mutex_lock(&port->mutex); 289 const bool enabled = (status & USB_HUB_PORT_STATUS_ENABLED) != 0; 315 290 /* 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);291 292 if (enabled) { 293 port->reset_status = RESET_OK; 294 usb_log_debug("(%p-%u): Port reset complete.\n", hub, 295 port->port_number); 321 296 } else { 322 usb_log_warning(323 "Port %zu reset complete but port not enabled.\n",324 port->port_number);297 port->reset_status = RESET_FAIL; 298 usb_log_warning("(%p-%u): Port reset complete but port not " 299 "enabled.", hub, port->port_number); 325 300 } 326 301 fibril_condvar_broadcast(&port->reset_cv); … … 330 305 int rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET); 331 306 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)); 307 usb_log_error("(%p-%u): Failed to clear port reset change: %s.", 308 hub, port->port_number, str_error(rc)); 335 309 } 336 310 } … … 376 350 } 377 351 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));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); 395 369 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; 370 } else { 371 return usb_hub_port_clear_feature(port, 372 USB_HUB_FEATURE_PORT_ENABLE); 373 } 408 374 } 409 375 … … 418 384 int add_device_phase1_worker_fibril(void *arg) 419 385 { 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)); 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; 393 free(arg); 394 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 } 446 447 } 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 459 free(arg); 460 461 return rc; 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; 462 465 } 463 466 … … 485 488 data->speed = speed; 486 489 487 fibril_mutex_lock(&port->mutex);488 port->reset_completed = false;489 fibril_mutex_unlock(&port->mutex);490 491 490 fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data); 492 491 if (fibril == 0) {
Note:
See TracChangeset
for help on using the changeset viewer.