Changes in uspace/drv/usbhub/usbhub.c [c50941f:f35b294] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/usbhub/usbhub.c
rc50941f rf35b294 37 37 #include <errno.h> 38 38 #include <str_error.h> 39 #include <inttypes.h> 39 40 40 41 #include <usb_iface.h> … … 53 54 #include "usb/classes/classes.h" 54 55 55 static int usb_hub_trigger_connecting_non_removable_devices( 56 usb_hub_info_t * hub, usb_hub_descriptor_t * descriptor); 57 56 57 static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev); 58 59 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info); 60 61 static int usb_hub_set_configuration(usb_hub_info_t * hub_info); 62 63 static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info); 64 65 static int usb_process_hub_over_current(usb_hub_info_t * hub_info, 66 usb_hub_status_t status); 67 68 static int usb_process_hub_power_change(usb_hub_info_t * hub_info, 69 usb_hub_status_t status); 70 71 static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info); 72 73 74 /// \TODO malloc checking 58 75 59 76 //********************************************* 60 77 // 61 78 // hub driver code, initialization 79 // 80 //********************************************* 81 82 /** 83 * Initialize hub device driver fibril 84 * 85 * Creates hub representation and fibril that periodically checks hub`s status. 86 * Hub representation is passed to the fibril. 87 * @param usb_dev generic usb device information 88 * @return error code 89 */ 90 int usb_hub_add_device(usb_device_t * usb_dev) { 91 if (!usb_dev) return EINVAL; 92 usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev); 93 //create hc connection 94 usb_log_debug("Initializing USB wire abstraction.\n"); 95 int opResult = usb_hc_connection_initialize_from_device( 96 &hub_info->connection, 97 hub_info->usb_device->ddf_dev); 98 if (opResult != EOK) { 99 usb_log_error("could not initialize connection to device, " 100 "errno %d\n", 101 opResult); 102 free(hub_info); 103 return opResult; 104 } 105 106 usb_pipe_start_session(hub_info->control_pipe); 107 //set hub configuration 108 opResult = usb_hub_set_configuration(hub_info); 109 if (opResult != EOK) { 110 usb_log_error("could not set hub configuration, errno %d\n", 111 opResult); 112 free(hub_info); 113 return opResult; 114 } 115 //get port count and create attached_devs 116 opResult = usb_hub_process_hub_specific_info(hub_info); 117 if (opResult != EOK) { 118 usb_log_error("could process hub specific info, errno %d\n", 119 opResult); 120 free(hub_info); 121 return opResult; 122 } 123 usb_pipe_end_session(hub_info->control_pipe); 124 125 /// \TODO what is this? 126 usb_log_debug("Creating `hub' function.\n"); 127 ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev, 128 fun_exposed, "hub"); 129 assert(hub_fun != NULL); 130 hub_fun->ops = NULL; 131 132 opResult = ddf_fun_bind(hub_fun); 133 assert(opResult == EOK); 134 opResult = ddf_fun_add_to_class(hub_fun, "hub"); 135 assert(opResult == EOK); 136 137 opResult = usb_hub_start_hub_fibril(hub_info); 138 if(opResult!=EOK) 139 free(hub_info); 140 return opResult; 141 } 142 143 144 /** Callback for polling hub for changes. 145 * 146 * @param dev Device where the change occured. 147 * @param change_bitmap Bitmap of changed ports. 148 * @param change_bitmap_size Size of the bitmap in bytes. 149 * @param arg Custom argument, points to @c usb_hub_info_t. 150 * @return Whether to continue polling. 151 */ 152 bool hub_port_changes_callback(usb_device_t *dev, 153 uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) { 154 usb_hub_info_t *hub = (usb_hub_info_t *) arg; 155 156 /* FIXME: check that we received enough bytes. */ 157 if (change_bitmap_size == 0) { 158 goto leave; 159 } 160 161 bool change; 162 change = ((uint8_t*) change_bitmap)[0] & 1; 163 if (change) { 164 usb_hub_process_global_interrupt(hub); 165 } 166 167 size_t port; 168 for (port = 1; port < hub->port_count + 1; port++) { 169 bool change = (change_bitmap[port / 8] >> (port % 8)) % 2; 170 if (change) { 171 usb_hub_process_interrupt(hub, port); 172 } 173 } 174 leave: 175 /* FIXME: proper interval. */ 176 async_usleep(1000 * 1000 * 10); 177 178 return true; 179 } 180 181 /** 182 * release default address used by given hub 183 * 184 * Also unsets hub->is_default_address_used. Convenience wrapper function. 185 * @note hub->connection MUST be open for communication 186 * @param hub hub representation 187 * @return error code 188 */ 189 int usb_hub_release_default_address(usb_hub_info_t * hub) { 190 int opResult = usb_hc_release_default_address(&hub->connection); 191 if (opResult != EOK) { 192 usb_log_error("could not release default address, errno %d\n", 193 opResult); 194 return opResult; 195 } 196 hub->is_default_address_used = false; 197 return EOK; 198 } 199 200 201 //********************************************* 202 // 203 // support functions 62 204 // 63 205 //********************************************* … … 71 213 */ 72 214 static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev) { 73 usb_hub_info_t * result = usb_new(usb_hub_info_t);74 if (!result) return NULL;215 usb_hub_info_t * result = malloc(sizeof(usb_hub_info_t)); 216 if (!result) return NULL; 75 217 result->usb_device = usb_dev; 76 218 result->status_change_pipe = usb_dev->pipes[0].pipe; … … 90 232 * @return error code 91 233 */ 92 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info) {234 static int usb_hub_process_hub_specific_info(usb_hub_info_t * hub_info) { 93 235 // get hub descriptor 94 236 usb_log_debug("creating serialized descriptor\n"); 95 237 void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE); 96 238 usb_hub_descriptor_t * descriptor; 97 98 /* this was one fix of some bug, should not be needed anymore 99 * these lines allow to reset hub once more, it can be used as 100 * brute-force initialization for non-removable devices 101 int opResult = usb_request_set_configuration(&result->endpoints.control, 1); 102 if(opResult!=EOK){ 103 usb_log_error("could not set default configuration, errno %d",opResult); 104 return opResult; 105 } 106 */ 239 int opResult; 240 107 241 size_t received_size; 108 int opResult = usb_request_get_descriptor(&hub_info->usb_device->ctrl_pipe,109 110 USB_DESCTYPE_HUB,111 0, 0, serialized_descriptor,112 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size); 113 114 if (opResult != EOK) {115 usb_log_error("failed when receiving hub descriptor,badcode = %d\n",116 242 opResult = usb_request_get_descriptor(hub_info->control_pipe, 243 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE, 244 USB_DESCTYPE_HUB, 0, 0, serialized_descriptor, 245 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size); 246 247 if (opResult != EOK) { 248 usb_log_error("failed when receiving hub descriptor, " 249 "badcode = %d\n", 250 opResult); 117 251 free(serialized_descriptor); 118 252 return opResult; … … 120 254 usb_log_debug2("deserializing descriptor\n"); 121 255 descriptor = usb_deserialize_hub_desriptor(serialized_descriptor); 122 if (descriptor==NULL){256 if (descriptor == NULL) { 123 257 usb_log_warning("could not deserialize descriptor \n"); 124 258 return opResult; 125 259 } 126 usb_log_debug("setting port count to %d\n", descriptor->ports_count);260 usb_log_debug("setting port count to %d\n", descriptor->ports_count); 127 261 hub_info->port_count = descriptor->ports_count; 128 hub_info->ports = malloc(sizeof(usb_hub_port_t) * (hub_info->port_count+1)); 262 /// \TODO this is not semantically correct 263 hub_info->ports = malloc( 264 sizeof (usb_hub_port_t) * (hub_info->port_count + 1)); 129 265 size_t port; 130 266 for (port = 0; port < hub_info->port_count + 1; port++) { 131 267 usb_hub_port_init(&hub_info->ports[port]); 132 268 } 133 //handle non-removable devices134 usb_hub_trigger_connecting_non_removable_devices(hub_info, descriptor);135 269 usb_log_debug2("freeing data\n"); 136 270 free(serialized_descriptor); … … 139 273 return EOK; 140 274 } 275 141 276 /** 142 277 * Set configuration of hub … … 147 282 * @return error code 148 283 */ 149 static int usb_hub_set_configuration(usb_hub_info_t * hub_info) {284 static int usb_hub_set_configuration(usb_hub_info_t * hub_info) { 150 285 //device descriptor 151 286 usb_standard_device_descriptor_t *std_descriptor … … 153 288 usb_log_debug("hub has %d configurations\n", 154 289 std_descriptor->configuration_count); 155 if (std_descriptor->configuration_count<1){290 if (std_descriptor->configuration_count < 1) { 156 291 usb_log_error("there are no configurations available\n"); 157 292 return EINVAL; … … 173 308 } 174 309 usb_log_debug("\tused configuration %d\n", 175 310 config_descriptor->configuration_number); 176 311 177 312 return EOK; … … 179 314 180 315 /** 181 * Initialize hub device driver fibril 182 * 183 * Creates hub representation and fibril that periodically checks hub`s status. 184 * Hub representation is passed to the fibril. 185 * @param usb_dev generic usb device information 186 * @return error code 187 */ 188 int usb_hub_add_device(usb_device_t * usb_dev){ 189 if(!usb_dev) return EINVAL; 190 usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev); 191 //create hc connection 192 usb_log_debug("Initializing USB wire abstraction.\n"); 193 int opResult = usb_hc_connection_initialize_from_device( 194 &hub_info->connection, 195 hub_info->usb_device->ddf_dev); 196 if(opResult != EOK){ 197 usb_log_error("could not initialize connection to device, errno %d\n", 198 opResult); 199 free(hub_info); 200 return opResult; 201 } 202 203 usb_pipe_start_session(hub_info->control_pipe); 204 //set hub configuration 205 opResult = usb_hub_set_configuration(hub_info); 206 if(opResult!=EOK){ 207 usb_log_error("could not set hub configuration, errno %d\n",opResult); 208 free(hub_info); 209 return opResult; 210 } 211 //get port count and create attached_devs 212 opResult = usb_hub_process_hub_specific_info(hub_info); 213 if(opResult!=EOK){ 214 usb_log_error("could not set hub configuration, errno %d\n",opResult); 215 free(hub_info); 216 return opResult; 217 } 218 usb_pipe_end_session(hub_info->control_pipe); 219 220 221 /// \TODO what is this? 222 usb_log_debug("Creating `hub' function.\n"); 223 ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev, 224 fun_exposed, "hub"); 225 assert(hub_fun != NULL); 226 hub_fun->ops = NULL; 227 228 int rc = ddf_fun_bind(hub_fun); 229 assert(rc == EOK); 230 rc = ddf_fun_add_to_class(hub_fun, "hub"); 231 assert(rc == EOK); 232 316 * create and start fibril with hub control loop 317 * 318 * Before the fibril is started, the control pipe and host controller 319 * connection of the hub is open. 320 * 321 * @param hub_info hub representing structure 322 * @return error code 323 */ 324 static int usb_hub_start_hub_fibril(usb_hub_info_t * hub_info){ 233 325 /* 234 326 * The processing will require opened control pipe and connection … … 239 331 * auto destruction, this could work better. 240 332 */ 241 rc = usb_pipe_start_session(&usb_dev->ctrl_pipe);333 int rc = usb_pipe_start_session(hub_info->control_pipe); 242 334 if (rc != EOK) { 243 335 usb_log_error("Failed to start session on control pipe: %s.\n", 244 336 str_error(rc)); 245 goto leave;337 return rc; 246 338 } 247 339 rc = usb_hc_connection_open(&hub_info->connection); 248 340 if (rc != EOK) { 249 usb_pipe_end_session( &usb_dev->ctrl_pipe);341 usb_pipe_end_session(hub_info->control_pipe); 250 342 usb_log_error("Failed to open connection to HC: %s.\n", 251 343 str_error(rc)); 252 goto leave;344 return rc; 253 345 } 254 346 255 347 rc = usb_device_auto_poll(hub_info->usb_device, 0, 256 hub_port_changes_callback, ((hub_info->port_count +1) / 8) + 1,348 hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1, 257 349 NULL, hub_info); 258 350 if (rc != EOK) { … … 266 358 hub_info->usb_device->ddf_dev->name, hub_info->port_count); 267 359 return EOK; 268 269 leave: 270 free(hub_info); 271 272 return rc; 273 } 274 275 276 //********************************************* 277 // 278 // hub driver code, main loop and port handling 279 // 280 //********************************************* 281 282 /** 283 * triggers actions to connect non0removable devices 284 * 285 * This will trigger operations leading to activated non-removable device. 286 * Control pipe of the hub must be open fo communication. 287 * @param hub hub representation 288 * @param descriptor usb hub descriptor 289 * @return error code 290 */ 291 static int usb_hub_trigger_connecting_non_removable_devices(usb_hub_info_t * hub, 292 usb_hub_descriptor_t * descriptor) 293 { 294 usb_log_info("attaching non-removable devices(if any)\n"); 295 usb_device_request_setup_packet_t request; 360 } 361 362 //********************************************* 363 // 364 // change handling functions 365 // 366 //********************************************* 367 368 369 /** 370 * process hub over current change 371 * 372 * This means either to power off the hub or power it on. 373 * @param hub_info hub instance 374 * @param status hub status bitmask 375 * @return error code 376 */ 377 static int usb_process_hub_over_current(usb_hub_info_t * hub_info, 378 usb_hub_status_t status) { 296 379 int opResult; 297 size_t rcvd_size; 298 usb_port_status_t status; 299 uint8_t * non_removable_dev_bitmap = descriptor->devices_removable; 300 int port; 301 for(port=1;port<=descriptor->ports_count;++port){ 302 bool is_non_removable = 303 ((non_removable_dev_bitmap[port/8]) >> (port%8)) %2; 304 if(is_non_removable){ 305 usb_log_debug("non-removable device on port %d\n",port); 306 usb_hub_set_port_status_request(&request, port); 307 opResult = usb_pipe_control_read( 308 hub->control_pipe, 309 &request, sizeof(usb_device_request_setup_packet_t), 310 &status, 4, &rcvd_size 311 ); 380 if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_OVER_CURRENT)){ 381 opResult = usb_hub_clear_feature(hub_info->control_pipe, 382 USB_HUB_FEATURE_HUB_LOCAL_POWER); 383 if (opResult != EOK) { 384 usb_log_error("cannot power off hub: %d\n", 385 opResult); 386 } 387 } else { 388 opResult = usb_hub_set_feature(hub_info->control_pipe, 389 USB_HUB_FEATURE_HUB_LOCAL_POWER); 390 if (opResult != EOK) { 391 usb_log_error("cannot power on hub: %d\n", 392 opResult); 393 } 394 } 395 return opResult; 396 } 397 398 /** 399 * process hub power change 400 * 401 * If the power has been lost, reestablish it. 402 * If it was reestablished, re-power all ports. 403 * @param hub_info hub instance 404 * @param status hub status bitmask 405 * @return error code 406 */ 407 static int usb_process_hub_power_change(usb_hub_info_t * hub_info, 408 usb_hub_status_t status) { 409 int opResult; 410 if (usb_hub_is_status(status,USB_HUB_FEATURE_HUB_LOCAL_POWER)) { 411 //restart power on hub 412 opResult = usb_hub_set_feature(hub_info->control_pipe, 413 USB_HUB_FEATURE_HUB_LOCAL_POWER); 414 if (opResult != EOK) { 415 usb_log_error("cannot power on hub: %d\n", 416 opResult); 417 } 418 } else {//power reestablished on hub- restart ports 419 size_t port; 420 for (port = 0; port < hub_info->port_count; ++port) { 421 opResult = usb_hub_set_port_feature( 422 hub_info->control_pipe, 423 port, USB_HUB_FEATURE_PORT_POWER); 312 424 if (opResult != EOK) { 313 usb_log_error("could not get port status of port %d errno:%d\n", 314 port, opResult); 315 return opResult; 316 } 317 //set the status change bit, so it will be noticed in driver loop 318 if(usb_port_dev_connected(&status)){ 319 usb_hub_set_disable_port_feature_request(&request, port, 320 USB_HUB_FEATURE_PORT_CONNECTION); 321 opResult = usb_pipe_control_read( 322 hub->control_pipe, 323 &request, sizeof(usb_device_request_setup_packet_t), 324 &status, 4, &rcvd_size 325 ); 326 if (opResult != EOK) { 327 usb_log_warning( 328 "could not clear port connection on port %d errno:%d\n", 329 port, opResult); 330 } 331 usb_log_debug("cleared port connection\n"); 332 usb_hub_set_enable_port_feature_request(&request, port, 333 USB_HUB_FEATURE_PORT_ENABLE); 334 opResult = usb_pipe_control_read( 335 hub->control_pipe, 336 &request, sizeof(usb_device_request_setup_packet_t), 337 &status, 4, &rcvd_size 338 ); 339 if (opResult != EOK) { 340 usb_log_warning( 341 "could not set port enabled on port %d errno:%d\n", 342 port, opResult); 343 } 344 usb_log_debug("port set to enabled - should lead to connection change\n"); 425 usb_log_error("cannot power on port %d; %d\n", 426 port, opResult); 345 427 } 346 428 } 347 429 } 348 /// \TODO this is just a debug code 349 for(port=1;port<=descriptor->ports_count;++port){ 350 bool is_non_removable = 351 ((non_removable_dev_bitmap[port/8]) >> (port%8)) %2; 352 if(is_non_removable){ 353 usb_log_debug("port %d is non-removable\n",port); 354 usb_port_status_t status; 355 size_t rcvd_size; 356 usb_device_request_setup_packet_t request; 357 //int opResult; 358 usb_hub_set_port_status_request(&request, port); 359 //endpoint 0 360 opResult = usb_pipe_control_read( 361 hub->control_pipe, 362 &request, sizeof(usb_device_request_setup_packet_t), 363 &status, 4, &rcvd_size 364 ); 365 if (opResult != EOK) { 366 usb_log_error("could not get port status %d\n",opResult); 367 } 368 if (rcvd_size != sizeof (usb_port_status_t)) { 369 usb_log_error("received status has incorrect size\n"); 370 } 371 //something connected/disconnected 372 if (usb_port_connect_change(&status)) { 373 usb_log_debug("some connection changed\n"); 374 } 375 usb_log_debug("status: %s\n",usb_debug_str_buffer( 376 (uint8_t *)&status,4,4)); 377 } 378 } 379 return EOK; 380 } 381 382 383 /** 384 * release default address used by given hub 385 * 386 * Also unsets hub->is_default_address_used. Convenience wrapper function. 387 * @note hub->connection MUST be open for communication 388 * @param hub hub representation 389 * @return error code 390 */ 391 static int usb_hub_release_default_address(usb_hub_info_t * hub){ 392 int opResult = usb_hc_release_default_address(&hub->connection); 393 if(opResult!=EOK){ 394 usb_log_error("could not release default address, errno %d\n",opResult); 395 return opResult; 396 } 397 hub->is_default_address_used = false; 398 return EOK; 399 } 400 401 /** 402 * routine called when a device on port has been removed 403 * 404 * If the device on port had default address, it releases default address. 405 * Otherwise does not do anything, because DDF does not allow to remove device 406 * from it`s device tree. 407 * @param hub hub representation 408 * @param port port number, starting from 1 409 */ 410 void usb_hub_removed_device( 411 usb_hub_info_t * hub,uint16_t port) { 412 413 int opResult = usb_hub_clear_port_feature(hub->control_pipe, 414 port, USB_HUB_FEATURE_C_PORT_CONNECTION); 415 if(opResult != EOK){ 416 usb_log_warning("could not clear port-change-connection flag\n"); 417 } 418 /** \TODO remove device from device manager - not yet implemented in 419 * devide manager 420 */ 421 422 //close address 423 if(hub->ports[port].attached_device.address >= 0){ 424 /*uncomment this code to use it when DDF allows device removal 425 opResult = usb_hc_unregister_device( 426 &hub->connection, hub->attached_devs[port].address); 427 if(opResult != EOK) { 428 dprintf(USB_LOG_LEVEL_WARNING, "could not release address of " \ 429 "removed device: %d", opResult); 430 } 431 hub->attached_devs[port].address = 0; 432 hub->attached_devs[port].handle = 0; 433 */ 434 }else{ 435 usb_log_warning("this is strange, disconnected device had no address\n"); 436 //device was disconnected before it`s port was reset - return default address 437 usb_hub_release_default_address(hub); 438 } 439 } 440 441 442 /** 443 * Process over current condition on port. 444 * 445 * Turn off the power on the port. 446 * 447 * @param hub hub representation 448 * @param port port number, starting from 1 449 */ 450 void usb_hub_over_current( usb_hub_info_t * hub, 451 uint16_t port){ 430 return opResult; 431 } 432 433 /** 434 * process hub interrupts 435 * 436 * The change can be either in the over-current condition or 437 * local-power lost condition. 438 * @param hub_info hub instance 439 */ 440 static void usb_hub_process_global_interrupt(usb_hub_info_t * hub_info) { 441 usb_log_debug("global interrupt on a hub\n"); 442 usb_pipe_t *pipe = hub_info->control_pipe; 452 443 int opResult; 453 opResult = usb_hub_clear_port_feature(hub->control_pipe, 454 port, USB_HUB_FEATURE_PORT_POWER); 455 if(opResult!=EOK){ 456 usb_log_error("cannot power off port %d; %d\n", 457 port, opResult); 458 } 459 } 460 444 445 usb_port_status_t status; 446 size_t rcvd_size; 447 usb_device_request_setup_packet_t request; 448 //int opResult; 449 usb_hub_set_hub_status_request(&request); 450 //endpoint 0 451 452 opResult = usb_pipe_control_read( 453 pipe, 454 &request, sizeof (usb_device_request_setup_packet_t), 455 &status, 4, &rcvd_size 456 ); 457 if (opResult != EOK) { 458 usb_log_error("could not get hub status\n"); 459 return; 460 } 461 if (rcvd_size != sizeof (usb_port_status_t)) { 462 usb_log_error("received status has incorrect size\n"); 463 return; 464 } 465 //port reset 466 if ( 467 usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_OVER_CURRENT)) { 468 usb_process_hub_over_current(hub_info, status); 469 } 470 if ( 471 usb_hub_is_status(status,16+USB_HUB_FEATURE_C_HUB_LOCAL_POWER)) { 472 usb_process_hub_power_change(hub_info, status); 473 } 474 } 461 475 462 476 /**
Note:
See TracChangeset
for help on using the changeset viewer.