source: mainline/uspace/lib/usb/src/hcdhubd.c@ 2f4438f5

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

Doxygen comment fixes

Mainly proper subgrouping and some missing @param comments.

  • Property mode set to 100644
File size: 8.6 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
30 * @{
31 */
32/** @file
33 * @brief Common stuff for both HC driver and hub driver.
34 */
35#include <usb/hcdhubd.h>
36#include <usb/devreq.h>
37#include <usbhc_iface.h>
38#include <usb_iface.h>
39#include <usb/descriptor.h>
40#include <driver.h>
41#include <bool.h>
42#include <errno.h>
43#include <str_error.h>
44#include <usb/classes/hub.h>
45
46#include "hcdhubd_private.h"
47
48
49static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle)
50{
51 assert(dev);
52 assert(dev->parent != NULL);
53
54 device_t *parent = dev->parent;
55
56 if (parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) {
57 usb_iface_t *usb_iface
58 = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE];
59 assert(usb_iface != NULL);
60 if (usb_iface->get_hc_handle) {
61 int rc = usb_iface->get_hc_handle(parent, handle);
62 return rc;
63 }
64 }
65
66 return ENOTSUP;
67}
68
69static usb_iface_t usb_iface = {
70 .get_hc_handle = usb_iface_get_hc_handle
71};
72
73static device_ops_t child_ops = {
74 .interfaces[USB_DEV_IFACE] = &usb_iface
75};
76
77/** Callback when new device is detected and must be handled by this driver.
78 *
79 * @param dev New device.
80 * @return Error code.
81 */
82static int add_device(device_t *dev) {
83 return ENOTSUP;
84}
85
86/** Operations for combined HC and HUB driver. */
87static driver_ops_t hc_driver_generic_ops = {
88 .add_device = add_device
89};
90
91/** Combined HC and HUB driver. */
92static driver_t hc_driver_generic = {
93 .driver_ops = &hc_driver_generic_ops
94};
95
96/** Main USB host controller driver routine.
97 *
98 * @see driver_main
99 *
100 * @param hc Host controller driver.
101 * @return Error code.
102 */
103int usb_hcd_main(usb_hc_driver_t *hc) {
104 hc_driver = hc;
105 hc_driver_generic.name = hc->name;
106
107 /*
108 * Run the device driver framework.
109 */
110 return driver_main(&hc_driver_generic);
111}
112
113/** Add a root hub for given host controller.
114 * This function shall be called only once for each host controller driven
115 * by this driver.
116 * It takes care of creating child device - hub - that will be driven by
117 * this task.
118 *
119 * @param dev Host controller device.
120 * @return Error code.
121 */
122int usb_hcd_add_root_hub(device_t *dev)
123{
124 char *id;
125 int rc = asprintf(&id, "usb&hub");
126 if (rc <= 0) {
127 return rc;
128 }
129
130 rc = usb_hc_add_child_device(dev, USB_HUB_DEVICE_NAME, id, true);
131 if (rc != EOK) {
132 free(id);
133 }
134
135 return rc;
136}
137
138/** Info about child device. */
139struct child_device_info {
140 device_t *parent;
141 const char *name;
142 const char *match_id;
143};
144
145/** Adds a child device fibril worker. */
146static int fibril_add_child_device(void *arg) {
147 struct child_device_info *child_info
148 = (struct child_device_info *) arg;
149 int rc;
150
151 async_usleep(1000);
152
153 device_t *child = create_device();
154 match_id_t *match_id = NULL;
155
156 if (child == NULL) {
157 rc = ENOMEM;
158 goto failure;
159 }
160 child->name = child_info->name;
161 child->parent = child_info->parent;
162 child->ops = &child_ops;
163
164 match_id = create_match_id();
165 if (match_id == NULL) {
166 rc = ENOMEM;
167 goto failure;
168 }
169 match_id->id = child_info->match_id;
170 match_id->score = 10;
171 add_match_id(&child->match_ids, match_id);
172
173 printf("%s: adding child device `%s' with match \"%s\"\n",
174 hc_driver->name, child->name, match_id->id);
175 rc = child_device_register(child, child_info->parent);
176 printf("%s: child device `%s' registration: %s\n",
177 hc_driver->name, child->name, str_error(rc));
178
179 if (rc != EOK) {
180 goto failure;
181 }
182
183 goto leave;
184
185failure:
186 if (child != NULL) {
187 child->name = NULL;
188 delete_device(child);
189 }
190
191 if (match_id != NULL) {
192 match_id->id = NULL;
193 delete_match_id(match_id);
194 }
195
196leave:
197 free(arg);
198 return EOK;
199}
200
201/** Adds a child.
202 * Due to deadlock in devman when parent registers child that oughts to be
203 * driven by the same task, the child adding is done in separate fibril.
204 * Not optimal, but it works.
205 * Update: not under all circumstances the new fibril is successful either.
206 * Thus the last parameter to let the caller choose.
207 *
208 * @param parent Parent device.
209 * @param name Device name.
210 * @param match_id Match id.
211 * @param create_fibril Whether to run the addition in new fibril.
212 * @return Error code.
213 */
214int usb_hc_add_child_device(device_t *parent, const char *name,
215 const char *match_id, bool create_fibril) {
216 printf("%s: about to add child device `%s' (%s)\n", hc_driver->name,
217 name, match_id);
218
219 /*
220 * Seems that creating fibril which postpones the action
221 * is the best solution.
222 */
223 create_fibril = true;
224
225 struct child_device_info *child_info
226 = malloc(sizeof (struct child_device_info));
227
228 child_info->parent = parent;
229 child_info->name = name;
230 child_info->match_id = match_id;
231
232 if (create_fibril) {
233 fid_t fibril = fibril_create(fibril_add_child_device, child_info);
234 if (!fibril) {
235 return ENOMEM;
236 }
237 fibril_add_ready(fibril);
238 } else {
239 fibril_add_child_device(child_info);
240 }
241
242 return EOK;
243}
244
245/** Tell USB address of given device.
246 *
247 * @param handle Devman handle of the device.
248 * @return USB device address or error code.
249 */
250usb_address_t usb_get_address_by_handle(devman_handle_t handle) {
251 /* TODO: search list of attached devices. */
252 return ENOENT;
253}
254
255usb_address_t usb_use_free_address(usb_hc_device_t * this_hcd) {
256 //is there free address?
257 link_t * addresses = &this_hcd->addresses;
258 if (list_empty(addresses)) return -1;
259 link_t * link_addr = addresses;
260 bool found = false;
261 usb_address_list_t * range = NULL;
262 while (!found) {
263 link_addr = link_addr->next;
264 if (link_addr == addresses) return -2;
265 range = list_get_instance(link_addr,
266 usb_address_list_t, link);
267 if (range->upper_bound - range->lower_bound > 0) {
268 found = true;
269 }
270 }
271 //now we have interval
272 int result = range->lower_bound;
273 ++(range->lower_bound);
274 if (range->upper_bound - range->lower_bound == 0) {
275 list_remove(&range->link);
276 free(range);
277 }
278 return result;
279}
280
281void usb_free_used_address(usb_hc_device_t * this_hcd, usb_address_t addr) {
282 //check range
283 if (addr < usb_lowest_address || addr > usb_highest_address)
284 return;
285 link_t * addresses = &this_hcd->addresses;
286 link_t * link_addr = addresses;
287 //find 'good' interval
288 usb_address_list_t * found_range = NULL;
289 bool found = false;
290 while (!found) {
291 link_addr = link_addr->next;
292 if (link_addr == addresses) {
293 found = true;
294 } else {
295 usb_address_list_t * range = list_get_instance(link_addr,
296 usb_address_list_t, link);
297 if ( (range->lower_bound - 1 == addr) ||
298 (range->upper_bound == addr)) {
299 found = true;
300 found_range = range;
301 }
302 if (range->lower_bound - 1 > addr) {
303 found = true;
304 }
305
306 }
307 }
308 if (found_range == NULL) {
309 //no suitable range found
310 usb_address_list_t * result_range =
311 (usb_address_list_t*) malloc(sizeof (usb_address_list_t));
312 result_range->lower_bound = addr;
313 result_range->upper_bound = addr + 1;
314 list_insert_before(&result_range->link, link_addr);
315 } else {
316 //we have good range
317 if (found_range->lower_bound - 1 == addr) {
318 --found_range->lower_bound;
319 } else {
320 //only one possible case
321 ++found_range->upper_bound;
322 if (found_range->link.next != addresses) {
323 usb_address_list_t * next_range =
324 list_get_instance( &found_range->link.next,
325 usb_address_list_t, link);
326 //check neighbour range
327 if (next_range->lower_bound == addr + 1) {
328 //join ranges
329 found_range->upper_bound = next_range->upper_bound;
330 list_remove(&next_range->link);
331 free(next_range);
332 }
333 }
334 }
335 }
336
337}
338
339/**
340 * @}
341 */
Note: See TracBrowser for help on using the repository browser.