1 | /*
|
---|
2 | * Main API entry point
|
---|
3 | *
|
---|
4 | * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
|
---|
5 | *
|
---|
6 | * This library is covered by the LGPL, read LICENSE for details.
|
---|
7 | */
|
---|
8 |
|
---|
9 | #include <stdlib.h> /* getenv */
|
---|
10 | #include <stdio.h> /* stderr */
|
---|
11 | #include <string.h> /* strcmp */
|
---|
12 | #include <errno.h>
|
---|
13 |
|
---|
14 | #include "usbi.h"
|
---|
15 |
|
---|
16 | int usb_debug = 0;
|
---|
17 | struct usb_bus *_usb_busses = NULL;
|
---|
18 |
|
---|
19 | int usb_find_busses(void)
|
---|
20 | {
|
---|
21 | struct usb_bus *busses, *bus;
|
---|
22 | int ret, changes = 0;
|
---|
23 |
|
---|
24 | ret = usb_os_find_busses(&busses);
|
---|
25 | if (ret < 0)
|
---|
26 | return ret;
|
---|
27 |
|
---|
28 | /*
|
---|
29 | * Now walk through all of the busses we know about and compare against
|
---|
30 | * this new list. Any duplicates will be removed from the new list.
|
---|
31 | * If we don't find it in the new list, the bus was removed. Any
|
---|
32 | * busses still in the new list, are new to us.
|
---|
33 | */
|
---|
34 | bus = _usb_busses;
|
---|
35 | while (bus)
|
---|
36 | {
|
---|
37 | int found = 0;
|
---|
38 | struct usb_bus *nbus, *tbus = bus->next;
|
---|
39 |
|
---|
40 | nbus = busses;
|
---|
41 | while (nbus)
|
---|
42 | {
|
---|
43 | struct usb_bus *tnbus = nbus->next;
|
---|
44 |
|
---|
45 | if (!strcmp(bus->dirname, nbus->dirname))
|
---|
46 | {
|
---|
47 | /* Remove it from the new busses list */
|
---|
48 | LIST_DEL(busses, nbus);
|
---|
49 |
|
---|
50 | usb_free_bus(nbus);
|
---|
51 | found = 1;
|
---|
52 | break;
|
---|
53 | }
|
---|
54 |
|
---|
55 | nbus = tnbus;
|
---|
56 | }
|
---|
57 |
|
---|
58 | if (!found)
|
---|
59 | {
|
---|
60 | /* The bus was removed from the system */
|
---|
61 | LIST_DEL(_usb_busses, bus);
|
---|
62 | usb_free_bus(bus);
|
---|
63 | changes++;
|
---|
64 | }
|
---|
65 |
|
---|
66 | bus = tbus;
|
---|
67 | }
|
---|
68 |
|
---|
69 | /*
|
---|
70 | * Anything on the *busses list is new. So add them to usb_busses and
|
---|
71 | * process them like the new bus it is.
|
---|
72 | */
|
---|
73 | bus = busses;
|
---|
74 | while (bus)
|
---|
75 | {
|
---|
76 | struct usb_bus *tbus = bus->next;
|
---|
77 |
|
---|
78 | /*
|
---|
79 | * Remove it from the temporary list first and add it to the real
|
---|
80 | * usb_busses list.
|
---|
81 | */
|
---|
82 | LIST_DEL(busses, bus);
|
---|
83 |
|
---|
84 | LIST_ADD(_usb_busses, bus);
|
---|
85 |
|
---|
86 | changes++;
|
---|
87 |
|
---|
88 | bus = tbus;
|
---|
89 | }
|
---|
90 |
|
---|
91 | return changes;
|
---|
92 | }
|
---|
93 |
|
---|
94 | int usb_find_devices(void)
|
---|
95 | {
|
---|
96 | struct usb_bus *bus;
|
---|
97 | int ret, changes = 0;
|
---|
98 |
|
---|
99 | for (bus = usb_busses; bus; bus = bus->next)
|
---|
100 | {
|
---|
101 | struct usb_device *devices, *dev;
|
---|
102 |
|
---|
103 | /* Find all of the devices and put them into a temporary list */
|
---|
104 | ret = usb_os_find_devices(bus, &devices);
|
---|
105 | if (ret < 0)
|
---|
106 | return ret;
|
---|
107 |
|
---|
108 | /*
|
---|
109 | * Now walk through all of the devices we know about and compare
|
---|
110 | * against this new list. Any duplicates will be removed from the new
|
---|
111 | * list. If we don't find it in the new list, the device was removed.
|
---|
112 | * Any devices still in the new list, are new to us.
|
---|
113 | */
|
---|
114 | dev = bus->devices;
|
---|
115 | while (dev)
|
---|
116 | {
|
---|
117 | int found = 0;
|
---|
118 | struct usb_device *ndev, *tdev = dev->next;
|
---|
119 |
|
---|
120 | ndev = devices;
|
---|
121 | while (ndev)
|
---|
122 | {
|
---|
123 | struct usb_device *tndev = ndev->next;
|
---|
124 |
|
---|
125 | if (!strcmp(dev->filename, ndev->filename))
|
---|
126 | {
|
---|
127 | /* Remove it from the new devices list */
|
---|
128 | LIST_DEL(devices, ndev);
|
---|
129 |
|
---|
130 | usb_free_dev(ndev);
|
---|
131 | found = 1;
|
---|
132 | break;
|
---|
133 | }
|
---|
134 |
|
---|
135 | ndev = tndev;
|
---|
136 | }
|
---|
137 |
|
---|
138 | if (!found)
|
---|
139 | {
|
---|
140 | /* The device was removed from the system */
|
---|
141 | LIST_DEL(bus->devices, dev);
|
---|
142 | usb_free_dev(dev);
|
---|
143 | changes++;
|
---|
144 | }
|
---|
145 |
|
---|
146 | dev = tdev;
|
---|
147 | }
|
---|
148 |
|
---|
149 | /*
|
---|
150 | * Anything on the *devices list is new. So add them to bus->devices and
|
---|
151 | * process them like the new device it is.
|
---|
152 | */
|
---|
153 | dev = devices;
|
---|
154 | while (dev)
|
---|
155 | {
|
---|
156 | struct usb_device *tdev = dev->next;
|
---|
157 |
|
---|
158 | /*
|
---|
159 | * Remove it from the temporary list first and add it to the real
|
---|
160 | * bus->devices list.
|
---|
161 | */
|
---|
162 | LIST_DEL(devices, dev);
|
---|
163 |
|
---|
164 | /*
|
---|
165 | * Some ports fetch the descriptors on scanning (like Linux) so we don't
|
---|
166 | * need to fetch them again.
|
---|
167 | */
|
---|
168 | if (!dev->config)
|
---|
169 | {
|
---|
170 | usb_dev_handle *udev;
|
---|
171 |
|
---|
172 | udev = usb_open(dev);
|
---|
173 | if (udev)
|
---|
174 | {
|
---|
175 | usb_fetch_and_parse_descriptors(udev);
|
---|
176 |
|
---|
177 | usb_close(udev);
|
---|
178 | }
|
---|
179 | }
|
---|
180 |
|
---|
181 | // [ID:2928293 Tim Green]
|
---|
182 | //
|
---|
183 | if (dev->config)
|
---|
184 | {
|
---|
185 | LIST_ADD(bus->devices, dev);
|
---|
186 | changes++;
|
---|
187 | }
|
---|
188 |
|
---|
189 | dev = tdev;
|
---|
190 | }
|
---|
191 |
|
---|
192 | usb_os_determine_children(bus);
|
---|
193 | }
|
---|
194 |
|
---|
195 | return changes;
|
---|
196 | }
|
---|
197 |
|
---|
198 | void usb_init(void)
|
---|
199 | {
|
---|
200 | if (getenv("USB_DEBUG"))
|
---|
201 | usb_set_debug(atoi(getenv("USB_DEBUG")));
|
---|
202 |
|
---|
203 | usb_os_init();
|
---|
204 | }
|
---|
205 |
|
---|
206 | usb_dev_handle *usb_open(struct usb_device *dev)
|
---|
207 | {
|
---|
208 | usb_dev_handle *udev;
|
---|
209 |
|
---|
210 | udev = malloc(sizeof(*udev));
|
---|
211 | if (!udev)
|
---|
212 | return NULL;
|
---|
213 |
|
---|
214 | udev->fd = -1;
|
---|
215 | udev->device = dev;
|
---|
216 | udev->bus = dev->bus;
|
---|
217 | udev->config = udev->interface = udev->altsetting = -1;
|
---|
218 |
|
---|
219 | if (usb_os_open(udev) < 0)
|
---|
220 | {
|
---|
221 | free(udev);
|
---|
222 | return NULL;
|
---|
223 | }
|
---|
224 |
|
---|
225 | return udev;
|
---|
226 | }
|
---|
227 |
|
---|
228 | int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
|
---|
229 | size_t buflen)
|
---|
230 | {
|
---|
231 | /*
|
---|
232 | * We can't use usb_get_descriptor() because it's lacking the index
|
---|
233 | * parameter. This will be fixed in libusb 1.0
|
---|
234 | */
|
---|
235 | return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
|
---|
236 | (USB_DT_STRING << 8) + index, langid, buf, (int)buflen, 1000);
|
---|
237 | }
|
---|
238 |
|
---|
239 | int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen)
|
---|
240 | {
|
---|
241 | char tbuf[255]; /* Some devices choke on size > 255 */
|
---|
242 | int ret, langid, si, di;
|
---|
243 |
|
---|
244 | /*
|
---|
245 | * Asking for the zero'th index is special - it returns a string
|
---|
246 | * descriptor that contains all the language IDs supported by the
|
---|
247 | * device. Typically there aren't many - often only one. The
|
---|
248 | * language IDs are 16 bit numbers, and they start at the third byte
|
---|
249 | * in the descriptor. See USB 2.0 specification, section 9.6.7, for
|
---|
250 | * more information on this. */
|
---|
251 | ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf));
|
---|
252 | if (ret < 0)
|
---|
253 | return ret;
|
---|
254 |
|
---|
255 | if (ret < 4)
|
---|
256 | return -EIO;
|
---|
257 |
|
---|
258 | langid = tbuf[2] | (tbuf[3] << 8);
|
---|
259 |
|
---|
260 | ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf));
|
---|
261 | if (ret < 0)
|
---|
262 | return ret;
|
---|
263 |
|
---|
264 | if (tbuf[1] != USB_DT_STRING)
|
---|
265 | return -EIO;
|
---|
266 |
|
---|
267 | if (tbuf[0] > ret)
|
---|
268 | return -EFBIG;
|
---|
269 |
|
---|
270 | for (di = 0, si = 2; si < tbuf[0]; si += 2)
|
---|
271 | {
|
---|
272 | if (di >= ((int)buflen - 1))
|
---|
273 | break;
|
---|
274 |
|
---|
275 | if (tbuf[si + 1]) /* high byte */
|
---|
276 | buf[di++] = '?';
|
---|
277 | else
|
---|
278 | buf[di++] = tbuf[si];
|
---|
279 | }
|
---|
280 |
|
---|
281 | buf[di] = 0;
|
---|
282 |
|
---|
283 | return di;
|
---|
284 | }
|
---|
285 |
|
---|
286 | int usb_close(usb_dev_handle *dev)
|
---|
287 | {
|
---|
288 | int ret;
|
---|
289 |
|
---|
290 | ret = usb_os_close(dev);
|
---|
291 | free(dev);
|
---|
292 |
|
---|
293 | return ret;
|
---|
294 | }
|
---|
295 |
|
---|
296 | struct usb_device *usb_device(usb_dev_handle *dev)
|
---|
297 | {
|
---|
298 | return dev->device;
|
---|
299 | }
|
---|
300 |
|
---|
301 | void usb_free_dev(struct usb_device *dev)
|
---|
302 | {
|
---|
303 | usb_destroy_configuration(dev);
|
---|
304 | free(dev->children);
|
---|
305 | free(dev);
|
---|
306 | }
|
---|
307 |
|
---|
308 | struct usb_bus *usb_get_busses(void)
|
---|
309 | {
|
---|
310 | return _usb_busses;
|
---|
311 | }
|
---|
312 |
|
---|
313 | void usb_free_bus(struct usb_bus *bus)
|
---|
314 | {
|
---|
315 | free(bus);
|
---|
316 | }
|
---|
317 |
|
---|