hub.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 Vojtech Horky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 /* Static functions. */
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                  * TODO:
00143                  * If the hub was configured, we can normally
00144                  * announce the plug-in.
00145                  * Otherwise, we will wait until hub is configured
00146                  * and announce changes in single burst.
00147                  */
00148                 //if (port->state == HUB_PORT_STATE_DISCONNECTED) {
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             /* Current connect status. */
00341             port->connected_device == NULL ? 0 : 1,
00342             /* Port enabled/disabled. */
00343             port->state == HUB_PORT_STATE_ENABLED ? 1 : 0,
00344             /* Suspend. */
00345             (port->state == HUB_PORT_STATE_SUSPENDED)
00346                 || (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,
00347             /* Over-current. */
00348             0,
00349             /* Reset. */
00350             port->state == HUB_PORT_STATE_RESETTING ? 1 : 0,
00351             /* Reserved. */
00352             0, 0, 0)
00353 
00354             | (MAKE_BYTE(
00355             /* Port power. */
00356             port->state == HUB_PORT_STATE_POWERED_OFF ? 0 : 1,
00357             /* Full-speed device. */
00358             0,
00359             /* Reserved. */
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  * STATIC (HELPER) FUNCTIONS
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 

Generated on Thu Jun 2 07:45:44 2011 for HelenOS/USB by  doxygen 1.4.7