Changes in uspace/drv/bus/usb/usbhub/usbhub.c [1dc4a5e:cae002c] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/usbhub/usbhub.c
r1dc4a5e rcae002c 1 1 /* 2 2 * Copyright (c) 2010 Matus Dekanek 3 * Copyright (c) 2011 Jan Vesely 3 4 * All rights reserved. 4 5 * … … 38 39 #include <str_error.h> 39 40 #include <inttypes.h> 40 41 #include <usb_iface.h> 41 #include <stdio.h> 42 43 #include <usb/usb.h> 44 #include <usb/debug.h> 45 #include <usb/dev/pipes.h> 46 #include <usb/classes/classes.h> 42 47 #include <usb/ddfiface.h> 43 48 #include <usb/descriptor.h> … … 46 51 #include <usb/classes/hub.h> 47 52 #include <usb/dev/poll.h> 48 #include < stdio.h>53 #include <usb_iface.h> 49 54 50 55 #include "usbhub.h" 51 #include " usbhub_private.h"52 #include "port_status.h" 53 # include <usb/usb.h>54 #include <usb/dev/pipes.h> 55 #include <usb/classes/classes.h> 56 57 58 static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev); 59 60 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info); 61 62 static int usb_hub_set_configuration(usb_hub_info_t *hub_info);63 64 static int usb_ hub_start_hub_fibril(usb_hub_info_t *hub_info);65 66 static int usb_process_hub_over_current(usb_hub_info_t *hub_info,56 #include "status.h" 57 58 #define HUB_FNC_NAME "hub" 59 60 /** Standard get hub global status request */ 61 static const usb_device_request_setup_packet_t get_hub_status_request = { 62 .request_type = USB_HUB_REQ_TYPE_GET_HUB_STATUS, 63 .request = USB_HUB_REQUEST_GET_STATUS, 64 .index = 0, 65 .value = 0, 66 .length = sizeof(usb_hub_status_t), 67 }; 68 69 static int usb_set_first_configuration(usb_device_t *usb_device); 70 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev); 71 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev, 67 72 usb_hub_status_t status); 68 69 static int usb_process_hub_local_power_change(usb_hub_info_t *hub_info, 70 usb_hub_status_t status); 71 72 static void usb_hub_process_global_interrupt(usb_hub_info_t *hub_info); 73 73 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev); 74 74 static void usb_hub_polling_terminated_callback(usb_device_t *device, 75 75 bool was_error, void *data); 76 76 77 78 //********************************************* 79 // 80 // hub driver code, initialization 81 // 82 //********************************************* 83 84 /** 85 * Initialize hub device driver fibril 86 * 87 * Creates hub representation and fibril that periodically checks hub`s status. 77 /** 78 * Initialize hub device driver structure. 79 * 80 * Creates hub representation and fibril that periodically checks hub's status. 88 81 * Hub representation is passed to the fibril. 89 82 * @param usb_dev generic usb device information 90 83 * @return error code 91 84 */ 92 int usb_hub_add_device(usb_device_t *usb_dev) { 93 if (!usb_dev) return EINVAL; 94 usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev); 95 //create hc connection 85 int usb_hub_device_add(usb_device_t *usb_dev) 86 { 87 assert(usb_dev); 88 /* Create driver soft-state structure */ 89 usb_hub_dev_t *hub_dev = 90 usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t)); 91 if (hub_dev == NULL) { 92 usb_log_error("Failed to create hub driver structure.\n"); 93 return ENOMEM; 94 } 95 hub_dev->usb_device = usb_dev; 96 hub_dev->pending_ops_count = 0; 97 hub_dev->running = false; 98 fibril_mutex_initialize(&hub_dev->pending_ops_mutex); 99 fibril_condvar_initialize(&hub_dev->pending_ops_cv); 100 101 /* Create hc connection */ 96 102 usb_log_debug("Initializing USB wire abstraction.\n"); 97 103 int opResult = usb_hc_connection_initialize_from_device( 98 &hub_info->connection, 99 hub_info->usb_device->ddf_dev); 100 if (opResult != EOK) { 101 usb_log_error("Could not initialize connection to device, " 102 " %s\n", 103 str_error(opResult)); 104 free(hub_info); 104 &hub_dev->connection, hub_dev->usb_device->ddf_dev); 105 if (opResult != EOK) { 106 usb_log_error("Could not initialize connection to device: %s\n", 107 str_error(opResult)); 105 108 return opResult; 106 109 } 107 110 108 //set hub configuration 109 opResult = usb_hub_set_configuration(hub_info); 110 if (opResult != EOK) { 111 usb_log_error("Could not set hub configuration, %s\n", 112 str_error(opResult)); 113 free(hub_info); 111 /* Set hub's first configuration. (There should be only one) */ 112 opResult = usb_set_first_configuration(usb_dev); 113 if (opResult != EOK) { 114 usb_log_error("Could not set hub configuration: %s\n", 115 str_error(opResult)); 114 116 return opResult; 115 117 } 116 //get port count and create attached_devs 117 opResult = usb_hub_process_hub_specific_info(hub_info); 118 119 /* Get port count and create attached_devices. */ 120 opResult = usb_hub_process_hub_specific_info(hub_dev); 118 121 if (opResult != EOK) { 119 122 usb_log_error("Could process hub specific info, %s\n", 120 123 str_error(opResult)); 121 free(hub_info);122 124 return opResult; 123 125 } 124 126 125 usb_log_debug("Creating 'hub' function in DDF.\n"); 126 ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev, 127 fun_exposed, "hub"); 128 assert(hub_fun != NULL); 129 hub_fun->ops = NULL; 130 131 opResult = ddf_fun_bind(hub_fun); 132 assert(opResult == EOK); 133 opResult = ddf_fun_add_to_category(hub_fun, "hub"); 134 assert(opResult == EOK); 135 136 opResult = usb_hub_start_hub_fibril(hub_info); 137 if (opResult != EOK) 138 free(hub_info); 139 return opResult; 140 } 141 127 /* Create hub control function. */ 128 usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n"); 129 hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev, 130 fun_exposed, HUB_FNC_NAME); 131 if (hub_dev->hub_fun == NULL) { 132 usb_log_error("Failed to create hub function.\n"); 133 return ENOMEM; 134 } 135 136 /* Bind hub control function. */ 137 opResult = ddf_fun_bind(hub_dev->hub_fun); 138 if (opResult != EOK) { 139 usb_log_error("Failed to bind hub function: %s.\n", 140 str_error(opResult)); 141 ddf_fun_destroy(hub_dev->hub_fun); 142 return opResult; 143 } 144 145 /* Start hub operation. */ 146 opResult = usb_device_auto_poll(hub_dev->usb_device, 0, 147 hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8), 148 usb_hub_polling_terminated_callback, hub_dev); 149 if (opResult != EOK) { 150 /* Function is already bound */ 151 ddf_fun_unbind(hub_dev->hub_fun); 152 ddf_fun_destroy(hub_dev->hub_fun); 153 usb_log_error("Failed to create polling fibril: %s.\n", 154 str_error(opResult)); 155 return opResult; 156 } 157 hub_dev->running = true; 158 usb_log_info("Controlling hub '%s' (%zu ports).\n", 159 hub_dev->usb_device->ddf_dev->name, hub_dev->port_count); 160 161 return EOK; 162 } 163 /*----------------------------------------------------------------------------*/ 164 /** 165 * Turn off power to all ports. 166 * 167 * @param usb_dev generic usb device information 168 * @return error code 169 */ 170 int usb_hub_device_remove(usb_device_t *usb_dev) 171 { 172 return ENOTSUP; 173 } 174 /*----------------------------------------------------------------------------*/ 175 /** 176 * Remove all attached devices 177 * @param usb_dev generic usb device information 178 * @return error code 179 */ 180 int usb_hub_device_gone(usb_device_t *usb_dev) 181 { 182 assert(usb_dev); 183 usb_hub_dev_t *hub = usb_dev->driver_data; 184 assert(hub); 185 unsigned tries = 10; 186 while (hub->running) { 187 async_usleep(100000); 188 if (!tries--) { 189 usb_log_error("Can't remove hub, still running.\n"); 190 return EINPROGRESS; 191 } 192 } 193 194 assert(!hub->running); 195 196 for (size_t port = 0; port < hub->port_count; ++port) { 197 if (hub->ports[port].attached_device.fun) { 198 const int ret = 199 usb_hub_port_fini(&hub->ports[port], hub); 200 if (ret != EOK) 201 return ret; 202 } 203 } 204 free(hub->ports); 205 206 const int ret = ddf_fun_unbind(hub->hub_fun); 207 if (ret != EOK) { 208 usb_log_error("Failed to unbind '%s' function: %s.\n", 209 HUB_FNC_NAME, str_error(ret)); 210 return ret; 211 } 212 ddf_fun_destroy(hub->hub_fun); 213 214 usb_log_info("USB hub driver, stopped and cleaned.\n"); 215 return EOK; 216 } 217 /*----------------------------------------------------------------------------*/ 142 218 /** Callback for polling hub for changes. 143 219 * … … 145 221 * @param change_bitmap Bitmap of changed ports. 146 222 * @param change_bitmap_size Size of the bitmap in bytes. 147 * @param arg Custom argument, points to @c usb_hub_ info_t.223 * @param arg Custom argument, points to @c usb_hub_dev_t. 148 224 * @return Whether to continue polling. 149 225 */ 150 226 bool hub_port_changes_callback(usb_device_t *dev, 151 uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) { 227 uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) 228 { 152 229 usb_log_debug("hub_port_changes_callback\n"); 153 usb_hub_info_t *hub = (usb_hub_info_t *) arg; 154 155 /* FIXME: check that we received enough bytes. */ 230 usb_hub_dev_t *hub = arg; 231 assert(hub); 232 233 /* It is an error condition if we didn't receive enough data */ 156 234 if (change_bitmap_size == 0) { 157 goto leave;158 } 159 160 bool change;161 c hange = ((uint8_t*) change_bitmap)[0] & 1;235 return false; 236 } 237 238 /* Lowest bit indicates global change */ 239 const bool change = change_bitmap[0] & 1; 162 240 if (change) { 163 usb_hub_process_global_interrupt(hub); 164 } 165 166 size_t port; 167 for (port = 1; port < hub->port_count + 1; port++) { 168 bool change = (change_bitmap[port / 8] >> (port % 8)) % 2; 241 usb_hub_global_interrupt(hub); 242 } 243 244 /* N + 1 bit indicates change on port N */ 245 for (size_t port = 0; port < hub->port_count + 1; port++) { 246 const size_t bit = port + 1; 247 const bool change = (change_bitmap[bit / 8] >> (bit % 8)) & 1; 169 248 if (change) { 170 usb_hub_process_port_interrupt(hub, port); 171 } 172 } 173 leave: 174 /* FIXME: proper interval. */ 175 async_usleep(1000 * 250); 176 249 usb_hub_port_process_interrupt(&hub->ports[port], hub); 250 } 251 } 177 252 return true; 178 253 } 179 180 181 //********************************************* 182 // 183 // support functions 184 // 185 //********************************************* 186 187 /** 188 * create usb_hub_info_t structure 189 * 190 * Does only basic copying of known information into new structure. 191 * @param usb_dev usb device structure 192 * @return basic usb_hub_info_t structure 193 */ 194 static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev) { 195 usb_hub_info_t * result = malloc(sizeof (usb_hub_info_t)); 196 if (!result) return NULL; 197 result->usb_device = usb_dev; 198 result->status_change_pipe = usb_dev->pipes[0].pipe; 199 result->control_pipe = &usb_dev->ctrl_pipe; 200 result->is_default_address_used = false; 201 202 result->ports = NULL; 203 result->port_count = (size_t) - 1; 204 fibril_mutex_initialize(&result->port_mutex); 205 206 fibril_mutex_initialize(&result->pending_ops_mutex); 207 fibril_condvar_initialize(&result->pending_ops_cv); 208 result->pending_ops_count = 0; 209 return result; 210 } 211 212 /** 213 * Load hub-specific information into hub_info structure and process if needed 214 * 215 * Particularly read port count and initialize structure holding port 216 * information. If there are non-removable devices, start initializing them. 254 /*----------------------------------------------------------------------------*/ 255 /** 256 * Load hub-specific information into hub_dev structure and process if needed 257 * 258 * Read port count and initialize structures holding per port information. 259 * If there are any non-removable devices, start initializing them. 217 260 * This function is hub-specific and should be run only after the hub is 218 * configured using usb_ hub_set_configuration function.219 * @param hub_ infohub representation261 * configured using usb_set_first_configuration function. 262 * @param hub_dev hub representation 220 263 * @return error code 221 264 */ 222 int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info) 223 { 224 // get hub descriptor 265 static int usb_hub_process_hub_specific_info(usb_hub_dev_t *hub_dev) 266 { 267 assert(hub_dev); 268 269 /* Get hub descriptor. */ 225 270 usb_log_debug("Retrieving descriptor\n"); 226 u int8_t serialized_descriptor[USB_HUB_MAX_DESCRIPTOR_SIZE];227 int opResult; 228 271 usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe; 272 273 usb_hub_descriptor_header_t descriptor; 229 274 size_t received_size; 230 opResult = usb_request_get_descriptor(hub_info->control_pipe,275 int opResult = usb_request_get_descriptor(control_pipe, 231 276 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE, 232 USB_DESCTYPE_HUB, 0, 0, serialized_descriptor, 233 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size); 234 277 USB_DESCTYPE_HUB, 0, 0, &descriptor, 278 sizeof(usb_hub_descriptor_header_t), &received_size); 235 279 if (opResult != EOK) { 236 280 usb_log_error("Failed to receive hub descriptor: %s.\n", … … 238 282 return opResult; 239 283 } 240 usb_log_debug2("Parsing descriptor\n"); 241 usb_hub_descriptor_t descriptor; 242 opResult = usb_deserialize_hub_desriptor( 243 serialized_descriptor, received_size, &descriptor); 244 if (opResult != EOK) { 245 usb_log_error("Could not parse descriptor: %s\n", 246 str_error(opResult)); 247 return opResult; 248 } 249 usb_log_debug("Setting port count to %d.\n", descriptor.ports_count); 250 hub_info->port_count = descriptor.ports_count; 251 252 hub_info->ports = 253 malloc(sizeof(usb_hub_port_t) * (hub_info->port_count + 1)); 254 if (!hub_info->ports) { 284 285 usb_log_debug("Setting port count to %d.\n", descriptor.port_count); 286 hub_dev->port_count = descriptor.port_count; 287 288 hub_dev->ports = calloc(hub_dev->port_count, sizeof(usb_hub_port_t)); 289 if (!hub_dev->ports) { 255 290 return ENOMEM; 256 291 } 257 292 258 size_t port; 259 for (port = 0; port < hub_info->port_count + 1; ++port) { 260 usb_hub_port_init(&hub_info->ports[port]); 261 } 262 263 const bool is_power_switched = 264 !(descriptor.hub_characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG); 265 if (is_power_switched) { 266 usb_log_debug("Hub power switched\n"); 267 const bool per_port_power = descriptor.hub_characteristics 268 & HUB_CHAR_POWER_PER_PORT_FLAG; 269 270 for (port = 1; port <= hub_info->port_count; ++port) { 271 usb_log_debug("Powering port %zu.\n", port); 272 opResult = usb_hub_set_port_feature( 273 hub_info->control_pipe, 274 port, USB_HUB_FEATURE_PORT_POWER); 275 if (opResult != EOK) { 276 usb_log_error("Cannot power on port %zu: %s.\n", 277 port, str_error(opResult)); 278 } else { 279 if (!per_port_power) { 280 usb_log_debug( 281 "Ganged power switching mode, " 282 "one port is enough.\n"); 283 break; 284 } 293 for (size_t port = 0; port < hub_dev->port_count; ++port) { 294 usb_hub_port_init( 295 &hub_dev->ports[port], port + 1, control_pipe); 296 } 297 298 hub_dev->power_switched = 299 !(descriptor.characteristics & HUB_CHAR_NO_POWER_SWITCH_FLAG); 300 hub_dev->per_port_power = 301 descriptor.characteristics & HUB_CHAR_POWER_PER_PORT_FLAG; 302 303 if (!hub_dev->power_switched) { 304 usb_log_info( 305 "Power switching not supported, ports always powered.\n"); 306 return EOK; 307 } 308 309 usb_log_info("Hub port power switching enabled.\n"); 310 311 for (size_t port = 0; port < hub_dev->port_count; ++port) { 312 usb_log_debug("Powering port %zu.\n", port); 313 const int ret = usb_hub_port_set_feature( 314 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 315 316 if (ret != EOK) { 317 usb_log_error("Cannot power on port %zu: %s.\n", 318 hub_dev->ports[port].port_number, str_error(ret)); 319 } else { 320 if (!hub_dev->per_port_power) { 321 usb_log_debug("Ganged power switching, " 322 "one port is enough.\n"); 323 break; 285 324 } 286 325 } 287 288 } else {289 usb_log_debug("Power not switched, not going to be powered\n");290 326 } 291 327 return EOK; 292 328 } 293 294 /** 295 * Set configuration of hub329 /*----------------------------------------------------------------------------*/ 330 /** 331 * Set configuration of and USB device 296 332 * 297 333 * Check whether there is at least one configuration and sets the first one. 298 334 * This function should be run prior to running any hub-specific action. 299 * @param hub_info hubrepresentation335 * @param usb_device usb device representation 300 336 * @return error code 301 337 */ 302 static int usb_hub_set_configuration(usb_hub_info_t *hub_info) { 303 //device descriptor 304 usb_standard_device_descriptor_t *std_descriptor 305 = &hub_info->usb_device->descriptors.device; 306 usb_log_debug("Hub has %d configurations\n", 307 std_descriptor->configuration_count); 308 if (std_descriptor->configuration_count < 1) { 338 static int usb_set_first_configuration(usb_device_t *usb_device) 339 { 340 assert(usb_device); 341 /* Get number of possible configurations from device descriptor */ 342 const size_t configuration_count = 343 usb_device->descriptors.device.configuration_count; 344 usb_log_debug("Hub has %zu configurations.\n", configuration_count); 345 346 if (configuration_count < 1) { 309 347 usb_log_error("There are no configurations available\n"); 310 348 return EINVAL; 311 349 } 312 350 351 if (usb_device->descriptors.configuration_size 352 < sizeof(usb_standard_configuration_descriptor_t)) { 353 usb_log_error("Configuration descriptor is not big enough" 354 " to fit standard configuration descriptor.\n"); 355 return EOVERFLOW; 356 } 357 358 // TODO: Make sure that the cast is correct 313 359 usb_standard_configuration_descriptor_t *config_descriptor 314 360 = (usb_standard_configuration_descriptor_t *) 315 hub_info->usb_device->descriptors.configuration; 316 317 /* Set configuration. */ 318 int opResult = usb_request_set_configuration( 319 &hub_info->usb_device->ctrl_pipe, 320 config_descriptor->configuration_number); 321 361 usb_device->descriptors.configuration; 362 363 /* Set configuration. Use the configuration that was in 364 * usb_device->descriptors.configuration i.e. The first one. */ 365 const int opResult = usb_request_set_configuration( 366 &usb_device->ctrl_pipe, config_descriptor->configuration_number); 322 367 if (opResult != EOK) { 323 368 usb_log_error("Failed to set hub configuration: %s.\n", 324 369 str_error(opResult)); 325 return opResult; 326 } 327 usb_log_debug("\tUsed configuration %d\n", 328 config_descriptor->configuration_number); 329 330 return EOK; 331 } 332 333 /** 334 * create and start fibril with hub control loop 335 * 336 * Before the fibril is started, the control pipe and host controller 337 * connection of the hub is open. 338 * 339 * @param hub_info hub representing structure 340 * @return error code 341 */ 342 static int usb_hub_start_hub_fibril(usb_hub_info_t *hub_info) { 343 int rc; 344 345 rc = usb_device_auto_poll(hub_info->usb_device, 0, 346 hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1, 347 usb_hub_polling_terminated_callback, hub_info); 348 if (rc != EOK) { 349 usb_log_error("Failed to create polling fibril: %s.\n", 350 str_error(rc)); 351 free(hub_info); 352 return rc; 353 } 354 355 usb_log_info("Controlling hub `%s' (%zu ports).\n", 356 hub_info->usb_device->ddf_dev->name, hub_info->port_count); 357 return EOK; 358 } 359 360 //********************************************* 361 // 362 // change handling functions 363 // 364 //********************************************* 365 366 /** 367 * process hub over current change 370 } else { 371 usb_log_debug("\tUsed configuration %d\n", 372 config_descriptor->configuration_number); 373 } 374 return opResult; 375 } 376 /*----------------------------------------------------------------------------*/ 377 /** 378 * Process hub over current change 368 379 * 369 380 * This means either to power off the hub or power it on. 370 * @param hub_ infohub instance381 * @param hub_dev hub instance 371 382 * @param status hub status bitmask 372 383 * @return error code 373 384 */ 374 static int usb_process_hub_over_current(usb_hub_info_t *hub_info, 375 usb_hub_status_t status) { 376 int opResult; 377 if (usb_hub_is_status(status, USB_HUB_FEATURE_HUB_OVER_CURRENT)) { 378 //poweroff all ports 379 unsigned int port; 380 for (port = 1; port <= hub_info->port_count; ++port) { 381 opResult = usb_hub_clear_port_feature( 382 hub_info->control_pipe, port, 383 USB_HUB_FEATURE_PORT_POWER); 384 if (opResult != EOK) { 385 usb_log_warning( 386 "Cannot power off port %d; %s\n", 387 port, str_error(opResult)); 388 } 389 } 390 } else { 391 //power all ports 392 unsigned int port; 393 for (port = 1; port <= hub_info->port_count; ++port) { 394 opResult = usb_hub_set_port_feature( 395 hub_info->control_pipe, port, 396 USB_HUB_FEATURE_PORT_POWER); 397 if (opResult != EOK) { 398 usb_log_warning( 399 "Cannot power off port %d; %s\n", 400 port, str_error(opResult)); 401 } 402 } 403 } 404 return opResult; 405 } 406 407 /** 408 * process hub local power change 409 * 410 * This change is ignored. 411 * @param hub_info hub instance 412 * @param status hub status bitmask 413 * @return error code 414 */ 415 static int usb_process_hub_local_power_change(usb_hub_info_t *hub_info, 416 usb_hub_status_t status) { 417 int opResult = EOK; 418 opResult = usb_hub_clear_feature(hub_info->control_pipe, 419 USB_HUB_FEATURE_C_HUB_LOCAL_POWER); 420 if (opResult != EOK) { 421 usb_log_error("Cannnot clear hub power change flag: " 422 "%s\n", 423 str_error(opResult)); 424 } 425 return opResult; 426 } 427 428 /** 429 * process hub interrupts 430 * 431 * The change can be either in the over-current condition or 432 * local-power change. 433 * @param hub_info hub instance 434 */ 435 static void usb_hub_process_global_interrupt(usb_hub_info_t *hub_info) { 385 static void usb_hub_over_current(const usb_hub_dev_t *hub_dev, 386 usb_hub_status_t status) 387 { 388 if (status & USB_HUB_STATUS_OVER_CURRENT) { 389 /* Hub should remove power from all ports if it detects OC */ 390 usb_log_warning("Detected hub over-current condition, " 391 "all ports should be powered off."); 392 return; 393 } 394 395 /* Ports are always powered. */ 396 if (!hub_dev->power_switched) 397 return; 398 399 /* Over-current condition is gone, it is safe to turn the ports on. */ 400 for (size_t port = 0; port < hub_dev->port_count; ++port) { 401 const int ret = usb_hub_port_set_feature( 402 &hub_dev->ports[port], USB_HUB_FEATURE_PORT_POWER); 403 if (ret != EOK) { 404 usb_log_warning("HUB OVER-CURRENT GONE: Cannot power on" 405 " port %zu: %s\n", hub_dev->ports[port].port_number, 406 str_error(ret)); 407 } else { 408 if (!hub_dev->per_port_power) 409 return; 410 } 411 } 412 413 } 414 /*----------------------------------------------------------------------------*/ 415 /** 416 * Process hub interrupts. 417 * 418 * The change can be either in the over-current condition or local-power change. 419 * @param hub_dev hub instance 420 */ 421 static void usb_hub_global_interrupt(const usb_hub_dev_t *hub_dev) 422 { 423 assert(hub_dev); 424 assert(hub_dev->usb_device); 436 425 usb_log_debug("Global interrupt on a hub\n"); 437 usb_pipe_t *pipe = hub_info->control_pipe; 438 int opResult; 439 440 usb_port_status_t status; 426 usb_pipe_t *control_pipe = &hub_dev->usb_device->ctrl_pipe; 427 428 usb_hub_status_t status; 441 429 size_t rcvd_size; 442 usb_device_request_setup_packet_t request; 443 //int opResult; 444 usb_hub_set_hub_status_request(&request); 445 //endpoint 0 446 447 opResult = usb_pipe_control_read( 448 pipe, 449 &request, sizeof (usb_device_request_setup_packet_t), 450 &status, 4, &rcvd_size 451 ); 430 /* NOTE: We can't use standard USB GET_STATUS request, because 431 * hubs reply is 4byte instead of 2 */ 432 const int opResult = usb_pipe_control_read(control_pipe, 433 &get_hub_status_request, sizeof(get_hub_status_request), 434 &status, sizeof(usb_hub_status_t), &rcvd_size); 452 435 if (opResult != EOK) { 453 436 usb_log_error("Could not get hub status: %s\n", … … 455 438 return; 456 439 } 457 if (rcvd_size != sizeof (usb_port_status_t)) {440 if (rcvd_size != sizeof(usb_hub_status_t)) { 458 441 usb_log_error("Received status has incorrect size\n"); 459 442 return; 460 443 } 461 //port reset 462 if ( 463 usb_hub_is_status(status, 16 + USB_HUB_FEATURE_C_HUB_OVER_CURRENT)) { 464 usb_process_hub_over_current(hub_info, status); 465 } 466 if ( 467 usb_hub_is_status(status, 16 + USB_HUB_FEATURE_C_HUB_LOCAL_POWER)) { 468 usb_process_hub_local_power_change(hub_info, status); 469 } 470 } 471 444 445 /* Handle status changes */ 446 if (status & USB_HUB_STATUS_C_OVER_CURRENT) { 447 usb_hub_over_current(hub_dev, status); 448 /* Ack change in hub OC flag */ 449 const int ret = usb_request_clear_feature( 450 &hub_dev->usb_device->ctrl_pipe, USB_REQUEST_TYPE_CLASS, 451 USB_REQUEST_RECIPIENT_DEVICE, 452 USB_HUB_FEATURE_C_HUB_OVER_CURRENT, 0); 453 if (ret != EOK) { 454 usb_log_error("Failed to clear hub over-current " 455 "change flag: %s.\n", str_error(opResult)); 456 } 457 } 458 459 if (status & USB_HUB_STATUS_C_LOCAL_POWER) { 460 /* NOTE: Handling this is more complicated. 461 * If the transition is from bus power to local power, all 462 * is good and we may signal the parent hub that we don't 463 * need the power. 464 * If the transition is from local power to bus power 465 * the hub should turn off all the ports and devices need 466 * to be reinitialized taking into account the limited power 467 * that is now available. 468 * There is no support for power distribution in HelenOS, 469 * (or other OSes/hub devices that I've seen) so this is not 470 * implemented. 471 * Just ACK the change. 472 */ 473 const int ret = usb_request_clear_feature( 474 control_pipe, USB_REQUEST_TYPE_CLASS, 475 USB_REQUEST_RECIPIENT_DEVICE, 476 USB_HUB_FEATURE_C_HUB_LOCAL_POWER, 0); 477 if (opResult != EOK) { 478 usb_log_error("Failed to clear hub power change " 479 "flag: %s.\n", str_error(ret)); 480 } 481 } 482 } 483 /*----------------------------------------------------------------------------*/ 472 484 /** 473 485 * callback called from hub polling fibril when the fibril terminates 474 486 * 475 * Should perform a cleanup - deletes hub_info.487 * Does not perform cleanup, just marks the hub as not running. 476 488 * @param device usb device afected 477 489 * @param was_error indicates that the fibril is stoped due to an error 478 * @param data pointer to usb_hub_ info_t structure490 * @param data pointer to usb_hub_dev_t structure 479 491 */ 480 492 static void usb_hub_polling_terminated_callback(usb_device_t *device, 481 bool was_error, void *data) { 482 usb_hub_info_t * hub = data; 493 bool was_error, void *data) 494 { 495 usb_hub_dev_t *hub = data; 483 496 assert(hub); 484 497 … … 494 507 */ 495 508 if (hub->pending_ops_count > 0) { 496 fibril_mutex_lock(&hub->port_mutex); 497 size_t port; 498 for (port = 0; port < hub->port_count; port++) { 499 usb_hub_port_t *the_port = hub->ports + port; 500 fibril_mutex_lock(&the_port->reset_mutex); 501 the_port->reset_completed = true; 502 the_port->reset_okay = false; 503 fibril_condvar_broadcast(&the_port->reset_cv); 504 fibril_mutex_unlock(&the_port->reset_mutex); 505 } 506 fibril_mutex_unlock(&hub->port_mutex); 509 for (size_t port = 0; port < hub->port_count; ++port) { 510 usb_hub_port_reset_fail(&hub->ports[port]); 511 } 507 512 } 508 513 /* And now wait for them. */ … … 512 517 } 513 518 fibril_mutex_unlock(&hub->pending_ops_mutex); 514 515 usb_device_destroy(hub->usb_device); 516 517 free(hub->ports); 518 free(hub); 519 } 520 521 522 523 519 hub->running = false; 520 } 524 521 /** 525 522 * @}
Note:
See TracChangeset
for help on using the changeset viewer.