source: mainline/uspace/lib/usb/src/hcdhubd.c@ 8f62b0f

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

Add example of usb_hc_async usage

The example simply sets address of the root hub.

  • Property mode set to 100644
File size: 7.4 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 libusb usb
30 * @{
31 */
32/** @file
33 * @brief HC driver and hub driver (implementation).
34 */
35#include <usb/hcdhubd.h>
36#include <usb/devreq.h>
37#include <usbhc_iface.h>
38#include <driver.h>
39#include <bool.h>
40#include <errno.h>
41
42#define USB_HUB_DEVICE_NAME "usbhub"
43
44/** List of handled host controllers. */
45static LIST_INITIALIZE(hc_list);
46
47/** Our HC driver. */
48static usb_hc_driver_t *hc_driver = NULL;
49
50static usbhc_iface_t usb_interface = {
51 .interrupt_out = NULL,
52 .interrupt_in = NULL
53};
54
55static device_ops_t usb_device_ops = {
56 .interfaces[USBHC_DEV_IFACE] = &usb_interface
57};
58
59static void set_hub_address(usb_hc_device_t *hc, usb_address_t address);
60
61/** Callback when new device is detected and must be handled by this driver.
62 *
63 * @param dev New device.
64 * @return Error code.
65 */
66static int add_device(device_t *dev)
67{
68 /*
69 * FIXME: use some magic to determine whether hub or another HC
70 * was connected.
71 */
72 bool is_hc = str_cmp(dev->name, USB_HUB_DEVICE_NAME) != 0;
73 printf("%s: add_device(name=\"%s\")\n", hc_driver->name, dev->name);
74
75 if (is_hc) {
76 /*
77 * We are the HC itself.
78 */
79 usb_hc_device_t *hc_dev = malloc(sizeof(usb_hc_device_t));
80 list_initialize(&hc_dev->link);
81 hc_dev->transfer_ops = NULL;
82
83 hc_dev->generic = dev;
84 dev->ops = &usb_device_ops;
85 hc_dev->generic->driver_data = hc_dev;
86
87 int rc = hc_driver->add_hc(hc_dev);
88 if (rc != EOK) {
89 free(hc_dev);
90 return rc;
91 }
92
93 /*
94 * FIXME: The following line causes devman to hang.
95 * Will investigate later why.
96 */
97 // add_device_to_class(dev, "usbhc");
98
99 list_append(&hc_dev->link, &hc_list);
100
101 return EOK;
102 } else {
103 usb_hc_device_t *hc = list_get_instance(hc_list.next, usb_hc_device_t, link);
104 set_hub_address(hc, 5);
105
106 /*
107 * We are some (probably deeply nested) hub.
108 * Thus, assign our own operations and explore already
109 * connected devices.
110 */
111
112 return ENOTSUP;
113 }
114}
115
116/** Sample usage of usb_hc_async functions.
117 * This function sets hub address using standard SET_ADDRESS request.
118 *
119 * @warning This function shall be removed once you are familiar with
120 * the usb_hc_ API.
121 *
122 * @param hc Host controller the hub belongs to.
123 * @param address New hub address.
124 */
125static void set_hub_address(usb_hc_device_t *hc, usb_address_t address)
126{
127 printf("%s: setting hub address to %d\n", hc->generic->name, address);
128 usb_target_t target = {0, 0};
129 usb_handle_t handle;
130 int rc;
131
132 usb_device_request_setup_packet_t setup_packet = {
133 .request_type = 0,
134 .request = USB_DEVREQ_SET_ADDRESS,
135 .index = 0,
136 .length = 0,
137 };
138 setup_packet.value = address;
139
140 rc = usb_hc_async_control_write_setup(hc, target,
141 &setup_packet, sizeof(setup_packet), &handle);
142 if (rc != EOK) {
143 return;
144 }
145
146 rc = usb_hc_async_wait_for(handle);
147 if (rc != EOK) {
148 return;
149 }
150
151 rc = usb_hc_async_control_write_status(hc, target, &handle);
152 if (rc != EOK) {
153 return;
154 }
155
156 rc = usb_hc_async_wait_for(handle);
157 if (rc != EOK) {
158 return;
159 }
160
161 printf("%s: hub address changed\n", hc->generic->name);
162}
163
164/** Check changes on all known hubs.
165 */
166static void check_hub_changes(void)
167{
168 /*
169 * Iterate through all HCs.
170 */
171 link_t *link_hc;
172 for (link_hc = hc_list.next;
173 link_hc != &hc_list;
174 link_hc = link_hc->next) {
175 usb_hc_device_t *hc = list_get_instance(link_hc,
176 usb_hc_device_t, link);
177 /*
178 * Iterate through all their hubs.
179 */
180 link_t *link_hub;
181 for (link_hub = hc->hubs.next;
182 link_hub != &hc->hubs;
183 link_hub = link_hub->next) {
184 usb_hcd_hub_info_t *hub = list_get_instance(link_hub,
185 usb_hcd_hub_info_t, link);
186
187 /*
188 * Check status change pipe of this hub.
189 */
190 usb_target_t target = {
191 .address = hub->device->address,
192 .endpoint = 1
193 };
194
195 // FIXME: count properly
196 size_t byte_length = (hub->port_count / 8) + 1;
197
198 void *change_bitmap = malloc(byte_length);
199 size_t actual_size;
200 usb_handle_t handle;
201
202 /*
203 * Send the request.
204 * FIXME: check returned value for possible errors
205 */
206 usb_hc_async_interrupt_in(hc, target,
207 change_bitmap, byte_length, &actual_size,
208 &handle);
209
210 usb_hc_async_wait_for(handle);
211
212 /*
213 * TODO: handle the changes.
214 */
215 }
216 }
217}
218
219/** Operations for combined HC and HUB driver. */
220static driver_ops_t hc_driver_generic_ops = {
221 .add_device = add_device
222};
223
224/** Combined HC and HUB driver. */
225static driver_t hc_driver_generic = {
226 .driver_ops = &hc_driver_generic_ops
227};
228
229/** Main USB host controller driver routine.
230 *
231 * @see driver_main
232 *
233 * @param hc Host controller driver.
234 * @return Error code.
235 */
236int usb_hcd_main(usb_hc_driver_t *hc)
237{
238 hc_driver = hc;
239 hc_driver_generic.name = hc->name;
240
241 /*
242 * Launch here fibril that will periodically check all
243 * attached hubs for status change.
244 * WARN: This call will effectively do nothing.
245 */
246 check_hub_changes();
247
248 /*
249 * Run the device driver framework.
250 */
251 return driver_main(&hc_driver_generic);
252}
253
254/** Add a root hub for given host controller.
255 * This function shall be called only once for each host controller driven
256 * by this driver.
257 * It takes care of creating child device - hub - that will be driven by
258 * this task.
259 *
260 * @param dev Host controller device.
261 * @return Error code.
262 */
263int usb_hcd_add_root_hub(usb_hc_device_t *dev)
264{
265 int rc;
266
267 /*
268 * Announce presence of child device.
269 */
270 device_t *hub = NULL;
271 match_id_t *match_id = NULL;
272
273 hub = create_device();
274 if (hub == NULL) {
275 rc = ENOMEM;
276 goto failure;
277 }
278 hub->name = USB_HUB_DEVICE_NAME;
279
280 match_id = create_match_id();
281 if (match_id == NULL) {
282 rc = ENOMEM;
283 goto failure;
284 }
285
286 char *id;
287 rc = asprintf(&id, "usb&hc=%s&hub", dev->generic->name);
288 if (rc <= 0) {
289 rc = ENOMEM;
290 goto failure;
291 }
292
293 match_id->id = id;
294 match_id->score = 30;
295
296 add_match_id(&hub->match_ids, match_id);
297
298 rc = child_device_register(hub, dev->generic);
299 if (rc != EOK) {
300 goto failure;
301 }
302
303 printf("%s: registered root hub\n", dev->generic->name);
304 return EOK;
305
306failure:
307 if (hub != NULL) {
308 hub->name = NULL;
309 delete_device(hub);
310 }
311 delete_match_id(match_id);
312
313 return rc;
314}
315
316/**
317 * @}
318 */
Note: See TracBrowser for help on using the repository browser.