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
16int usb_debug = 0;
17struct usb_bus *usb_busses = NULL;
18
19int 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    int found = 0;
37    struct usb_bus *nbus, *tbus = bus->next;
38
39    nbus = busses;
40    while (nbus) {
41      struct usb_bus *tnbus = nbus->next;
42
43      if (!strcmp(bus->dirname, nbus->dirname)) {
44        /* Remove it from the new busses list */
45        LIST_DEL(busses, nbus);
46
47        usb_free_bus(nbus);
48        found = 1;
49        break;
50      }
51
52      nbus = tnbus;
53    }
54
55    if (!found) {
56      /* The bus was removed from the system */
57      LIST_DEL(usb_busses, bus);
58      usb_free_bus(bus);
59      changes++;
60    }
61
62    bus = tbus;
63  }
64
65  /*
66   * Anything on the *busses list is new. So add them to usb_busses and
67   * process them like the new bus it is.
68   */
69  bus = busses;
70  while (bus) {
71    struct usb_bus *tbus = bus->next;
72
73    /*
74     * Remove it from the temporary list first and add it to the real
75     * usb_busses list.
76     */
77    LIST_DEL(busses, bus);
78
79    LIST_ADD(usb_busses, bus);
80
81    changes++;
82
83    bus = tbus;
84  }
85
86  return changes;
87}
88
89int usb_find_devices(void)
90{
91  struct usb_bus *bus;
92  int ret, changes = 0;
93
94  for (bus = usb_busses; bus; bus = bus->next) {
95    struct usb_device *devices, *dev;
96
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;
101
102    /*
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.
107     */
108    dev = bus->devices;
109    while (dev) {
110      int found = 0;
111      struct usb_device *ndev, *tdev = dev->next;
112
113      ndev = devices;
114      while (ndev) {
115        struct usb_device *tndev = ndev->next;
116
117        if (!strcmp(dev->filename, ndev->filename)) {
118          /* Remove it from the new devices list */
119          LIST_DEL(devices, ndev);
120
121          usb_free_dev(ndev);
122          found = 1;
123          break;
124        }
125
126        ndev = tndev;
127      }
128
129      if (!found) {
130        /* The device was removed from the system */
131        LIST_DEL(bus->devices, dev);
132        usb_free_dev(dev);
133        changes++;
134      }
135
136      dev = tdev;
137    }
138
139    /*
140     * Anything on the *devices list is new. So add them to bus->devices and
141     * process them like the new device it is.
142     */
143    dev = devices;
144    while (dev) {
145      struct usb_device *tdev = dev->next;
146
147      /*
148       * Remove it from the temporary list first and add it to the real
149       * bus->devices list.
150       */
151      LIST_DEL(devices, dev);
152
153      LIST_ADD(bus->devices, dev);
154
155      /*
156       * Some ports fetch the descriptors on scanning (like Linux) so we don't
157       * need to fetch them again.
158       */
159      if (!dev->config) {
160        usb_dev_handle *udev;
161
162        udev = usb_open(dev);
163        if (udev) {
164          usb_fetch_and_parse_descriptors(udev);
165
166          usb_close(udev);
167        }
168      }
169
170      changes++;
171
172      dev = tdev;
173    }
174
175    usb_os_determine_children(bus);
176  }
177
178  return changes;
179}
180
181void usb_set_debug(int level)
182{
183  if (usb_debug || level)
184    fprintf(stderr, "usb_set_debug: Setting debugging level to %d (%s)\n",
185	level, level ? "on" : "off");
186
187  usb_debug = level;
188}
189
190void usb_init(void)
191{
192  if (getenv("USB_DEBUG"))
193    usb_set_debug(atoi(getenv("USB_DEBUG")));
194
195  usb_os_init();
196}
197
198usb_dev_handle *usb_open(struct usb_device *dev)
199{
200  usb_dev_handle *udev;
201
202  udev = malloc(sizeof(*udev));
203  if (!udev)
204    return NULL;
205
206  udev->fd = -1;
207  udev->device = dev;
208  udev->bus = dev->bus;
209  udev->config = udev->interface = udev->altsetting = -1;
210
211  if (usb_os_open(udev) < 0) {
212    free(udev);
213    return NULL;
214  }
215
216  return udev;
217}
218
219int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
220	size_t buflen)
221{
222  /*
223   * We can't use usb_get_descriptor() because it's lacking the index
224   * parameter. This will be fixed in libusb 1.0
225   */
226  return usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
227			(USB_DT_STRING << 8) + index, langid, buf, buflen, 1000);
228}
229
230int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen)
231{
232  char tbuf[255];	/* Some devices choke on size > 255 */
233  int ret, langid, si, di;
234
235  /*
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;
245
246  if (ret < 4)
247    return -EIO;
248
249  langid = tbuf[2] | (tbuf[3] << 8);
250
251  ret = usb_get_string(dev, index, langid, tbuf, sizeof(tbuf));
252  if (ret < 0)
253    return ret;
254
255  if (tbuf[1] != USB_DT_STRING)
256    return -EIO;
257
258  if (tbuf[0] > ret)
259    return -EFBIG;
260
261  for (di = 0, si = 2; si < tbuf[0]; si += 2) {
262    if (di >= (buflen - 1))
263      break;
264
265    if (tbuf[si + 1])	/* high byte */
266      buf[di++] = '?';
267    else
268      buf[di++] = tbuf[si];
269  }
270
271  buf[di] = 0;
272
273  return di;
274}
275
276int usb_close(usb_dev_handle *dev)
277{
278  int ret;
279
280  ret = usb_os_close(dev);
281  free(dev);
282
283  return ret;
284}
285
286struct usb_device *usb_device(usb_dev_handle *dev)
287{
288  return dev->device;
289}
290
291void usb_free_dev(struct usb_device *dev)
292{
293  usb_destroy_configuration(dev);
294  free(dev->children);
295  free(dev);
296}
297
298struct usb_bus *usb_get_busses(void)
299{
300  return usb_busses;
301}
302
303void usb_free_bus(struct usb_bus *bus)
304{
305  free(bus);
306}
307
308