[175] | 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 |
|
---|