source: mainline/uspace/drv/vhc/hub.c@ ecf52c4b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ecf52c4b was 138a7fd, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

Fixes & improvements in virtual hub

The changes includes:

  • unified (a bit) debugging output
  • port is put into power-off state after SET_CONFIGURATION request
  • less ports on the hub
  • delayed port changes run in separate fibril
  • shorter waiting for transactions in HC scheduling manager
  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 * Copyright (c) 2010 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup usb
30 * @{
31 */
32/** @file
33 * @brief Virtual USB hub.
34 */
35#include <usb/classes/classes.h>
36#include <usbvirt/hub.h>
37#include <usbvirt/device.h>
38#include <errno.h>
39#include <str_error.h>
40#include <stdlib.h>
41#include <driver.h>
42
43#include "vhcd.h"
44#include "hub.h"
45#include "hubintern.h"
46#include "conn.h"
47
48
49/** Standard device descriptor. */
50usb_standard_device_descriptor_t std_device_descriptor = {
51 .length = sizeof(usb_standard_device_descriptor_t),
52 .descriptor_type = USB_DESCTYPE_DEVICE,
53 .usb_spec_version = 0x110,
54 .device_class = USB_CLASS_HUB,
55 .device_subclass = 0,
56 .device_protocol = 0,
57 .max_packet_size = 64,
58 .configuration_count = 1
59};
60
61/** Standard interface descriptor. */
62usb_standard_interface_descriptor_t std_interface_descriptor = {
63 .length = sizeof(usb_standard_interface_descriptor_t),
64 .descriptor_type = USB_DESCTYPE_INTERFACE,
65 .interface_number = 0,
66 .alternate_setting = 0,
67 .endpoint_count = 1,
68 .interface_class = USB_CLASS_HUB,
69 .interface_subclass = 0,
70 .interface_protocol = 0,
71 .str_interface = 0
72};
73
74hub_descriptor_t hub_descriptor = {
75 .length = sizeof(hub_descriptor_t),
76 .type = USB_DESCTYPE_HUB,
77 .port_count = HUB_PORT_COUNT,
78 .characteristics = 0,
79 .power_on_warm_up = 50, /* Huh? */
80 .max_current = 100, /* Huh again. */
81 .removable_device = { 0 },
82 .port_power = { 0xFF }
83};
84
85/** Endpoint descriptor. */
86usb_standard_endpoint_descriptor_t endpoint_descriptor = {
87 .length = sizeof(usb_standard_endpoint_descriptor_t),
88 .descriptor_type = USB_DESCTYPE_ENDPOINT,
89 .endpoint_address = HUB_STATUS_CHANGE_PIPE | 128,
90 .attributes = USB_TRANSFER_INTERRUPT,
91 .max_packet_size = 8,
92 .poll_interval = 0xFF
93};
94
95/** Standard configuration descriptor. */
96usb_standard_configuration_descriptor_t std_configuration_descriptor = {
97 .length = sizeof(usb_standard_configuration_descriptor_t),
98 .descriptor_type = USB_DESCTYPE_CONFIGURATION,
99 .total_length =
100 sizeof(usb_standard_configuration_descriptor_t)
101 + sizeof(std_interface_descriptor)
102 + sizeof(hub_descriptor)
103 + sizeof(endpoint_descriptor)
104 ,
105 .interface_count = 1,
106 .configuration_number = HUB_CONFIGURATION_ID,
107 .str_configuration = 0,
108 .attributes = 128, /* denotes bus-powered device */
109 .max_power = 50
110};
111
112/** All hub configuration descriptors. */
113static usbvirt_device_configuration_extras_t extra_descriptors[] = {
114 {
115 .data = (uint8_t *) &std_interface_descriptor,
116 .length = sizeof(std_interface_descriptor)
117 },
118 {
119 .data = (uint8_t *) &hub_descriptor,
120 .length = sizeof(hub_descriptor)
121 },
122 {
123 .data = (uint8_t *) &endpoint_descriptor,
124 .length = sizeof(endpoint_descriptor)
125 }
126};
127
128/** Hub configuration. */
129usbvirt_device_configuration_t configuration = {
130 .descriptor = &std_configuration_descriptor,
131 .extra = extra_descriptors,
132 .extra_count = sizeof(extra_descriptors)/sizeof(extra_descriptors[0])
133};
134
135/** Hub standard descriptors. */
136usbvirt_descriptors_t descriptors = {
137 .device = &std_device_descriptor,
138 .configuration = &configuration,
139 .configuration_count = 1,
140};
141
142/** Hub as a virtual device. */
143usbvirt_device_t virthub_dev = {
144 .ops = &hub_ops,
145 .descriptors = &descriptors,
146 .lib_debug_level = 1,
147 .lib_debug_enabled_tags = USBVIRT_DEBUGTAG_ALL
148};
149
150/** Hub device. */
151hub_device_t hub_dev;
152
153static usb_address_t hub_set_address(usbvirt_device_t *hub)
154{
155 usb_address_t new_address;
156 int rc = vhc_iface.request_address(NULL, &new_address);
157 if (rc != EOK) {
158 return rc;
159 }
160
161 usb_device_request_setup_packet_t setup_packet = {
162 .request_type = 0,
163 .request = USB_DEVREQ_SET_ADDRESS,
164 .index = 0,
165 .length = 0,
166 };
167 setup_packet.value = new_address;
168
169 hub->transaction_setup(hub, 0, &setup_packet, sizeof(setup_packet));
170 hub->transaction_in(hub, 0, NULL, 0, NULL);
171
172 return new_address;
173}
174
175/** Initialize virtual hub. */
176void hub_init(device_t *hc_dev)
177{
178 size_t i;
179
180 for (i = 0; i < HUB_PORT_COUNT; i++) {
181 hub_port_t *port = &hub_dev.ports[i];
182
183 port->index = (int) i;
184 port->device = NULL;
185 port->state = HUB_PORT_STATE_NOT_CONFIGURED;
186 port->status_change = 0;
187 }
188
189 usbvirt_connect_local(&virthub_dev);
190
191 dprintf(1, "virtual hub (%d ports) created", HUB_PORT_COUNT);
192
193 usb_address_t hub_address = hub_set_address(&virthub_dev);
194 if (hub_address < 0) {
195 dprintf(1, "problem changing hub address (%s)",
196 str_error(hub_address));
197 }
198
199 dprintf(2, "virtual hub address changed to %d", hub_address);
200
201 char *id;
202 int rc = asprintf(&id, "usb&hub");
203 if (rc <= 0) {
204 return;
205 }
206 devman_handle_t hub_handle;
207 rc = child_device_register_wrapper(hc_dev, "hub", id, 10, &hub_handle);
208 if (rc != EOK) {
209 free(id);
210 }
211
212 vhc_iface.bind_address(NULL, hub_address, hub_handle);
213
214 dprintf(2, "virtual hub has devman handle %d", (int) hub_handle);
215}
216
217/** Connect device to the hub.
218 *
219 * @param device Device to be connected.
220 * @return Port where the device was connected to.
221 */
222size_t hub_add_device(virtdev_connection_t *device)
223{
224 size_t i;
225 for (i = 0; i < HUB_PORT_COUNT; i++) {
226 hub_port_t *port = &hub_dev.ports[i];
227
228 if (port->device != NULL) {
229 continue;
230 }
231
232 port->device = device;
233
234 /*
235 * TODO:
236 * If the hub was configured, we can normally
237 * announce the plug-in.
238 * Otherwise, we will wait until hub is configured
239 * and announce changes in single burst.
240 */
241 //if (port->state == HUB_PORT_STATE_DISCONNECTED) {
242 port->state = HUB_PORT_STATE_DISABLED;
243 set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
244 //}
245
246 return i;
247 }
248
249 return (size_t)-1;
250}
251
252/** Disconnect device from the hub. */
253void hub_remove_device(virtdev_connection_t *device)
254{
255 size_t i;
256 for (i = 0; i < HUB_PORT_COUNT; i++) {
257 hub_port_t *port = &hub_dev.ports[i];
258
259 if (port->device != device) {
260 continue;
261 }
262
263 port->device = NULL;
264 port->state = HUB_PORT_STATE_DISCONNECTED;
265
266 set_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
267 }
268}
269
270/** Tell whether device port is open.
271 *
272 * @return Whether communication to and from the device can go through the hub.
273 */
274bool hub_can_device_signal(virtdev_connection_t * device)
275{
276 size_t i;
277 for (i = 0; i < HUB_PORT_COUNT; i++) {
278 if (hub_dev.ports[i].device == device) {
279 return hub_dev.ports[i].state == HUB_PORT_STATE_ENABLED;
280 }
281 }
282
283 return false;
284}
285
286/** Format hub port status.
287 *
288 * @param result Buffer where to store status string.
289 * @param len Number of characters that is possible to store in @p result
290 * (excluding trailing zero).
291 */
292void hub_get_port_statuses(char *result, size_t len)
293{
294 if (len > HUB_PORT_COUNT) {
295 len = HUB_PORT_COUNT;
296 }
297 size_t i;
298 for (i = 0; i < len; i++) {
299 result[i] = hub_port_state_as_char(hub_dev.ports[i].state);
300 }
301 result[len] = 0;
302}
303
304/**
305 * @}
306 */
Note: See TracBrowser for help on using the repository browser.