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
00028
00035 #include <usb/classes/classes.h>
00036 #include <usbvirt/device.h>
00037 #include <errno.h>
00038 #include <str_error.h>
00039 #include <assert.h>
00040 #include <stdlib.h>
00041 #include <ddf/driver.h>
00042 #include <usb/debug.h>
00043
00044 #include "hub.h"
00045
00046
00049 #define MAKE_BYTE(b0, b1, b2, b3, b4, b5, b6, b7) \
00050 (( \
00051 ((b0) << 0) \
00052 | ((b1) << 1) \
00053 | ((b2) << 2) \
00054 | ((b3) << 3) \
00055 | ((b4) << 4) \
00056 | ((b5) << 5) \
00057 | ((b6) << 6) \
00058 | ((b7) << 7) \
00059 ))
00060
00061
00062 static hub_port_t *get_hub_port(hub_t *, size_t);
00063 static void set_port_status_change(hub_port_t *, hub_status_change_t);
00064 static void clear_port_status_change(hub_port_t *, uint16_t);
00065 static int set_port_state_delayed_fibril(void *);
00066 static void set_port_state_delayed(hub_t *, size_t, suseconds_t,
00067 hub_port_state_t, hub_port_state_t);
00068
00070 char hub_port_state_to_char(hub_port_state_t state) {
00071 switch (state) {
00072 case HUB_PORT_STATE_NOT_CONFIGURED:
00073 return '-';
00074 case HUB_PORT_STATE_POWERED_OFF:
00075 return 'O';
00076 case HUB_PORT_STATE_DISCONNECTED:
00077 return 'X';
00078 case HUB_PORT_STATE_DISABLED:
00079 return 'D';
00080 case HUB_PORT_STATE_RESETTING:
00081 return 'R';
00082 case HUB_PORT_STATE_ENABLED:
00083 return 'E';
00084 case HUB_PORT_STATE_SUSPENDED:
00085 return 'S';
00086 case HUB_PORT_STATE_RESUMING:
00087 return 'F';
00088 default:
00089 return '?';
00090 }
00091 }
00092
00098 static void hub_init_port(hub_port_t *port, hub_t *hub, size_t index)
00099 {
00100 port->connected_device = NULL;
00101 port->index = index;
00102 port->state = HUB_PORT_STATE_NOT_CONFIGURED;
00103 port->status_change = 0;
00104 port->hub = hub;
00105 }
00106
00111 void hub_init(hub_t *hub)
00112 {
00113 size_t i;
00114 for (i = 0; i < HUB_PORT_COUNT; i++) {
00115 hub_init_port(&hub->ports[i], hub, i + 1);
00116 }
00117 hub->custom_data = NULL;
00118 hub->signal_changes = true;
00119 fibril_mutex_initialize(&hub->guard);
00120 }
00121
00129 size_t hub_connect_device(hub_t *hub, void *device)
00130 {
00131 size_t i;
00132 for (i = 0; i < HUB_PORT_COUNT; i++) {
00133 hub_port_t *port = &hub->ports[i];
00134
00135 if (port->connected_device != NULL) {
00136 continue;
00137 }
00138
00139 port->connected_device = device;
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 port->state = HUB_PORT_STATE_DISABLED;
00150 set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
00151
00152
00153 return i;
00154 }
00155
00156 return (size_t) -1;
00157 }
00158
00165 int hub_disconnect_device(hub_t *hub, void *device)
00166 {
00167 size_t index = hub_find_device(hub, device);
00168 if (index == (size_t) -1) {
00169 return ENOENT;
00170 }
00171
00172 hub_port_t *port = &hub->ports[index];
00173
00174 port->connected_device = NULL;
00175 port->state = HUB_PORT_STATE_DISCONNECTED;
00176 set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
00177
00178 return EOK;
00179 }
00180
00188 size_t hub_find_device(hub_t *hub, void *device)
00189 {
00190 size_t i;
00191 for (i = 0; i < HUB_PORT_COUNT; i++) {
00192 hub_port_t *port = &hub->ports[i];
00193
00194 if (port->connected_device == device) {
00195 return i;
00196 }
00197 }
00198
00199 return -1;
00200 }
00201
00206 void hub_acquire(hub_t *hub)
00207 {
00208 fibril_mutex_lock(&hub->guard);
00209 }
00210
00215 void hub_release(hub_t *hub)
00216 {
00217 fibril_mutex_unlock(&hub->guard);
00218 }
00219
00226 void hub_set_port_state(hub_t *hub, size_t port_index, hub_port_state_t state)
00227 {
00228 hub_port_t *port = get_hub_port(hub, port_index);
00229 if (port == NULL) {
00230 return;
00231 }
00232
00233 usb_log_debug("Setting port %zu to state %d.\n", port_index, state);
00234
00235 switch (state) {
00236 case HUB_PORT_STATE_POWERED_OFF:
00237 clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
00238 clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
00239 clear_port_status_change(port, HUB_STATUS_C_PORT_RESET);
00240 break;
00241 case HUB_PORT_STATE_RESUMING:
00242 port->state = state;
00243 set_port_state_delayed(hub, port_index,
00244 10, state, HUB_PORT_STATE_ENABLED);
00245 break;
00246 case HUB_PORT_STATE_RESETTING:
00247 port->state = state;
00248 set_port_state_delayed(hub, port_index,
00249 10, state, HUB_PORT_STATE_ENABLED);
00250 break;
00251 case HUB_PORT_STATE_ENABLED:
00252 if (port->state == HUB_PORT_STATE_RESETTING) {
00253 set_port_status_change(port, HUB_STATUS_C_PORT_RESET);
00254 }
00255 break;
00256 default:
00257 break;
00258 }
00259
00260 port->state = state;
00261 }
00262
00268 void hub_set_port_state_all(hub_t *hub, hub_port_state_t state)
00269 {
00270 size_t i;
00271 for (i = 0; i < HUB_PORT_COUNT; i++) {
00272 hub_set_port_state(hub, i, state);
00273 }
00274 }
00275
00282 hub_port_state_t hub_get_port_state(hub_t *hub, size_t port_index)
00283 {
00284 hub_port_t *port = get_hub_port(hub, port_index);
00285 if (port == NULL) {
00286 return HUB_PORT_STATE_UNKNOWN;
00287 }
00288
00289 return port->state;
00290 }
00291
00298 void hub_clear_port_status_change(hub_t *hub, size_t port_index,
00299 hub_status_change_t change)
00300 {
00301 hub_port_t *port = get_hub_port(hub, port_index);
00302 if (port == NULL) {
00303 return;
00304 }
00305
00306 clear_port_status_change(port, change);
00307 }
00308
00315 uint16_t hub_get_port_status_change(hub_t *hub, size_t port_index)
00316 {
00317 hub_port_t *port = get_hub_port(hub, port_index);
00318 if (port == NULL) {
00319 return 0;
00320 }
00321
00322 return port->status_change;
00323 }
00324
00331 uint32_t hub_get_port_status(hub_t *hub, size_t port_index)
00332 {
00333 hub_port_t *port = get_hub_port(hub, port_index);
00334 if (port == NULL) {
00335 return 0;
00336 }
00337
00338 uint32_t status;
00339 status = MAKE_BYTE(
00340
00341 port->connected_device == NULL ? 0 : 1,
00342
00343 port->state == HUB_PORT_STATE_ENABLED ? 1 : 0,
00344
00345 (port->state == HUB_PORT_STATE_SUSPENDED)
00346 || (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,
00347
00348 0,
00349
00350 port->state == HUB_PORT_STATE_RESETTING ? 1 : 0,
00351
00352 0, 0, 0)
00353
00354 | (MAKE_BYTE(
00355
00356 port->state == HUB_PORT_STATE_POWERED_OFF ? 0 : 1,
00357
00358 0,
00359
00360 0, 0, 0, 0, 0, 0
00361 )) << 8;
00362
00363 status |= (port->status_change << 16);
00364
00365 return status;
00366 }
00367
00375 uint8_t hub_get_status_change_bitmap(hub_t *hub)
00376 {
00377 uint8_t change_map = 0;
00378
00379 size_t i;
00380 for (i = 0; i < HUB_PORT_COUNT; i++) {
00381 hub_port_t *port = &hub->ports[i];
00382
00383 if (port->status_change != 0) {
00384 change_map |= (1 << port->index);
00385 }
00386 }
00387
00388 return change_map;
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00405 static hub_port_t *get_hub_port(hub_t *hub, size_t port)
00406 {
00407 if (port >= HUB_PORT_COUNT) {
00408 return NULL;
00409 }
00410
00411 return &hub->ports[port];
00412 }
00413
00419 static void set_port_status_change(hub_port_t *port,
00420 hub_status_change_t change)
00421 {
00422 assert(port != NULL);
00423 uint16_t old_value = port->status_change;
00424 port->status_change |= change;
00425 usb_log_debug("Changing status change on %zu: %04x => %04x\n",
00426 port->index,
00427 (unsigned int) old_value, (unsigned int) port->status_change);
00428 port->hub->signal_changes = true;
00429 }
00430
00436 static void clear_port_status_change(hub_port_t *port,
00437 uint16_t change)
00438 {
00439 assert(port != NULL);
00440 port->status_change &= (~change);
00441 port->hub->signal_changes = true;
00442 }
00443
00445 struct delay_port_state_change {
00447 suseconds_t delay;
00449 hub_port_state_t old_state;
00451 hub_port_state_t new_state;
00453 size_t port;
00455 hub_t *hub;
00456 };
00457
00463 static int set_port_state_delayed_fibril(void *arg)
00464 {
00465 struct delay_port_state_change *change
00466 = (struct delay_port_state_change *) arg;
00467
00468 async_usleep(change->delay);
00469
00470 hub_acquire(change->hub);
00471
00472 hub_port_t *port = get_hub_port(change->hub, change->port);
00473 assert(port != NULL);
00474
00475 if (port->state == change->old_state) {
00476 hub_set_port_state(change->hub, change->port,
00477 change->new_state);
00478 }
00479
00480 hub_release(change->hub);
00481
00482 free(change);
00483
00484 return EOK;
00485 }
00486
00498 static void set_port_state_delayed(hub_t *hub, size_t port_index,
00499 suseconds_t delay_time_ms,
00500 hub_port_state_t old_state, hub_port_state_t new_state)
00501 {
00502 struct delay_port_state_change *change
00503 = malloc(sizeof(struct delay_port_state_change));
00504
00505 change->hub = hub;
00506 change->port = port_index;
00507 change->delay = delay_time_ms * 1000;
00508 change->old_state = old_state;
00509 change->new_state = new_state;
00510 fid_t fibril = fibril_create(set_port_state_delayed_fibril, change);
00511 if (fibril == 0) {
00512 printf("Failed to create fibril\n");
00513 free(change);
00514 return;
00515 }
00516 fibril_add_ready(fibril);
00517 }
00518
00519
00520