Update TODO list
[trut64.git] / libusb / usb.c
blob9b8773e11fbe49ded62b71c241a03b991e412646
1 /*
2 * Main API entry point
4 * Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
6 * This library is covered by the LGPL, read LICENSE for details.
7 */
9 #include <stdlib.h> /* getenv */
10 #include <stdio.h> /* stderr */
11 #include <string.h> /* strcmp */
12 #include <errno.h>
14 #include "usbi.h"
16 int usb_debug = 0;
17 struct usb_bus *usb_busses = NULL;
19 int usb_find_busses(void)
21 struct usb_bus *busses, *bus;
22 int ret, changes = 0;
24 ret = usb_os_find_busses(&busses);
25 if (ret < 0)
26 return ret;
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.
34 bus = usb_busses;
35 while (bus) {
36 int found = 0;
37 struct usb_bus *nbus, *tbus = bus->next;
39 nbus = busses;
40 while (nbus) {
41 struct usb_bus *tnbus = nbus->next;
43 if (!strcmp(bus->dirname, nbus->dirname)) {
44 /* Remove it from the new busses list */
45 LIST_DEL(busses, nbus);
47 usb_free_bus(nbus);
48 found = 1;
49 break;
52 nbus = tnbus;
55 if (!found) {
56 /* The bus was removed from the system */
57 LIST_DEL(usb_busses, bus);
58 usb_free_bus(bus);
59 changes++;
62 bus = tbus;
66 * Anything on the *busses list is new. So add them to usb_busses and
67 * process them like the new bus it is.
69 bus = busses;
70 while (bus) {
71 struct usb_bus *tbus = bus->next;
74 * Remove it from the temporary list first and add it to the real
75 * usb_busses list.
77 LIST_DEL(busses, bus);
79 LIST_ADD(usb_busses, bus);
81 changes++;
83 bus = tbus;
86 return changes;
89 int usb_find_devices(void)
91 struct usb_bus *bus;
92 int ret, changes = 0;
94 for (bus = usb_busses; bus; bus = bus->next) {
95 struct usb_device *devices, *dev;
97 /* Find all of the devices and put them into a temporary list */
98 ret = usb_os_find_devices(bus, &devices);
99 if (ret < 0)
100 return ret;
103 * Now walk through all of the devices we know about and compare
104 * against this new list. Any duplicates will be removed from the new
105 * list. If we don't find it in the new list, the device was removed.
106 * Any devices still in the new list, are new to us.
108 dev = bus->devices;
109 while (dev) {
110 int found = 0;
111 struct usb_device *ndev, *tdev = dev->next;
113 ndev = devices;
114 while (ndev) {
115 struct usb_device *tndev = ndev->next;
117 if (!strcmp(dev->filename, ndev->filename)) {
118 /* Remove it from the new devices list */
119 LIST_DEL(devices, ndev);
121 usb_free_dev(ndev);
122 found = 1;
123 break;
126 ndev = tndev;
129 if (!found) {
130 /* The device was removed from the system */
131 LIST_DEL(bus->devices, dev);
132 usb_free_dev(dev);
133 changes++;
136 dev = tdev;
140 * Anything on the *devices list is new. So add them to bus->devices and
141 * process them like the new device it is.
143 dev = devices;
144 while (dev) {
145 struct usb_device *tdev = dev->next;
148 * Remove it from the temporary list first and add it to the real
149 * bus->devices list.
151 LIST_DEL(devices, dev);
153 LIST_ADD(bus->devices, dev);
156 * Some ports fetch the descriptors on scanning (like Linux) so we don't
157 * need to fetch them again.
159 if (!dev->config) {
160 usb_dev_handle *udev;
162 udev = usb_open(dev);
163 if (udev) {
164 usb_fetch_and_parse_descriptors(udev);
166 usb_close(udev);
170 changes++;
172 dev = tdev;
175 usb_os_determine_children(bus);
178 return changes;
181 void usb_set_debug(int level)
183 if (usb_debug || level)
184 fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n",
185 level, level ? "on" : "off");
187 usb_debug = level;
190 void usb_init(void)
192 if (getenv("USB_DEBUG"))
193 usb_set_debug(atoi(getenv("USB_DEBUG")));
195 usb_os_init();
198 usb_dev_handle *usb_open(struct usb_device *dev)
200 usb_dev_handle *udev;
202 udev = malloc(sizeof(*udev));
203 if (!udev)
204 return NULL;
206 udev->fd = -1;
207 udev->device = dev;
208 udev->bus = dev->bus;
209 udev->config = udev->interface = udev->altsetting = -1;
211 if (usb_os_open(udev) < 0) {
212 free(udev);
213 return NULL;
216 return udev;
219 int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
220 size_t buflen)
223 * We can't use usb_get_descriptor() because it's lacking the index
224 * parameter. This will be fixed in libusb 1.0
226 return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
227 (USB_DT_STRING << 8) + index, langid, buf, buflen, 1000);
230 int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen)
232 char tbuf[255]; /* Some devices choke on size > 255 */
233 int ret, langid, si, di;
236 * Asking for the zero'th index is special - it returns a string
237 * descriptor that contains all the language IDs supported by the
238 * device. Typically there aren't many - often only one. The
239 * language IDs are 16 bit numbers, and they start at the third byte
240 * in the descriptor. See USB 2.0 specification, section 9.6.7, for
241 * more information on this. */
242 ret = usb_get_string(dev, 0, 0, tbuf, sizeof(tbuf));
243 if (ret < 0)
244 return ret;
246 if (ret < 4)
247 return -EIO;
249 langid = tbuf[2] | (tbuf[3] << 8);
251 ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf));
252 if (ret < 0)
253 return ret;
255 if (tbuf[1] != USB_DT_STRING)
256 return -EIO;
258 if (tbuf[0] > ret)
259 return -EFBIG;
261 for (di = 0, si = 2; si < tbuf[0]; si += 2) {
262 if (di >= (buflen - 1))
263 break;
265 if (tbuf[si + 1]) /* high byte */
266 buf[di++] = '?';
267 else
268 buf[di++] = tbuf[si];
271 buf[di] = 0;
273 return di;
276 int usb_close(usb_dev_handle *dev)
278 int ret;
280 ret = usb_os_close(dev);
281 free(dev);
283 return ret;
286 struct usb_device *usb_device(usb_dev_handle *dev)
288 return dev->device;
291 void usb_free_dev(struct usb_device *dev)
293 usb_destroy_configuration(dev);
294 free(dev->children);
295 free(dev);
298 struct usb_bus *usb_get_busses(void)
300 return usb_busses;
303 void usb_free_bus(struct usb_bus *bus)
305 free(bus);