Changes in uspace/drv/bus/usb/usbhub/port.c [aa148b3:b7fd2a0] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/port.c
raa148b3 rb7fd2a0 40 40 #include <inttypes.h> 41 41 #include <fibril_synch.h> 42 #include <usbhc_iface.h>43 42 44 43 #include <usb/debug.h> … … 48 47 #include "status.h" 49 48 50 #define port_log(lvl, port, fmt, ...) do { usb_log_##lvl("(%p-%u): " fmt, (port->hub), (port->port_number), ##__VA_ARGS__); } while (0) 51 52 /** Initialize hub port information. 53 * 54 * @param port Port to be initialized. 55 */ 56 void usb_hub_port_init(usb_hub_port_t *port, usb_hub_dev_t *hub, unsigned int port_number) 57 { 58 assert(port); 59 memset(port, 0, sizeof(*port)); 60 port->hub = hub; 61 port->port_number = port_number; 62 usb_port_init(&port->base); 63 } 64 65 static inline usb_hub_port_t *get_hub_port(usb_port_t *port) 66 { 67 assert(port); 68 return (usb_hub_port_t *) port; 69 } 70 71 /** 72 * Inform the HC that the device on port is gone. 73 */ 74 static void remove_device(usb_port_t *port_base) 75 { 76 usb_hub_port_t *port = get_hub_port(port_base); 77 78 async_exch_t *exch = usb_device_bus_exchange_begin(port->hub->usb_device); 79 if (!exch) { 80 port_log(error, port, "Cannot remove the device, failed creating exchange."); 81 return; 82 } 83 84 const errno_t err = usbhc_device_remove(exch, port->port_number); 85 if (err) 86 port_log(error, port, "Failed to remove device: %s", str_error(err)); 87 88 usb_device_bus_exchange_end(exch); 89 } 90 91 92 static usb_speed_t get_port_speed(usb_hub_port_t *port, uint32_t status) 93 { 94 assert(port); 95 assert(port->hub); 96 97 return usb_port_speed(port->hub->speed, status); 98 } 99 100 /** 101 * Routine for adding a new device in USB2. 102 */ 103 static errno_t enumerate_device_usb2(usb_hub_port_t *port, async_exch_t *exch) 104 { 105 errno_t err; 106 107 port_log(debug, port, "Requesting default address."); 108 err = usb_hub_reserve_default_address(port->hub, exch, &port->base); 109 if (err != EOK) { 110 port_log(error, port, "Failed to reserve default address: %s", str_error(err)); 111 return err; 112 } 113 114 /* Reservation of default address could have blocked */ 115 if (port->base.state != PORT_CONNECTING) 116 goto out_address; 117 118 port_log(debug, port, "Resetting port."); 119 if ((err = usb_hub_set_port_feature(port->hub, port->port_number, USB_HUB_FEATURE_PORT_RESET))) { 120 port_log(warning, port, "Port reset request failed: %s", str_error(err)); 121 goto out_address; 122 } 123 124 if ((err = usb_port_wait_for_enabled(&port->base))) { 125 port_log(error, port, "Failed to reset port: %s", str_error(err)); 126 goto out_address; 127 } 128 129 port_log(debug, port, "Enumerating device."); 130 if ((err = usbhc_device_enumerate(exch, port->port_number, port->speed))) { 131 port_log(error, port, "Failed to enumerate device: %s", str_error(err)); 132 /* Disable the port */ 133 usb_hub_clear_port_feature(port->hub, port->port_number, USB2_HUB_FEATURE_PORT_ENABLE); 134 goto out_address; 135 } 136 137 port_log(debug, port, "Device enumerated"); 138 139 out_address: 140 usb_hub_release_default_address(port->hub, exch); 141 return err; 142 } 143 144 /** 145 * Routine for adding a new device in USB 3. 146 */ 147 static errno_t enumerate_device_usb3(usb_hub_port_t *port, async_exch_t *exch) 148 { 149 errno_t err; 150 151 port_log(debug, port, "Issuing a warm reset."); 152 if ((err = usb_hub_set_port_feature(port->hub, port->port_number, USB3_HUB_FEATURE_BH_PORT_RESET))) { 153 port_log(warning, port, "Port reset request failed: %s", str_error(err)); 154 return err; 155 } 156 157 if ((err = usb_port_wait_for_enabled(&port->base))) { 158 port_log(error, port, "Failed to reset port: %s", str_error(err)); 159 return err; 160 } 161 162 port_log(debug, port, "Enumerating device."); 163 if ((err = usbhc_device_enumerate(exch, port->port_number, port->speed))) { 164 port_log(error, port, "Failed to enumerate device: %s", str_error(err)); 165 return err; 166 } 167 168 port_log(debug, port, "Device enumerated"); 49 /** Information for fibril for device discovery. */ 50 struct add_device_phase1 { 51 usb_hub_dev_t *hub; 52 usb_hub_port_t *port; 53 usb_speed_t speed; 54 }; 55 56 static errno_t usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub); 57 static void usb_hub_port_reset_completed(usb_hub_port_t *port, 58 usb_hub_dev_t *hub, usb_port_status_t status); 59 static errno_t get_port_status(usb_hub_port_t *port, usb_port_status_t *status); 60 static errno_t add_device_phase1_worker_fibril(void *arg); 61 static errno_t create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub, 62 usb_speed_t speed); 63 64 errno_t usb_hub_port_fini(usb_hub_port_t *port, usb_hub_dev_t *hub) 65 { 66 assert(port); 67 if (port->device_attached) 68 return usb_hub_port_device_gone(port, hub); 169 69 return EOK; 170 70 } 171 71 172 static errno_t enumerate_device(usb_port_t *port_base) 173 { 174 usb_hub_port_t *port = get_hub_port(port_base); 175 176 port_log(debug, port, "Setting up new device."); 177 async_exch_t *exch = usb_device_bus_exchange_begin(port->hub->usb_device); 178 if (!exch) { 179 port_log(error, port, "Failed to create exchange."); 180 return ENOMEM; 181 } 182 183 const errno_t err = port->hub->speed == USB_SPEED_SUPER 184 ? enumerate_device_usb3(port, exch) 185 : enumerate_device_usb2(port, exch); 186 187 usb_device_bus_exchange_end(exch); 188 return err; 189 } 190 191 static void port_changed_connection(usb_hub_port_t *port, usb_port_status_t status) 192 { 193 const bool connected = !!(status & USB_HUB_PORT_STATUS_CONNECTION); 194 port_log(debug, port, "Connection change: device %s.", connected ? "attached" : "removed"); 195 196 if (connected) { 197 usb_port_connected(&port->base, &enumerate_device); 198 } else { 199 usb_port_disabled(&port->base, &remove_device); 200 } 201 } 202 203 static void port_changed_enabled(usb_hub_port_t *port, usb_port_status_t status) 204 { 205 const bool enabled = !!(status & USB_HUB_PORT_STATUS_ENABLE); 206 if (enabled) { 207 port_log(warning, port, "Port unexpectedly changed to enabled."); 208 } else { 209 usb_port_disabled(&port->base, &remove_device); 210 } 211 } 212 213 static void port_changed_overcurrent(usb_hub_port_t *port, usb_port_status_t status) 214 { 215 const bool overcurrent = !!(status & USB_HUB_PORT_STATUS_OC); 216 217 /* According to the USB specs: 218 * 11.13.5 Over-current Reporting and Recovery 219 * Hub device is responsible for putting port in power off 220 * mode. USB system software is responsible for powering port 221 * back on when the over-current condition is gone */ 222 223 usb_port_disabled(&port->base, &remove_device); 224 225 if (!overcurrent) { 226 const errno_t err = usb_hub_set_port_feature(port->hub, port->port_number, USB_HUB_FEATURE_PORT_POWER); 227 if (err) 228 port_log(error, port, "Failed to set port power after OC: %s.", str_error(err)); 229 } 230 } 231 232 static void port_changed_reset(usb_hub_port_t *port, usb_port_status_t status) 233 { 234 const bool enabled = !!(status & USB_HUB_PORT_STATUS_ENABLE); 235 236 if (enabled) { 237 port->speed = get_port_speed(port, status); 238 usb_port_enabled(&port->base); 239 } else 240 usb_port_disabled(&port->base, &remove_device); 241 } 242 243 typedef void (*change_handler_t)(usb_hub_port_t *, usb_port_status_t); 244 245 static void check_port_change(usb_hub_port_t *port, usb_port_status_t *status, 246 change_handler_t handler, usb_port_status_t mask, usb_hub_class_feature_t feature) 247 { 248 if ((*status & mask) == 0) 249 return; 250 251 /* Clear the change so it won't come again */ 252 usb_hub_clear_port_feature(port->hub, port->port_number, feature); 253 254 if (handler) 255 handler(port, *status); 256 257 /* Mark the change as resolved */ 258 *status &= ~mask; 72 /** 73 * Clear feature on hub port. 74 * 75 * @param port Port structure. 76 * @param feature Feature selector. 77 * @return Operation result 78 */ 79 errno_t usb_hub_port_clear_feature( 80 usb_hub_port_t *port, usb_hub_class_feature_t feature) 81 { 82 assert(port); 83 const usb_device_request_setup_packet_t clear_request = { 84 .request_type = USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE, 85 .request = USB_DEVREQ_CLEAR_FEATURE, 86 .value = feature, 87 .index = port->port_number, 88 .length = 0, 89 }; 90 return usb_pipe_control_write(port->control_pipe, &clear_request, 91 sizeof(clear_request), NULL, 0); 92 } 93 94 /** 95 * Set feature on hub port. 96 * 97 * @param port Port structure. 98 * @param feature Feature selector. 99 * @return Operation result 100 */ 101 errno_t usb_hub_port_set_feature( 102 usb_hub_port_t *port, usb_hub_class_feature_t feature) 103 { 104 assert(port); 105 const usb_device_request_setup_packet_t clear_request = { 106 .request_type = USB_HUB_REQ_TYPE_SET_PORT_FEATURE, 107 .request = USB_DEVREQ_SET_FEATURE, 108 .index = port->port_number, 109 .value = feature, 110 .length = 0, 111 }; 112 return usb_pipe_control_write(port->control_pipe, &clear_request, 113 sizeof(clear_request), NULL, 0); 114 } 115 116 /** 117 * Mark reset process as failed due to external reasons 118 * 119 * @param port Port structure 120 */ 121 void usb_hub_port_reset_fail(usb_hub_port_t *port) 122 { 123 assert(port); 124 fibril_mutex_lock(&port->mutex); 125 if (port->reset_status == IN_RESET) 126 port->reset_status = RESET_FAIL; 127 fibril_condvar_broadcast(&port->reset_cv); 128 fibril_mutex_unlock(&port->mutex); 259 129 } 260 130 … … 266 136 * @param hub hub representation 267 137 */ 268 void usb_hub_port_process_interrupt(usb_hub_port_t *port) 269 { 270 assert(port); 271 port_log(debug2, port, "Interrupt."); 138 void usb_hub_port_process_interrupt(usb_hub_port_t *port, usb_hub_dev_t *hub) 139 { 140 assert(port); 141 assert(hub); 142 usb_log_debug2("(%p-%u): Interrupt.\n", hub, port->port_number); 272 143 273 144 usb_port_status_t status = 0; 274 const errno_t err = usb_hub_get_port_status(port->hub, port->port_number, &status); 275 if (err != EOK) { 276 port_log(error, port, "Failed to get port status: %s.", str_error(err)); 145 const errno_t opResult = get_port_status(port, &status); 146 if (opResult != EOK) { 147 usb_log_error("(%p-%u): Failed to get port status: %s.\n", hub, 148 port->port_number, str_error(opResult)); 277 149 return; 278 150 } 279 151 280 check_port_change(port, &status, &port_changed_connection, 281 USB_HUB_PORT_STATUS_C_CONNECTION, USB_HUB_FEATURE_C_PORT_CONNECTION); 282 283 check_port_change(port, &status, &port_changed_overcurrent, 284 USB_HUB_PORT_STATUS_C_OC, USB_HUB_FEATURE_C_PORT_OVER_CURRENT); 285 286 check_port_change(port, &status, &port_changed_reset, 287 USB_HUB_PORT_STATUS_C_RESET, USB_HUB_FEATURE_C_PORT_RESET); 288 289 if (port->hub->speed <= USB_SPEED_HIGH) { 290 check_port_change(port, &status, &port_changed_enabled, 291 USB2_HUB_PORT_STATUS_C_ENABLE, USB2_HUB_FEATURE_C_PORT_ENABLE); 152 /* Connection change */ 153 if (status & USB_HUB_PORT_C_STATUS_CONNECTION) { 154 const bool connected = 155 (status & USB_HUB_PORT_STATUS_CONNECTION) != 0; 156 usb_log_debug("(%p-%u): Connection change: device %s.\n", hub, 157 port->port_number, connected ? "attached" : "removed"); 158 159 /* ACK the change */ 160 const errno_t opResult = usb_hub_port_clear_feature(port, 161 USB_HUB_FEATURE_C_PORT_CONNECTION); 162 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)); 166 } 167 168 if (connected) { 169 const errno_t opResult = create_add_device_fibril(port, hub, 170 usb_port_speed(status)); 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)); 175 } 176 } else { 177 /* Handle the case we were in reset */ 178 // FIXME: usb_hub_port_reset_fail(port); 179 /* If enabled change was reported leave the removal 180 * to that handler, it shall ACK the change too. */ 181 if (!(status & USB_HUB_PORT_C_STATUS_ENABLED)) { 182 usb_hub_port_device_gone(port, hub); 183 } 184 } 185 } 186 187 /* Enable change, ports are automatically disabled on errors. */ 188 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, 191 port->port_number); 192 usb_hub_port_device_gone(port, hub); 193 const errno_t rc = usb_hub_port_clear_feature(port, 194 USB_HUB_FEATURE_C_PORT_ENABLE); 195 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)); 199 } 200 201 } 202 203 /* Suspend change */ 204 if (status & USB_HUB_PORT_C_STATUS_SUSPEND) { 205 usb_log_error("(%p-%u): Port went to suspend state, this should" 206 " NOT happen as we do not support suspend state!", hub, 207 port->port_number); 208 const errno_t rc = usb_hub_port_clear_feature(port, 209 USB_HUB_FEATURE_C_PORT_SUSPEND); 210 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)); 214 } 215 } 216 217 /* Over current */ 218 if (status & USB_HUB_PORT_C_STATUS_OC) { 219 usb_log_debug("(%p-%u): Port OC reported!.", hub, 220 port->port_number); 221 /* According to the USB specs: 222 * 11.13.5 Over-current Reporting and Recovery 223 * Hub device is responsible for putting port in power off 224 * mode. USB system software is responsible for powering port 225 * back on when the over-current condition is gone */ 226 const errno_t rc = usb_hub_port_clear_feature(port, 227 USB_HUB_FEATURE_C_PORT_OVER_CURRENT); 228 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)); 232 } 233 if (!(status & ~USB_HUB_PORT_STATUS_OC)) { 234 const errno_t rc = usb_hub_port_set_feature( 235 port, USB_HUB_FEATURE_PORT_POWER); 236 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)); 240 } 241 } 242 } 243 244 /* Port reset, set on port reset complete. */ 245 if (status & USB_HUB_PORT_C_STATUS_RESET) { 246 usb_hub_port_reset_completed(port, hub, status); 247 } 248 249 usb_log_debug2("(%p-%u): Port status %#08" PRIx32, hub, 250 port->port_number, status); 251 } 252 253 /** 254 * routine called when a device on port has been removed 255 * 256 * If the device on port had default address, it releases default address. 257 * Otherwise does not do anything, because DDF does not allow to remove device 258 * from it`s device tree. 259 * @param port port structure 260 * @param hub hub representation 261 */ 262 errno_t usb_hub_port_device_gone(usb_hub_port_t *port, usb_hub_dev_t *hub) 263 { 264 assert(port); 265 assert(hub); 266 async_exch_t *exch = usb_device_bus_exchange_begin(hub->usb_device); 267 if (!exch) 268 return ENOMEM; 269 const errno_t 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 275 } 276 277 /** 278 * Process port reset change 279 * 280 * After this change port should be enabled, unless some problem occurred. 281 * This functions triggers second phase of enabling new device. 282 * @param port Port structure 283 * @param status Port status mask 284 */ 285 void usb_hub_port_reset_completed(usb_hub_port_t *port, usb_hub_dev_t *hub, 286 usb_port_status_t status) 287 { 288 assert(port); 289 fibril_mutex_lock(&port->mutex); 290 const bool enabled = (status & USB_HUB_PORT_STATUS_ENABLED) != 0; 291 /* Finalize device adding. */ 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); 292 297 } else { 293 check_port_change(port, &status, &port_changed_reset, 294 USB3_HUB_PORT_STATUS_C_BH_RESET, USB3_HUB_FEATURE_C_BH_PORT_RESET); 295 296 check_port_change(port, &status, NULL, 297 USB3_HUB_PORT_STATUS_C_LINK_STATE, USB3_HUB_FEATURE_C_PORT_LINK_STATE); 298 } 299 300 /* Check for changes we ignored */ 301 if (status & 0xffff0000) { 302 port_log(debug, port, "Port status change igored. Status: %#08" PRIx32, status); 303 } 304 } 305 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 } 302 fibril_condvar_broadcast(&port->reset_cv); 303 fibril_mutex_unlock(&port->mutex); 304 305 /* Clear the port reset change. */ 306 errno_t rc = usb_hub_port_clear_feature(port, USB_HUB_FEATURE_C_PORT_RESET); 307 if (rc != EOK) { 308 usb_log_error("(%p-%u): Failed to clear port reset change: %s.", 309 hub, port->port_number, str_error(rc)); 310 } 311 } 312 313 /** Retrieve port status. 314 * 315 * @param[in] port Port structure 316 * @param[out] status Where to store the port status. 317 * @return Error code. 318 */ 319 static errno_t get_port_status(usb_hub_port_t *port, usb_port_status_t *status) 320 { 321 assert(port); 322 /* USB hub specific GET_PORT_STATUS request. See USB Spec 11.16.2.6 323 * Generic GET_STATUS request cannot be used because of the difference 324 * in status data size (2B vs. 4B)*/ 325 const usb_device_request_setup_packet_t request = { 326 .request_type = USB_HUB_REQ_TYPE_GET_PORT_STATUS, 327 .request = USB_HUB_REQUEST_GET_STATUS, 328 .value = 0, 329 .index = uint16_host2usb(port->port_number), 330 .length = sizeof(usb_port_status_t), 331 }; 332 size_t recv_size; 333 usb_port_status_t status_tmp; 334 335 const errno_t rc = usb_pipe_control_read(port->control_pipe, 336 &request, sizeof(usb_device_request_setup_packet_t), 337 &status_tmp, sizeof(status_tmp), &recv_size); 338 if (rc != EOK) { 339 return rc; 340 } 341 342 if (recv_size != sizeof (status_tmp)) { 343 return ELIMIT; 344 } 345 346 if (status != NULL) { 347 *status = status_tmp; 348 } 349 350 return EOK; 351 } 352 353 static errno_t port_enable(usb_hub_port_t *port, usb_hub_dev_t *hub, bool enable) 354 { 355 if (enable) { 356 errno_t 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); 370 return rc; 371 } else { 372 return usb_hub_port_clear_feature(port, 373 USB_HUB_FEATURE_PORT_ENABLE); 374 } 375 } 376 377 /** Fibril for adding a new device. 378 * 379 * Separate fibril is needed because the port reset completion is announced 380 * via interrupt pipe and thus we cannot block here. 381 * 382 * @param arg Pointer to struct add_device_phase1. 383 * @return 0 Always. 384 */ 385 errno_t add_device_phase1_worker_fibril(void *arg) 386 { 387 struct add_device_phase1 *params = arg; 388 assert(params); 389 390 errno_t 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 errno_t 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 errno_t 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; 466 } 467 468 /** Start device adding when connection change is detected. 469 * 470 * This fires a new fibril to complete the device addition. 471 * 472 * @param hub Hub where the change occured. 473 * @param port Port index (starting at 1). 474 * @param speed Speed of the device. 475 * @return Error code. 476 */ 477 static errno_t create_add_device_fibril(usb_hub_port_t *port, usb_hub_dev_t *hub, 478 usb_speed_t speed) 479 { 480 assert(hub); 481 assert(port); 482 struct add_device_phase1 *data 483 = malloc(sizeof(struct add_device_phase1)); 484 if (data == NULL) { 485 return ENOMEM; 486 } 487 data->hub = hub; 488 data->port = port; 489 data->speed = speed; 490 491 fid_t fibril = fibril_create(add_device_phase1_worker_fibril, data); 492 if (fibril == 0) { 493 free(data); 494 return ENOMEM; 495 } 496 fibril_mutex_lock(&hub->pending_ops_mutex); 497 ++hub->pending_ops_count; 498 fibril_mutex_unlock(&hub->pending_ops_mutex); 499 fibril_add_ready(fibril); 500 501 return EOK; 502 } 306 503 307 504 /**
Note:
See TracChangeset
for help on using the changeset viewer.