00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00035 #include <ddf/driver.h>
00036 #include <bool.h>
00037 #include <errno.h>
00038 #include <str_error.h>
00039 #include <inttypes.h>
00040
00041 #include <usb_iface.h>
00042 #include <usb/ddfiface.h>
00043 #include <usb/descriptor.h>
00044 #include <usb/dev/recognise.h>
00045 #include <usb/dev/request.h>
00046 #include <usb/classes/hub.h>
00047 #include <usb/dev/poll.h>
00048 #include <stdio.h>
00049
00050 #include "usbhub.h"
00051 #include "usbhub_private.h"
00052 #include "port_status.h"
00053 #include <usb/usb.h>
00054 #include <usb/dev/pipes.h>
00055 #include <usb/classes/classes.h>
00056
00057
00058 static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev);
00059
00060 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info);
00061
00062 static int usb_hub_set_configuration(usb_hub_info_t *hub_info);
00063
00064 static int usb_hub_start_hub_fibril(usb_hub_info_t *hub_info);
00065
00066 static int usb_process_hub_over_current(usb_hub_info_t *hub_info,
00067 usb_hub_status_t status);
00068
00069 static int usb_process_hub_local_power_change(usb_hub_info_t *hub_info,
00070 usb_hub_status_t status);
00071
00072 static void usb_hub_process_global_interrupt(usb_hub_info_t *hub_info);
00073
00074 static void usb_hub_polling_terminated_callback(usb_device_t *device,
00075 bool was_error, void *data);
00076
00077
00078
00079
00080
00081
00082
00083
00092 int usb_hub_add_device(usb_device_t *usb_dev) {
00093 if (!usb_dev) return EINVAL;
00094 usb_hub_info_t *hub_info = usb_hub_info_create(usb_dev);
00095
00096 usb_log_debug("Initializing USB wire abstraction.\n");
00097 int opResult = usb_hc_connection_initialize_from_device(
00098 &hub_info->connection,
00099 hub_info->usb_device->ddf_dev);
00100 if (opResult != EOK) {
00101 usb_log_error("Could not initialize connection to device, "
00102 " %s\n",
00103 str_error(opResult));
00104 free(hub_info);
00105 return opResult;
00106 }
00107
00108
00109 opResult = usb_hub_set_configuration(hub_info);
00110 if (opResult != EOK) {
00111 usb_log_error("Could not set hub configuration, %s\n",
00112 str_error(opResult));
00113 free(hub_info);
00114 return opResult;
00115 }
00116
00117 opResult = usb_hub_process_hub_specific_info(hub_info);
00118 if (opResult != EOK) {
00119 usb_log_error("Could process hub specific info, %s\n",
00120 str_error(opResult));
00121 free(hub_info);
00122 return opResult;
00123 }
00124
00125 usb_log_debug("Creating 'hub' function in DDF.\n");
00126 ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
00127 fun_exposed, "hub");
00128 assert(hub_fun != NULL);
00129 hub_fun->ops = NULL;
00130
00131 opResult = ddf_fun_bind(hub_fun);
00132 assert(opResult == EOK);
00133 opResult = ddf_fun_add_to_class(hub_fun, "hub");
00134 assert(opResult == EOK);
00135
00136 opResult = usb_hub_start_hub_fibril(hub_info);
00137 if (opResult != EOK)
00138 free(hub_info);
00139 return opResult;
00140 }
00141
00150 bool hub_port_changes_callback(usb_device_t *dev,
00151 uint8_t *change_bitmap, size_t change_bitmap_size, void *arg) {
00152 usb_log_debug("hub_port_changes_callback\n");
00153 usb_hub_info_t *hub = (usb_hub_info_t *) arg;
00154
00155
00156 if (change_bitmap_size == 0) {
00157 goto leave;
00158 }
00159
00160 bool change;
00161 change = ((uint8_t*) change_bitmap)[0] & 1;
00162 if (change) {
00163 usb_hub_process_global_interrupt(hub);
00164 }
00165
00166 size_t port;
00167 for (port = 1; port < hub->port_count + 1; port++) {
00168 bool change = (change_bitmap[port / 8] >> (port % 8)) % 2;
00169 if (change) {
00170 usb_hub_process_port_interrupt(hub, port);
00171 }
00172 }
00173 leave:
00174
00175 async_usleep(1000 * 250);
00176
00177 return true;
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00194 static usb_hub_info_t * usb_hub_info_create(usb_device_t *usb_dev) {
00195 usb_hub_info_t * result = malloc(sizeof (usb_hub_info_t));
00196 if (!result) return NULL;
00197 result->usb_device = usb_dev;
00198 result->status_change_pipe = usb_dev->pipes[0].pipe;
00199 result->control_pipe = &usb_dev->ctrl_pipe;
00200 result->is_default_address_used = false;
00201
00202 result->ports = NULL;
00203 result->port_count = (size_t) - 1;
00204 fibril_mutex_initialize(&result->port_mutex);
00205
00206 fibril_mutex_initialize(&result->pending_ops_mutex);
00207 fibril_condvar_initialize(&result->pending_ops_cv);
00208 result->pending_ops_count = 0;
00209 return result;
00210 }
00211
00222 static int usb_hub_process_hub_specific_info(usb_hub_info_t *hub_info) {
00223
00224 usb_log_debug("Creating serialized descriptor\n");
00225 uint8_t serialized_descriptor[USB_HUB_MAX_DESCRIPTOR_SIZE];
00226 usb_hub_descriptor_t * descriptor;
00227 int opResult;
00228
00229 size_t received_size;
00230 opResult = usb_request_get_descriptor(hub_info->control_pipe,
00231 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
00232 USB_DESCTYPE_HUB, 0, 0, serialized_descriptor,
00233 USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
00234
00235 if (opResult != EOK) {
00236 usb_log_error("Failed when receiving hub descriptor, "
00237 "%s\n",
00238 str_error(opResult));
00239 free(serialized_descriptor);
00240 return opResult;
00241 }
00242 usb_log_debug2("Deserializing descriptor\n");
00243 descriptor = usb_create_deserialized_hub_desriptor(
00244 serialized_descriptor);
00245 if (descriptor == NULL) {
00246 usb_log_warning("could not deserialize descriptor \n");
00247 return ENOMEM;
00248 }
00249 usb_log_debug("setting port count to %d\n", descriptor->ports_count);
00250 hub_info->port_count = descriptor->ports_count;
00251 bool is_power_switched =
00252 ((descriptor->hub_characteristics & 1) == 0);
00253 bool has_individual_port_powering =
00254 ((descriptor->hub_characteristics & 1) != 0);
00255 hub_info->ports = malloc(
00256 sizeof (usb_hub_port_t) * (hub_info->port_count + 1));
00257 if (!hub_info->ports) {
00258 return ENOMEM;
00259 }
00260 size_t port;
00261 for (port = 0; port < hub_info->port_count + 1; ++port) {
00262 usb_hub_port_init(&hub_info->ports[port]);
00263 }
00264 if (is_power_switched) {
00265 usb_log_debug("Hub power switched\n");
00266
00267 if (!has_individual_port_powering) {
00268
00269 usb_log_debug("Hub has global powering\n");
00270 }
00271
00272 for (port = 1; port <= hub_info->port_count; ++port) {
00273 usb_log_debug("Powering port %zu.\n", port);
00274 opResult = usb_hub_set_port_feature(hub_info->control_pipe,
00275 port, USB_HUB_FEATURE_PORT_POWER);
00276 if (opResult != EOK) {
00277 usb_log_error("Cannot power on port %zu: %s.\n",
00278 port, str_error(opResult));
00279 }
00280 }
00281
00282 } else {
00283 usb_log_debug("Power not switched, not going to be powered\n");
00284 }
00285 usb_log_debug2("Freeing data\n");
00286 free(descriptor);
00287 return EOK;
00288 }
00289
00298 static int usb_hub_set_configuration(usb_hub_info_t *hub_info) {
00299
00300 usb_standard_device_descriptor_t *std_descriptor
00301 = &hub_info->usb_device->descriptors.device;
00302 usb_log_debug("Hub has %d configurations\n",
00303 std_descriptor->configuration_count);
00304 if (std_descriptor->configuration_count < 1) {
00305 usb_log_error("There are no configurations available\n");
00306 return EINVAL;
00307 }
00308
00309 usb_standard_configuration_descriptor_t *config_descriptor
00310 = (usb_standard_configuration_descriptor_t *)
00311 hub_info->usb_device->descriptors.configuration;
00312
00313
00314 int opResult = usb_request_set_configuration(
00315 &hub_info->usb_device->ctrl_pipe,
00316 config_descriptor->configuration_number);
00317
00318 if (opResult != EOK) {
00319 usb_log_error("Failed to set hub configuration: %s.\n",
00320 str_error(opResult));
00321 return opResult;
00322 }
00323 usb_log_debug("\tUsed configuration %d\n",
00324 config_descriptor->configuration_number);
00325
00326 return EOK;
00327 }
00328
00338 static int usb_hub_start_hub_fibril(usb_hub_info_t *hub_info) {
00339 int rc;
00340
00341 rc = usb_device_auto_poll(hub_info->usb_device, 0,
00342 hub_port_changes_callback, ((hub_info->port_count + 1) / 8) + 1,
00343 usb_hub_polling_terminated_callback, hub_info);
00344 if (rc != EOK) {
00345 usb_log_error("Failed to create polling fibril: %s.\n",
00346 str_error(rc));
00347 free(hub_info);
00348 return rc;
00349 }
00350
00351 usb_log_info("Controlling hub `%s' (%zu ports).\n",
00352 hub_info->usb_device->ddf_dev->name, hub_info->port_count);
00353 return EOK;
00354 }
00355
00356
00357
00358
00359
00360
00361
00370 static int usb_process_hub_over_current(usb_hub_info_t *hub_info,
00371 usb_hub_status_t status) {
00372 int opResult;
00373 if (usb_hub_is_status(status, USB_HUB_FEATURE_HUB_OVER_CURRENT)) {
00374
00375 unsigned int port;
00376 for (port = 1; port <= hub_info->port_count; ++port) {
00377 opResult = usb_hub_clear_port_feature(
00378 hub_info->control_pipe, port,
00379 USB_HUB_FEATURE_PORT_POWER);
00380 if (opResult != EOK) {
00381 usb_log_warning(
00382 "Cannot power off port %d; %s\n",
00383 port, str_error(opResult));
00384 }
00385 }
00386 } else {
00387
00388 unsigned int port;
00389 for (port = 1; port <= hub_info->port_count; ++port) {
00390 opResult = usb_hub_set_port_feature(
00391 hub_info->control_pipe, port,
00392 USB_HUB_FEATURE_PORT_POWER);
00393 if (opResult != EOK) {
00394 usb_log_warning(
00395 "Cannot power off port %d; %s\n",
00396 port, str_error(opResult));
00397 }
00398 }
00399 }
00400 return opResult;
00401 }
00402
00411 static int usb_process_hub_local_power_change(usb_hub_info_t *hub_info,
00412 usb_hub_status_t status) {
00413 int opResult = EOK;
00414 opResult = usb_hub_clear_feature(hub_info->control_pipe,
00415 USB_HUB_FEATURE_C_HUB_LOCAL_POWER);
00416 if (opResult != EOK) {
00417 usb_log_error("Cannnot clear hub power change flag: "
00418 "%s\n",
00419 str_error(opResult));
00420 }
00421 return opResult;
00422 }
00423
00431 static void usb_hub_process_global_interrupt(usb_hub_info_t *hub_info) {
00432 usb_log_debug("Global interrupt on a hub\n");
00433 usb_pipe_t *pipe = hub_info->control_pipe;
00434 int opResult;
00435
00436 usb_port_status_t status;
00437 size_t rcvd_size;
00438 usb_device_request_setup_packet_t request;
00439
00440 usb_hub_set_hub_status_request(&request);
00441
00442
00443 opResult = usb_pipe_control_read(
00444 pipe,
00445 &request, sizeof (usb_device_request_setup_packet_t),
00446 &status, 4, &rcvd_size
00447 );
00448 if (opResult != EOK) {
00449 usb_log_error("Could not get hub status: %s\n",
00450 str_error(opResult));
00451 return;
00452 }
00453 if (rcvd_size != sizeof (usb_port_status_t)) {
00454 usb_log_error("Received status has incorrect size\n");
00455 return;
00456 }
00457
00458 if (
00459 usb_hub_is_status(status, 16 + USB_HUB_FEATURE_C_HUB_OVER_CURRENT)) {
00460 usb_process_hub_over_current(hub_info, status);
00461 }
00462 if (
00463 usb_hub_is_status(status, 16 + USB_HUB_FEATURE_C_HUB_LOCAL_POWER)) {
00464 usb_process_hub_local_power_change(hub_info, status);
00465 }
00466 }
00467
00476 static void usb_hub_polling_terminated_callback(usb_device_t *device,
00477 bool was_error, void *data) {
00478 usb_hub_info_t * hub = data;
00479 assert(hub);
00480
00481 fibril_mutex_lock(&hub->pending_ops_mutex);
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 if (hub->pending_ops_count > 0) {
00492 fibril_mutex_lock(&hub->port_mutex);
00493 size_t port;
00494 for (port = 0; port < hub->port_count; port++) {
00495 usb_hub_port_t *the_port = hub->ports + port;
00496 fibril_mutex_lock(&the_port->reset_mutex);
00497 the_port->reset_completed = true;
00498 the_port->reset_okay = false;
00499 fibril_condvar_broadcast(&the_port->reset_cv);
00500 fibril_mutex_unlock(&the_port->reset_mutex);
00501 }
00502 fibril_mutex_unlock(&hub->port_mutex);
00503 }
00504
00505 while (hub->pending_ops_count > 0) {
00506 fibril_condvar_wait(&hub->pending_ops_cv,
00507 &hub->pending_ops_mutex);
00508 }
00509 fibril_mutex_unlock(&hub->pending_ops_mutex);
00510
00511 usb_device_destroy(hub->usb_device);
00512
00513 free(hub->ports);
00514 free(hub);
00515 }
00516
00517
00518
00519