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

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

Merge development/ changes

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