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

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

Interface class specification added to match id

  • Property mode set to 100644
File size: 7.9 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
29/** @addtogroup libusb usb
30 * @{
31 */
32/** @file
33 * @brief Functions for recognising kind of attached devices.
34 */
35#include <usb/usbdrv.h>
36#include <usb/classes/classes.h>
37#include <stdio.h>
38#include <errno.h>
39
40
41#define BCD_INT(a) (((unsigned int)(a)) / 256)
42#define BCD_FRAC(a) (((unsigned int)(a)) % 256)
43
44#define BCD_FMT "%x.%x"
45#define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
46
47/* FIXME: make this dynamic */
48#define MATCH_STRING_MAX 256
49
50/** Add formatted match id.
51 *
52 * @param matches List of match ids where to add to.
53 * @param score Score of the match.
54 * @param format Printf-like format
55 * @return Error code.
56 */
57static int usb_add_match_id(match_id_list_t *matches, int score,
58 const char *format, ...)
59{
60 char *match_str = NULL;
61 match_id_t *match_id = NULL;
62 int rc;
63
64 match_str = malloc(MATCH_STRING_MAX + 1);
65 if (match_str == NULL) {
66 rc = ENOMEM;
67 goto failure;
68 }
69
70 /*
71 * FIXME: replace with dynamic allocation of exact size
72 */
73 va_list args;
74 va_start(args, format );
75 vsnprintf(match_str, MATCH_STRING_MAX, format, args);
76 match_str[MATCH_STRING_MAX] = 0;
77 va_end(args);
78
79 match_id = create_match_id();
80 if (match_id == NULL) {
81 rc = ENOMEM;
82 goto failure;
83 }
84
85 match_id->id = match_str;
86 match_id->score = score;
87 add_match_id(matches, match_id);
88
89 return EOK;
90
91failure:
92 if (match_str != NULL) {
93 free(match_str);
94 }
95 if (match_id != NULL) {
96 match_id->id = NULL;
97 delete_match_id(match_id);
98 }
99
100 return rc;
101}
102
[a66225f3]103/** Add match ids based on configuration descriptor.
104 *
105 * @param hc Open phone to host controller.
106 * @param matches Match ids list to add matches to.
107 * @param address USB address of the attached device.
108 * @return Error code.
109 */
110static int usb_add_config_descriptor_match_ids(int hc,
111 match_id_list_t *matches, usb_address_t address,
112 int config_count)
113{
114 int final_rc = EOK;
115
116 int config_index;
117 for (config_index = 0; config_index < config_count; config_index++) {
118 int rc;
119 usb_standard_configuration_descriptor_t config_descriptor;
120 rc = usb_drv_req_get_bare_configuration_descriptor(hc,
121 address, config_index, &config_descriptor);
122 if (rc != EOK) {
123 final_rc = rc;
124 continue;
125 }
126
127 size_t full_config_descriptor_size;
128 void *full_config_descriptor
129 = malloc(config_descriptor.total_length);
130 rc = usb_drv_req_get_full_configuration_descriptor(hc,
131 address, config_index,
132 full_config_descriptor, config_descriptor.total_length,
133 &full_config_descriptor_size);
134 if (rc != EOK) {
135 final_rc = rc;
136 continue;
137 }
138 if (full_config_descriptor_size
139 != config_descriptor.total_length) {
140 final_rc = ERANGE;
141 continue;
142 }
143
144 /*
145 * Iterate through config descriptor to find the interface
146 * descriptors.
147 */
148 size_t position = sizeof(config_descriptor);
149 while (position + 1 < full_config_descriptor_size) {
150 uint8_t *current_descriptor
151 = ((uint8_t *) full_config_descriptor) + position;
152 uint8_t cur_descr_len = current_descriptor[0];
153 uint8_t cur_descr_type = current_descriptor[1];
154
155 position += cur_descr_len;
156
157 if (cur_descr_type != USB_DESCTYPE_INTERFACE) {
158 continue;
159 }
160 /*
161 * Finally, we found an interface descriptor.
162 */
163 usb_standard_interface_descriptor_t *interface
164 = (usb_standard_interface_descriptor_t *)
165 current_descriptor;
166
167 rc = usb_add_match_id(matches, 50,
168 "usb&interface&class=%s",
169 usb_str_class(interface->interface_class));
170 if (rc != EOK) {
171 final_rc = rc;
172 break;
173 }
174 }
175 }
176
177 return final_rc;
178}
179
[02ccfcd]180/** Create match ids describing attached device.
181 *
182 * @warning The list of match ids @p matches may change even when
183 * function exits with error.
184 *
185 * @param hc Open phone to host controller.
186 * @param matches Initialized list of match ids.
187 * @param address USB address of the attached device.
188 * @return Error code.
189 */
190int usb_drv_create_device_match_ids(int hc, match_id_list_t *matches,
191 usb_address_t address)
192{
193 int rc;
194 usb_standard_device_descriptor_t device_descriptor;
195
196 rc = usb_drv_req_get_device_descriptor(hc, address,
197 &device_descriptor);
198 if (rc != EOK) {
199 return rc;
200 }
201
202 /*
203 * Unless the vendor id is 0, the pair idVendor-idProduct
204 * quite uniquely describes the device.
205 */
206 if (device_descriptor.vendor_id != 0) {
207 /* First, with release number. */
208 rc = usb_add_match_id(matches, 100,
209 "usb&vendor=%d&product=%d&release=" BCD_FMT,
210 (int) device_descriptor.vendor_id,
211 (int) device_descriptor.product_id,
212 BCD_ARGS(device_descriptor.device_version));
213 if (rc != EOK) {
214 return rc;
215 }
216
217 /* Next, without release number. */
218 rc = usb_add_match_id(matches, 90, "usb&vendor=%d&product=%d",
219 (int) device_descriptor.vendor_id,
220 (int) device_descriptor.product_id);
221 if (rc != EOK) {
222 return rc;
223 }
224
225 }
226
227 /*
[a66225f3]228 * If the device class points to interface we skip adding
229 * class directly.
[02ccfcd]230 */
231 if (device_descriptor.device_class != USB_CLASS_USE_INTERFACE) {
232 rc = usb_add_match_id(matches, 50, "usb&class=%s",
233 usb_str_class(device_descriptor.device_class));
234 if (rc != EOK) {
235 return rc;
236 }
[a66225f3]237 }
238 /*
239 * Go through all configurations and add matches
240 * based on interface class.
241 */
242 rc = usb_add_config_descriptor_match_ids(hc, matches,
243 address, device_descriptor.configuration_count);
244 if (rc != EOK) {
245 return rc;
[02ccfcd]246 }
247
248 /*
249 * As a fallback, provide the simplest match id possible.
250 */
251 rc = usb_add_match_id(matches, 1, "usb&fallback");
252 if (rc != EOK) {
253 return rc;
254 }
255
256 return EOK;
257}
258
[7ed5b576]259
[02ccfcd]260/** Probe for device kind and register it in devman.
261 *
262 * @param hc Open phone to the host controller.
[7ed5b576]263 * @param parent Parent device.
[02ccfcd]264 * @param address Address of the (unknown) attached device.
265 * @return Error code.
266 */
[7ed5b576]267int usb_drv_register_child_in_devman(int hc, device_t *parent,
268 usb_address_t address, devman_handle_t *child_handle)
[02ccfcd]269{
[7ed5b576]270 device_t *child = NULL;
271 char *child_name = NULL;
272 int rc;
273
274 child = create_device();
275 if (child == NULL) {
276 rc = ENOMEM;
277 goto failure;
278 }
279
280 /*
281 * TODO: some better child naming
282 */
283 rc = asprintf(&child_name, "usb%p", child);
284 if (rc < 0) {
285 goto failure;
286 }
287 child->name = child_name;
288
289 rc = usb_drv_create_device_match_ids(hc, &child->match_ids, address);
290 if (rc != EOK) {
291 goto failure;
292 }
293
294 rc = child_device_register(child, parent);
295 if (rc != EOK) {
296 goto failure;
297 }
298
299 if (child_handle != NULL) {
300 *child_handle = child->handle;
301 }
302
303 return EOK;
304
305failure:
306 if (child != NULL) {
307 child->name = NULL;
308 /* This takes care of match_id deallocation as well. */
309 delete_device(child);
310 }
311 if (child_name != NULL) {
312 free(child_name);
313 }
314
315 return rc;
[02ccfcd]316
317}
[7ed5b576]318
[02ccfcd]319
320/**
321 * @}
322 */
Note: See TracBrowser for help on using the repository browser.