blob: 1d83a3903a0b5a7a5f8ebd081bae931deb918c4c [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
Mike Lockwoode15af092010-06-10 10:20:49 -040017// #define DEBUG 1
18#if DEBUG
19
20#ifdef USE_LIBLOG
21#define LOG_TAG "usbhost"
22#include "utils/Log.h"
23#define D LOGD
24#else
25#define D printf
26#endif
27
28#else
29#define D(...)
30#endif
31
Mike Lockwood30ff2c72010-05-09 16:23:47 -040032#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <string.h>
36
37#include <sys/ioctl.h>
38#include <sys/types.h>
39#include <sys/time.h>
40#include <sys/inotify.h>
41#include <dirent.h>
42#include <fcntl.h>
43#include <errno.h>
44#include <ctype.h>
45#include <pthread.h>
46
47#include <linux/usbdevice_fs.h>
48#include <linux/version.h>
49#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
50#include <linux/usb/ch9.h>
51#else
52#include <linux/usb_ch9.h>
53#endif
54#include <asm/byteorder.h>
55
56#include "usbhost/usbhost.h"
57
58#define USB_FS_DIR "/dev/bus/usb"
Mike Lockwood203f1022010-05-27 10:12:03 -040059#define USB_FS_ID_SCANNER "/dev/bus/usb/%d/%d"
Mike Lockwood30ff2c72010-05-09 16:23:47 -040060
Mike Lockwood30ff2c72010-05-09 16:23:47 -040061
Mike Lockwood6ac3aa12010-05-25 08:10:02 -040062struct usb_host_context {
63 usb_device_added_cb added_cb;
64 usb_device_removed_cb removed_cb;
65 void *client_data;
66};
67
Mike Lockwood30ff2c72010-05-09 16:23:47 -040068struct usb_device {
69 char dev_name[64];
70 unsigned char desc[256];
71 int desc_length;
72 int fd;
73 int writeable;
74};
75
76struct usb_endpoint
77{
78 struct usb_device *dev;
79 struct usb_endpoint_descriptor desc;
80 struct usbdevfs_urb urb;
81};
82
Mike Lockwood30ff2c72010-05-09 16:23:47 -040083static inline int badname(const char *name)
84{
85 while(*name) {
86 if(!isdigit(*name++)) return 1;
87 }
88 return 0;
89}
90
Mike Lockwood6ac3aa12010-05-25 08:10:02 -040091static void find_existing_devices(struct usb_host_context *context)
Mike Lockwood30ff2c72010-05-09 16:23:47 -040092{
93 char busname[32], devname[32];
94 DIR *busdir , *devdir ;
95 struct dirent *de;
96
97 busdir = opendir(USB_FS_DIR);
98 if(busdir == 0) return;
99
100 while((de = readdir(busdir)) != 0) {
101 if(badname(de->d_name)) continue;
102
103 snprintf(busname, sizeof busname, "%s/%s", USB_FS_DIR, de->d_name);
104 devdir = opendir(busname);
105 if(devdir == 0) continue;
106
107 while((de = readdir(devdir))) {
108 if(badname(de->d_name)) continue;
109
110 snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400111 context->added_cb(devname, context->client_data);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400112 } // end of devdir while
113 closedir(devdir);
114 } //end of busdir while
115 closedir(busdir);
116}
117
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400118static void* device_discovery_thread(void *client_data)
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400119{
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400120 struct usb_host_context *context = (struct usb_host_context *)client_data;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400121 struct inotify_event* event;
122 char event_buf[512];
123 char path[100];
124 int i, fd, ret;
125 int wd, wds[10];
126 int wd_count = sizeof(wds) / sizeof(wds[0]);
127
128 D("Created device discovery thread\n");
129
130 fd = inotify_init();
131 if (fd < 0) {
132 fprintf(stderr, "inotify_init failed\n");
133 return NULL;
134 }
135
136 /* watch for files added and deleted within USB_FS_DIR */
137 memset(wds, 0, sizeof(wds));
138 /* watch the root for new subdirectories */
139 wds[0] = inotify_add_watch(fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
140 if (wds[0] < 0) {
141 fprintf(stderr, "inotify_add_watch failed\n");
142 return NULL;
143 }
144
145 /* watch existing subdirectories of USB_FS_DIR */
146 for (i = 1; i < wd_count; i++) {
147 snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i);
148 ret = inotify_add_watch(fd, path, IN_CREATE | IN_DELETE);
149 if (ret > 0)
150 wds[i] = ret;
151 }
152
153 /* check for existing devices first, after we have inotify set up */
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400154 find_existing_devices(context);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400155
156 while (1) {
157 ret = read(fd, event_buf, sizeof(event_buf));
158 if (ret >= (int)sizeof(struct inotify_event)) {
159 event = (struct inotify_event *)event_buf;
160 wd = event->wd;
161 if (wd == wds[0]) {
162 i = atoi(event->name);
163 snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name);
164 D("new subdirectory %s: index: %d\n", path, i);
165 if (i > 0 && i < wd_count) {
166 ret = inotify_add_watch(fd, path, IN_CREATE | IN_DELETE);
167 if (ret > 0)
168 wds[i] = ret;
169 }
170 } else {
171 for (i = 1; i < wd_count; i++) {
172 if (wd == wds[i]) {
173 snprintf(path, sizeof(path), "%s/%03d/%s", USB_FS_DIR, i, event->name);
174 if (event->mask == IN_CREATE) {
175 D("new device %s\n", path);
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400176 context->added_cb(path, context->client_data);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400177 } else if (event->mask == IN_DELETE) {
178 D("gone device %s\n", path);
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400179 context->removed_cb(path, context->client_data);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400180 }
181 }
182 }
183 }
184 }
185 }
186 return NULL;
187}
188
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400189int 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 -0400190{
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400191 struct usb_host_context *context;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400192 pthread_t tid;
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400193 pthread_attr_t attr;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400194
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400195 if (!added_cb || !removed_cb)
196 return -EINVAL;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400197
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400198 context = calloc(1, sizeof(struct usb_host_context));
199 context->added_cb = added_cb;
200 context->removed_cb = removed_cb;
201 context->client_data = client_data;
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400202
Mike Lockwood6ac3aa12010-05-25 08:10:02 -0400203 pthread_attr_init(&attr);
204 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
205 return pthread_create(&tid, &attr, device_discovery_thread, context);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400206}
207
208struct usb_device *usb_device_open(const char *dev_name)
209{
210 struct usb_device *device = calloc(1, sizeof(struct usb_device));
211 int fd, length, did_retry = 0;
212
213 strcpy(device->dev_name, dev_name);
214 device->writeable = 1;
215
216retry:
217 fd = open(dev_name, O_RDWR);
218 if (fd < 0) {
219 /* if we fail, see if have read-only access */
220 fd = open(dev_name, O_RDONLY);
Mike Lockwoode15af092010-06-10 10:20:49 -0400221 D("usb_device_open open returned %d errno %d\n", fd, errno);
222 if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) {
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400223 /* work around race condition between inotify and permissions management */
224 sleep(1);
225 did_retry = 1;
226 goto retry;
227 }
228
229 if (fd < 0) goto fail;
230 device->writeable = 0;
231 D("[ usb open read-only %s fd = %d]\n", dev_name, fd);
232 }
233
234 length = read(fd, device->desc, sizeof(device->desc));
Mike Lockwoode15af092010-06-10 10:20:49 -0400235 D("usb_device_open read returned %d errno %d\n", fd, errno);
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400236 if (length < 0)
237 goto fail;
238
239 device->fd = fd;
240 device->desc_length = length;
241 return device;
242fail:
243 close(fd);
244 free(device);
245 return NULL;
246}
247
248void usb_device_close(struct usb_device *device)
249{
250 close(device->fd);
251 free(device);
252}
253
254const char* usb_device_get_name(struct usb_device *device)
255{
256 return device->dev_name;
257}
258
Mike Lockwood203f1022010-05-27 10:12:03 -0400259int usb_device_get_unique_id(struct usb_device *device)
260{
261 int bus = 0, dev = 0;
262 sscanf(device->dev_name, USB_FS_ID_SCANNER, &bus, &dev);
263 return bus * 1000 + dev;
264}
265
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400266uint16_t usb_device_get_vendor_id(struct usb_device *device)
267{
268 struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc;
269 return __le16_to_cpu(desc->idVendor);
270}
271
272uint16_t usb_device_get_product_id(struct usb_device *device)
273{
274 struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc;
275 return __le16_to_cpu(desc->idProduct);
276}
277
278char* usb_device_get_string(struct usb_device *device, int id)
279{
280 char string[256];
281 struct usbdevfs_ctrltransfer ctrl;
282 __u16 buffer[128];
283 __u16 languages[128];
284 int i, result;
285 int languageCount = 0;
286
287 string[0] = 0;
288
289 // reading the string requires read/write permission
290 if (!device->writeable) {
291 int fd = open(device->dev_name, O_RDWR);
292 if (fd > 0) {
293 close(device->fd);
294 device->fd = fd;
295 device->writeable = 1;
296 } else {
297 return NULL;
298 }
299 }
300
301 memset(languages, 0, sizeof(languages));
302 memset(&ctrl, 0, sizeof(ctrl));
303
304 // read list of supported languages
305 ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
306 ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
307 ctrl.wValue = (USB_DT_STRING << 8) | 0;
308 ctrl.wIndex = 0;
309 ctrl.wLength = sizeof(languages);
310 ctrl.data = languages;
311
312 result = ioctl(device->fd, USBDEVFS_CONTROL, &ctrl);
313 if (result > 0)
314 languageCount = (result - 2) / 2;
315
316 for (i = 1; i <= languageCount; i++) {
317 memset(buffer, 0, sizeof(buffer));
318 memset(&ctrl, 0, sizeof(ctrl));
319
320 ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
321 ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
322 ctrl.wValue = (USB_DT_STRING << 8) | id;
323 ctrl.wIndex = languages[i];
324 ctrl.wLength = sizeof(buffer);
325 ctrl.data = buffer;
326
327 result = ioctl(device->fd, USBDEVFS_CONTROL, &ctrl);
328 if (result > 0) {
329 int i;
330 // skip first word, and copy the rest to the string, changing shorts to bytes.
331 result /= 2;
332 for (i = 1; i < result; i++)
333 string[i - 1] = buffer[i];
334 string[i - 1] = 0;
335 return strdup(string);
336 }
337 }
338
339 return NULL;
340}
341
342char* usb_device_get_manufacturer_name(struct usb_device *device)
343{
344 struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
345
346 if (desc->iManufacturer)
347 return usb_device_get_string(device, desc->iManufacturer);
348 else
349 return NULL;
350}
351
352char* usb_device_get_product_name(struct usb_device *device)
353{
354 struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
355
356 if (desc->iProduct)
357 return usb_device_get_string(device, desc->iProduct);
358 else
359 return NULL;
360}
361
362char* usb_device_get_serial(struct usb_device *device)
363{
364 struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
365
366 if (desc->iSerialNumber)
367 return usb_device_get_string(device, desc->iSerialNumber);
368 else
369 return NULL;
370}
371
372int usb_device_is_writeable(struct usb_device *device)
373{
374 return device->writeable;
375}
376
377void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter)
378{
379 iter->config = device->desc;
380 iter->config_end = device->desc + device->desc_length;
381 iter->curr_desc = device->desc;
382}
383
384struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter)
385{
386 struct usb_descriptor_header* next;
387 if (iter->curr_desc >= iter->config_end)
388 return NULL;
389 next = (struct usb_descriptor_header*)iter->curr_desc;
390 iter->curr_desc += next->bLength;
391 return next;
392}
393
394int usb_device_claim_interface(struct usb_device *device, unsigned int interface)
395{
396 return ioctl(device->fd, USBDEVFS_CLAIMINTERFACE, &interface);
397}
398
399int usb_device_release_interface(struct usb_device *device, unsigned int interface)
400{
401 return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface);
402}
403
404struct usb_endpoint *usb_endpoint_open(struct usb_device *dev,
405 const struct usb_endpoint_descriptor *desc)
406{
407 struct usb_endpoint *ep = calloc(1, sizeof(struct usb_endpoint));
408 memcpy(&ep->desc, desc, sizeof(ep->desc));
409 ep->dev = dev;
410 return ep;
411}
412
413void usb_endpoint_close(struct usb_endpoint *ep)
414{
415 // cancel IO here?
416 free(ep);
417}
418
419int usb_endpoint_queue(struct usb_endpoint *ep, void *data, int len)
420{
421 struct usbdevfs_urb *urb = &ep->urb;
422 int res;
423
424 D("usb_endpoint_queue\n");
425 memset(urb, 0, sizeof(*urb));
426 urb->type = USBDEVFS_URB_TYPE_BULK;
427 urb->endpoint = ep->desc.bEndpointAddress;
428 urb->status = -1;
429 urb->buffer = data;
430 urb->buffer_length = len;
431
432 do {
433 res = ioctl(ep->dev->fd, USBDEVFS_SUBMITURB, urb);
434 } while((res < 0) && (errno == EINTR));
435
436 return res;
437}
438
439int usb_endpoint_wait(struct usb_device *dev, int *out_ep_num)
440{
441 struct usbdevfs_urb *out = NULL;
442 int res;
443
444 while (1) {
445 res = ioctl(dev->fd, USBDEVFS_REAPURB, &out);
446 D("USBDEVFS_REAPURB returned %d\n", res);
447 if (res < 0) {
448 if(errno == EINTR) {
449 continue;
450 }
451 D("[ reap urb - error ]\n");
452 *out_ep_num = -1;
453 } else {
454 D("[ urb @%p status = %d, actual = %d ]\n",
455 out, out->status, out->actual_length);
456 res = out->actual_length;
457 *out_ep_num = out->endpoint;
458 }
459 break;
460 }
461 return res;
462}
463
464int usb_endpoint_cancel(struct usb_endpoint *ep)
465{
466 return ioctl(ep->dev->fd, USBDEVFS_DISCARDURB, &ep->urb);
467}
468
Mike Lockwood5e567cb2010-05-12 08:53:49 -0400469struct usb_device *usb_endpoint_get_device(struct usb_endpoint *ep)
470{
471 return ep->dev;
472}
473
Mike Lockwood30ff2c72010-05-09 16:23:47 -0400474int usb_endpoint_number(struct usb_endpoint *ep)
475{
476 return ep->desc.bEndpointAddress;
477}
478
479int usb_endpoint_max_packet(struct usb_endpoint *ep)
480{
481 return __le16_to_cpu(ep->desc.wMaxPacketSize);
482}
483