source: mainline/uspace/lib/usb/src/recognise.c@ aa389fd

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since aa389fd 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: 10.4 KB
RevLine 
[02ccfcd]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
[3b77628]29/** @addtogroup libusb
[02ccfcd]30 * @{
31 */
32/** @file
33 * @brief Functions for recognising kind of attached devices.
34 */
[71ed4849]35#include <usb_iface.h>
[02ccfcd]36#include <usb/usbdrv.h>
37#include <usb/classes/classes.h>
38#include <stdio.h>
39#include <errno.h>
40
[3b77628]41/** Callback for getting host controller handle.
42 *
43 * @param dev Device in question.
44 * @param[out] handle Devman handle of the host controller.
45 * @return Error code.
46 */
[71ed4849]47static int usb_iface_get_hc_handle(device_t *dev, devman_handle_t *handle)
48{
49 assert(dev);
50 assert(dev->parent != NULL);
51
52 device_t *parent = dev->parent;
53
54 if (parent->ops && parent->ops->interfaces[USB_DEV_IFACE]) {
55 usb_iface_t *usb_iface
56 = (usb_iface_t *) parent->ops->interfaces[USB_DEV_IFACE];
57 assert(usb_iface != NULL);
58 if (usb_iface->get_hc_handle) {
59 int rc = usb_iface->get_hc_handle(parent, handle);
60 return rc;
61 }
62 }
63
64 return ENOTSUP;
65}
66
67static usb_iface_t usb_iface = {
68 .get_hc_handle = usb_iface_get_hc_handle
69};
70
71static device_ops_t child_ops = {
72 .interfaces[USB_DEV_IFACE] = &usb_iface
73};
[02ccfcd]74
75#define BCD_INT(a) (((unsigned int)(a)) / 256)
76#define BCD_FRAC(a) (((unsigned int)(a)) % 256)
77
78#define BCD_FMT "%x.%x"
79#define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
80
81/* FIXME: make this dynamic */
82#define MATCH_STRING_MAX 256
83
84/** Add formatted match id.
85 *
86 * @param matches List of match ids where to add to.
87 * @param score Score of the match.
88 * @param format Printf-like format
89 * @return Error code.
90 */
91static int usb_add_match_id(match_id_list_t *matches, int score,
92 const char *format, ...)
93{
94 char *match_str = NULL;
95 match_id_t *match_id = NULL;
96 int rc;
97
98 match_str = malloc(MATCH_STRING_MAX + 1);
99 if (match_str == NULL) {
100 rc = ENOMEM;
101 goto failure;
102 }
103
104 /*
105 * FIXME: replace with dynamic allocation of exact size
106 */
107 va_list args;
108 va_start(args, format );
109 vsnprintf(match_str, MATCH_STRING_MAX, format, args);
110 match_str[MATCH_STRING_MAX] = 0;
111 va_end(args);
112
113 match_id = create_match_id();
114 if (match_id == NULL) {
115 rc = ENOMEM;
116 goto failure;
117 }
118
119 match_id->id = match_str;
120 match_id->score = score;
121 add_match_id(matches, match_id);
122
123 return EOK;
124
125failure:
126 if (match_str != NULL) {
127 free(match_str);
128 }
129 if (match_id != NULL) {
130 match_id->id = NULL;
131 delete_match_id(match_id);
132 }
133
134 return rc;
135}
136
[692c0d3e]137/** Create DDF match ids from USB device descriptor.
138 *
139 * @param matches List of match ids to extend.
140 * @param device_descriptor Device descriptor returned by given device.
141 * @return Error code.
142 */
143int usb_drv_create_match_ids_from_device_descriptor(
144 match_id_list_t *matches,
145 const usb_standard_device_descriptor_t *device_descriptor)
146{
147 int rc;
148
149 /*
150 * Unless the vendor id is 0, the pair idVendor-idProduct
151 * quite uniquely describes the device.
152 */
153 if (device_descriptor->vendor_id != 0) {
154 /* First, with release number. */
155 rc = usb_add_match_id(matches, 100,
156 "usb&vendor=%d&product=%d&release=" BCD_FMT,
157 (int) device_descriptor->vendor_id,
158 (int) device_descriptor->product_id,
159 BCD_ARGS(device_descriptor->device_version));
160 if (rc != EOK) {
161 return rc;
162 }
163
164 /* Next, without release number. */
165 rc = usb_add_match_id(matches, 90, "usb&vendor=%d&product=%d",
166 (int) device_descriptor->vendor_id,
167 (int) device_descriptor->product_id);
168 if (rc != EOK) {
169 return rc;
170 }
171 }
172
173 /*
174 * If the device class points to interface we skip adding
175 * class directly.
176 */
177 if (device_descriptor->device_class != USB_CLASS_USE_INTERFACE) {
178 rc = usb_add_match_id(matches, 50, "usb&class=%s",
179 usb_str_class(device_descriptor->device_class));
180 if (rc != EOK) {
181 return rc;
182 }
183 }
184
185 return EOK;
186}
187
188/** Create DDF match ids from USB configuration descriptor.
189 * The configuration descriptor is expected to be in the complete form,
190 * i.e. including interface, endpoint etc. descriptors.
191 *
192 * @param matches List of match ids to extend.
193 * @param config_descriptor Configuration descriptor returned by given device.
194 * @param total_size Size of the @p config_descriptor.
195 * @return Error code.
196 */
197int usb_drv_create_match_ids_from_configuration_descriptor(
198 match_id_list_t *matches,
199 const void *config_descriptor, size_t total_size)
200{
201 /*
202 * Iterate through config descriptor to find the interface
203 * descriptors.
204 */
205 size_t position = sizeof(usb_standard_configuration_descriptor_t);
206 while (position + 1 < total_size) {
207 uint8_t *current_descriptor
208 = ((uint8_t *) config_descriptor) + position;
209 uint8_t cur_descr_len = current_descriptor[0];
210 uint8_t cur_descr_type = current_descriptor[1];
[d08abdb7]211
212 if (cur_descr_len == 0) {
213 return ENOENT;
214 }
[692c0d3e]215
216 position += cur_descr_len;
217
218 if (cur_descr_type != USB_DESCTYPE_INTERFACE) {
219 continue;
220 }
221
222 /*
223 * Finally, we found an interface descriptor.
224 */
225 usb_standard_interface_descriptor_t *interface
226 = (usb_standard_interface_descriptor_t *)
227 current_descriptor;
228
229 int rc = usb_add_match_id(matches, 50,
230 "usb&interface&class=%s",
231 usb_str_class(interface->interface_class));
232 if (rc != EOK) {
233 return rc;
234 }
235 }
236
237 return EOK;
238}
239
[a66225f3]240/** Add match ids based on configuration descriptor.
241 *
242 * @param hc Open phone to host controller.
243 * @param matches Match ids list to add matches to.
244 * @param address USB address of the attached device.
[3b77628]245 * @param config_count Number of configurations the device has.
[a66225f3]246 * @return Error code.
247 */
248static int usb_add_config_descriptor_match_ids(int hc,
249 match_id_list_t *matches, usb_address_t address,
250 int config_count)
251{
252 int final_rc = EOK;
253
254 int config_index;
255 for (config_index = 0; config_index < config_count; config_index++) {
256 int rc;
257 usb_standard_configuration_descriptor_t config_descriptor;
258 rc = usb_drv_req_get_bare_configuration_descriptor(hc,
259 address, config_index, &config_descriptor);
260 if (rc != EOK) {
261 final_rc = rc;
262 continue;
263 }
264
265 size_t full_config_descriptor_size;
266 void *full_config_descriptor
267 = malloc(config_descriptor.total_length);
268 rc = usb_drv_req_get_full_configuration_descriptor(hc,
269 address, config_index,
270 full_config_descriptor, config_descriptor.total_length,
271 &full_config_descriptor_size);
272 if (rc != EOK) {
273 final_rc = rc;
274 continue;
275 }
276 if (full_config_descriptor_size
277 != config_descriptor.total_length) {
278 final_rc = ERANGE;
279 continue;
280 }
[692c0d3e]281
282 rc = usb_drv_create_match_ids_from_configuration_descriptor(
283 matches,
284 full_config_descriptor, full_config_descriptor_size);
285 if (rc != EOK) {
286 final_rc = rc;
287 continue;
[a66225f3]288 }
[692c0d3e]289
[a66225f3]290 }
291
292 return final_rc;
293}
294
[02ccfcd]295/** Create match ids describing attached device.
296 *
297 * @warning The list of match ids @p matches may change even when
298 * function exits with error.
299 *
300 * @param hc Open phone to host controller.
301 * @param matches Initialized list of match ids.
302 * @param address USB address of the attached device.
303 * @return Error code.
304 */
305int usb_drv_create_device_match_ids(int hc, match_id_list_t *matches,
306 usb_address_t address)
307{
308 int rc;
[692c0d3e]309
310 /*
311 * Retrieve device descriptor and add matches from it.
312 */
[02ccfcd]313 usb_standard_device_descriptor_t device_descriptor;
314
315 rc = usb_drv_req_get_device_descriptor(hc, address,
316 &device_descriptor);
317 if (rc != EOK) {
318 return rc;
319 }
[692c0d3e]320
321 rc = usb_drv_create_match_ids_from_device_descriptor(matches,
322 &device_descriptor);
323 if (rc != EOK) {
324 return rc;
[a66225f3]325 }
[692c0d3e]326
[a66225f3]327 /*
328 * Go through all configurations and add matches
329 * based on interface class.
330 */
331 rc = usb_add_config_descriptor_match_ids(hc, matches,
332 address, device_descriptor.configuration_count);
333 if (rc != EOK) {
334 return rc;
[02ccfcd]335 }
336
337 /*
338 * As a fallback, provide the simplest match id possible.
339 */
340 rc = usb_add_match_id(matches, 1, "usb&fallback");
341 if (rc != EOK) {
342 return rc;
343 }
344
345 return EOK;
346}
347
[7ed5b576]348
[02ccfcd]349/** Probe for device kind and register it in devman.
350 *
[3b77628]351 * @param[in] hc Open phone to the host controller.
352 * @param[in] parent Parent device.
353 * @param[in] address Address of the (unknown) attached device.
354 * @param[out] child_handle Handle of the child device.
[02ccfcd]355 * @return Error code.
356 */
[7ed5b576]357int usb_drv_register_child_in_devman(int hc, device_t *parent,
358 usb_address_t address, devman_handle_t *child_handle)
[02ccfcd]359{
[b207803]360 static size_t device_name_index = 0;
361
[7ed5b576]362 device_t *child = NULL;
363 char *child_name = NULL;
364 int rc;
365
366 child = create_device();
367 if (child == NULL) {
368 rc = ENOMEM;
369 goto failure;
370 }
371
372 /*
[b207803]373 * TODO: Once the device driver framework support persistent
374 * naming etc., something more descriptive could be created.
[7ed5b576]375 */
[b207803]376 rc = asprintf(&child_name, "usbdev%02zu", device_name_index);
[7ed5b576]377 if (rc < 0) {
378 goto failure;
379 }
[71ed4849]380 child->parent = parent;
[7ed5b576]381 child->name = child_name;
[71ed4849]382 child->ops = &child_ops;
[7ed5b576]383
384 rc = usb_drv_create_device_match_ids(hc, &child->match_ids, address);
385 if (rc != EOK) {
386 goto failure;
387 }
388
389 rc = child_device_register(child, parent);
390 if (rc != EOK) {
391 goto failure;
392 }
393
394 if (child_handle != NULL) {
395 *child_handle = child->handle;
396 }
397
[b207803]398 device_name_index++;
399
[7ed5b576]400 return EOK;
401
402failure:
403 if (child != NULL) {
404 child->name = NULL;
405 /* This takes care of match_id deallocation as well. */
406 delete_device(child);
407 }
408 if (child_name != NULL) {
409 free(child_name);
410 }
411
412 return rc;
[02ccfcd]413
414}
[7ed5b576]415
[02ccfcd]416
417/**
418 * @}
419 */
Note: See TracBrowser for help on using the repository browser.