blob: a6b0867109460e137940c0347ff785b92c5a98a9 [file] [log] [blame]
Mike Lockwood30ff2c72010-05-09 16:23:47 -04001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <string.h>
21
22#include <sys/ioctl.h>
23#include <sys/types.h>
24#include <sys/time.h>
25#include <sys/inotify.h>
26#include <dirent.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <ctype.h>
30#include <pthread.h>
31
32#include <linux/usbdevice_fs.h>
33#include <linux/version.h>
34#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
35#include <linux/usb/ch9.h>
36#else
37#include <linux/usb_ch9.h>
38#endif
39#include <asm/byteorder.h>
40
41#include "usbhost/usbhost.h"
42
43#define USB_FS_DIR "/dev/bus/usb"
Mike Lockwood203f1022010-05-27 10:12:03 -040044#define USB_FS_ID_SCANNER "/dev/bus/usb/%d/%d"
Mike Lockwood30ff2c72010-05-09 16:23:47 -040045
46#if 0
47#define D printf
48#else
49#define D(...)
50#endif
51
Mike Lockwood6ac3aa12010-05-25 08:10:02 -040052struct usb_host_context {
53 usb_device_added_cb added_cb;
54 usb_device_removed_cb removed_cb;
55 void *client_data;
56};
57
Mike Lockwood30ff2c72010-05-09 16:23:47 -040058struct usb_device {
59 char dev_name[64];
60 unsigned char desc[256];
61 int desc_length;
62 int fd;
63 int writeable;
64};
65
66struct usb_endpoint
67{
68 struct usb_device *dev;
69 struct usb_endpoint_descriptor desc;
70 struct usbdevfs_urb urb;
71};
72
Mike Lockwood30ff2c72010-05-09 16:23:47 -040073static inline int badname(const char *name)
74{
75 while(*name) {
76 if(!isdigit(*name++)) return 1;
77 }
78 return 0;
79}
80
Mike Lockwood6ac3aa12010-05-25 08:10:02 -040081static void find_existing_devices(struct usb_host_context *context)
Mike Lockwood30ff2c72010-05-09 16:23:47 -040082{
83 char busname[32], devname[32];
84 DIR *busdir , *devdir ;
85 struct dirent *de;
86
87 busdir = opendir(USB_FS_DIR);
88 if(busdir == 0) return;
89
90 while((de = readdir(busdir)) != 0) {
91 if(badname(de->d_name)) continue;
92
93 snprintf(busname, sizeof busname, "%s/%s", USB_FS_DIR, de->d_name);
94 devdir = opendir(busname);
95 if(devdir == 0) continue;
96
97 while((de = readdir(devdir))) {
98 if(badname(de->d_name)) continue;
99
100 snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400101 context->added_cb(devname, context->client_data);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400102 } // end of devdir while
103 closedir(devdir);
104 } //end of busdir while
105 closedir(busdir);
106}
107
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400108static void* device_discovery_thread(void *client_data)
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400109{
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400110 struct usb_host_context *context = (struct usb_host_context *)client_data;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400111 struct inotify_event* event;
112 char event_buf[512];
113 char path[100];
114 int i, fd, ret;
115 int wd, wds[10];
116 int wd_count = sizeof(wds) / sizeof(wds[0]);
117
118 D("Created device discovery thread\n");
119
120 fd = inotify_init();
121 if (fd < 0) {
122 fprintf(stderr, "inotify_init failed\n");
123 return NULL;
124 }
125
126 /* watch for files added and deleted within USB_FS_DIR */
127 memset(wds, 0, sizeof(wds));
128 /* watch the root for new subdirectories */
129 wds[0] = inotify_add_watch(fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
130 if (wds[0] < 0) {
131 fprintf(stderr, "inotify_add_watch failed\n");
132 return NULL;
133 }
134
135 /* watch existing subdirectories of USB_FS_DIR */
136 for (i = 1; i < wd_count; i++) {
137 snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i);
138 ret = inotify_add_watch(fd, path, IN_CREATE | IN_DELETE);
139 if (ret > 0)
140 wds[i] = ret;
141 }
142
143 /* check for existing devices first, after we have inotify set up */
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400144 find_existing_devices(context);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400145
146 while (1) {
147 ret = read(fd, event_buf, sizeof(event_buf));
148 if (ret >= (int)sizeof(struct inotify_event)) {
149 event = (struct inotify_event *)event_buf;
150 wd = event->wd;
151 if (wd == wds[0]) {
152 i = atoi(event->name);
153 snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name);
154 D("new subdirectory %s: index: %d\n", path, i);
155 if (i > 0 && i < wd_count) {
156 ret = inotify_add_watch(fd, path, IN_CREATE | IN_DELETE);
157 if (ret > 0)
158 wds[i] = ret;
159 }
160 } else {
161 for (i = 1; i < wd_count; i++) {
162 if (wd == wds[i]) {
163 snprintf(path, sizeof(path), "%s/%03d/%s", USB_FS_DIR, i, event->name);
164 if (event->mask == IN_CREATE) {
165 D("new device %s\n", path);
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400166 context->added_cb(path, context->client_data);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400167 } else if (event->mask == IN_DELETE) {
168 D("gone device %s\n", path);
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400169 context->removed_cb(path, context->client_data);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400170 }
171 }
172 }
173 }
174 }
175 }
176 return NULL;
177}
178
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400179int usb_host_init(usb_device_added_cb added_cb, usb_device_removed_cb removed_cb, void *client_data)
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400180{
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400181 struct usb_host_context *context;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400182 pthread_t tid;
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400183 pthread_attr_t attr;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400184
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400185 if (!added_cb || !removed_cb)
186 return -EINVAL;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400187
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400188 context = calloc(1, sizeof(struct usb_host_context));
189 context->added_cb = added_cb;
190 context->removed_cb = removed_cb;
191 context->client_data = client_data;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400192
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400193 pthread_attr_init(&attr);
194 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
195 return pthread_create(&tid, &attr, device_discovery_thread, context);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400196}
197
198struct usb_device *usb_device_open(const char *dev_name)
199{
200 struct usb_device *device = calloc(1, sizeof(struct usb_device));
201 int fd, length, did_retry = 0;
202
203 strcpy(device->dev_name, dev_name);
204 device->writeable = 1;
205
206retry:
207 fd = open(dev_name, O_RDWR);
208 if (fd < 0) {
209 /* if we fail, see if have read-only access */
210 fd = open(dev_name, O_RDONLY);
211 if (fd < 0 && errno == EACCES && !did_retry) {
212 /* work around race condition between inotify and permissions management */
213 sleep(1);
214 did_retry = 1;
215 goto retry;
216 }
217
218 if (fd < 0) goto fail;
219 device->writeable = 0;
220 D("[ usb open read-only %s fd = %d]\n", dev_name, fd);
221 }
222
223 length = read(fd, device->desc, sizeof(device->desc));
224 if (length < 0)
225 goto fail;
226
227 device->fd = fd;
228 device->desc_length = length;
229 return device;
230fail:
231 close(fd);
232 free(device);
233 return NULL;
234}
235
236void usb_device_close(struct usb_device *device)
237{
238 close(device->fd);
239 free(device);
240}
241
242const char* usb_device_get_name(struct usb_device *device)
243{
244 return device->dev_name;
245}
246
Mike Lockwood203f1022010-05-27 10:12:03 -0400247int usb_device_get_unique_id(struct usb_device *device)
248{
249 int bus = 0, dev = 0;
250 sscanf(device->dev_name, USB_FS_ID_SCANNER, &bus, &dev);
251 return bus * 1000 + dev;
252}
253
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400254uint16_t usb_device_get_vendor_id(struct usb_device *device)
255{
256 struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc;
257 return __le16_to_cpu(desc->idVendor);
258}
259
260uint16_t usb_device_get_product_id(struct usb_device *device)
261{
262 struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc;
263 return __le16_to_cpu(desc->idProduct);
264}
265
266char* usb_device_get_string(struct usb_device *device, int id)
267{
268 char string[256];
269 struct usbdevfs_ctrltransfer ctrl;
270 __u16 buffer[128];
271 __u16 languages[128];
272 int i, result;
273 int languageCount = 0;
274
275 string[0] = 0;
276
277 // reading the string requires read/write permission
278 if (!device->writeable) {
279 int fd = open(device->dev_name, O_RDWR);
280 if (fd > 0) {
281 close(device->fd);
282 device->fd = fd;
283 device->writeable = 1;
284 } else {
285 return NULL;
286 }
287 }
288
289 memset(languages, 0, sizeof(languages));
290 memset(&ctrl, 0, sizeof(ctrl));
291
292 // read list of supported languages
293 ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
294 ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
295 ctrl.wValue = (USB_DT_STRING << 8) | 0;
296 ctrl.wIndex = 0;
297 ctrl.wLength = sizeof(languages);
298 ctrl.data = languages;
299
300 result = ioctl(device->fd, USBDEVFS_CONTROL, &ctrl);
301 if (result > 0)
302 languageCount = (result - 2) / 2;
303
304 for (i = 1; i <= languageCount; i++) {
305 memset(buffer, 0, sizeof(buffer));
306 memset(&ctrl, 0, sizeof(ctrl));
307
308 ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
309 ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
310 ctrl.wValue = (USB_DT_STRING << 8) | id;
311 ctrl.wIndex = languages[i];
312 ctrl.wLength = sizeof(buffer);
313 ctrl.data = buffer;
314
315 result = ioctl(device->fd, USBDEVFS_CONTROL, &ctrl);
316 if (result > 0) {
317 int i;
318 // skip first word, and copy the rest to the string, changing shorts to bytes.
319 result /= 2;
320 for (i = 1; i < result; i++)
321 string[i - 1] = buffer[i];
322 string[i - 1] = 0;
323 return strdup(string);
324 }
325 }
326
327 return NULL;
328}
329
330char* usb_device_get_manufacturer_name(struct usb_device *device)
331{
332 struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
333
334 if (desc->iManufacturer)
335 return usb_device_get_string(device, desc->iManufacturer);
336 else
337 return NULL;
338}
339
340char* usb_device_get_product_name(struct usb_device *device)
341{
342 struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
343
344 if (desc->iProduct)
345 return usb_device_get_string(device, desc->iProduct);
346 else
347 return NULL;
348}
349
350char* usb_device_get_serial(struct usb_device *device)
351{
352 struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
353
354 if (desc->iSerialNumber)
355 return usb_device_get_string(device, desc->iSerialNumber);
356 else
357 return NULL;
358}
359
360int usb_device_is_writeable(struct usb_device *device)
361{
362 return device->writeable;
363}
364
365void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter)
366{
367 iter->config = device->desc;
368 iter->config_end = device->desc + device->desc_length;
369 iter->curr_desc = device->desc;
370}
371
372struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter)
373{
374 struct usb_descriptor_header* next;
375 if (iter->curr_desc >= iter->config_end)
376 return NULL;
377 next = (struct usb_descriptor_header*)iter->curr_desc;
378 iter->curr_desc += next->bLength;
379 return next;
380}
381
382int usb_device_claim_interface(struct usb_device *device, unsigned int interface)
383{
384 return ioctl(device->fd, USBDEVFS_CLAIMINTERFACE, &interface);
385}
386
387int usb_device_release_interface(struct usb_device *device, unsigned int interface)
388{
389 return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface);
390}
391
392struct usb_endpoint *usb_endpoint_open(struct usb_device *dev,
393 const struct usb_endpoint_descriptor *desc)
394{
395 struct usb_endpoint *ep = calloc(1, sizeof(struct usb_endpoint));
396 memcpy(&ep->desc, desc, sizeof(ep->desc));
397 ep->dev = dev;
398 return ep;
399}
400
401void usb_endpoint_close(struct usb_endpoint *ep)
402{
403 // cancel IO here?
404 free(ep);
405}
406
407int usb_endpoint_queue(struct usb_endpoint *ep, void *data, int len)
408{
409 struct usbdevfs_urb *urb = &ep->urb;
410 int res;
411
412 D("usb_endpoint_queue\n");
413 memset(urb, 0, sizeof(*urb));
414 urb->type = USBDEVFS_URB_TYPE_BULK;
415 urb->endpoint = ep->desc.bEndpointAddress;
416 urb->status = -1;
417 urb->buffer = data;
418 urb->buffer_length = len;
419
420 do {
421 res = ioctl(ep->dev->fd, USBDEVFS_SUBMITURB, urb);
422 } while((res < 0) && (errno == EINTR));
423
424 return res;
425}
426
427int usb_endpoint_wait(struct usb_device *dev, int *out_ep_num)
428{
429 struct usbdevfs_urb *out = NULL;
430 int res;
431
432 while (1) {
433 res = ioctl(dev->fd, USBDEVFS_REAPURB, &out);
434 D("USBDEVFS_REAPURB returned %d\n", res);
435 if (res < 0) {
436 if(errno == EINTR) {
437 continue;
438 }
439 D("[ reap urb - error ]\n");
440 *out_ep_num = -1;
441 } else {
442 D("[ urb @%p status = %d, actual = %d ]\n",
443 out, out->status, out->actual_length);
444 res = out->actual_length;
445 *out_ep_num = out->endpoint;
446 }
447 break;
448 }
449 return res;
450}
451
452int usb_endpoint_cancel(struct usb_endpoint *ep)
453{
454 return ioctl(ep->dev->fd, USBDEVFS_DISCARDURB, &ep->urb);
455}
456
Mike Lockwood5e567cb2010-05-12 08:53:49 -0400457struct usb_device *usb_endpoint_get_device(struct usb_endpoint *ep)
458{
459 return ep->dev;
460}
461
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400462int usb_endpoint_number(struct usb_endpoint *ep)
463{
464 return ep->desc.bEndpointAddress;
465}
466
467int usb_endpoint_max_packet(struct usb_endpoint *ep)
468{
469 return __le16_to_cpu(ep->desc.wMaxPacketSize);
470}
471