libusbhost: Add support for creating a usb_device struct from an existing fd
We will use this for sharing USB file descriptors across address spaces via Binder
Change-Id: Iadbd3e0a4178f79d1d778fdfd5175f6fe0e2aaf5
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 5332acd..57d9c37 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -81,6 +81,16 @@
/* Releases all resources associated with the USB device */
void usb_device_close(struct usb_device *device);
+/* Creates a usb_device object for already open USB device.
+ * This is intended to facilitate sharing USB devices across address spaces.
+ */
+struct usb_device *usb_device_new(const char *dev_name, int fd);
+
+/* Returns the file descriptor for the usb_device. Used in conjunction with
+ * usb_device_new() for sharing USB devices across address spaces.
+ */
+int usb_device_get_fd(struct usb_device *device);
+
/* Returns the name for the USB device, which is the same as
* the dev_name passed to usb_device_open()
*/
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 98ccf7c..93c6dd3 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -214,11 +214,7 @@
struct usb_device *usb_device_open(const char *dev_name)
{
- struct usb_device *device = calloc(1, sizeof(struct usb_device));
- int fd, length, did_retry = 0;
-
- strcpy(device->dev_name, dev_name);
- device->writeable = 1;
+ int fd, did_retry = 0, writeable = 1;
retry:
fd = open(dev_name, O_RDWR);
@@ -233,23 +229,16 @@
goto retry;
}
- if (fd < 0) goto fail;
- device->writeable = 0;
+ if (fd < 0)
+ return NULL;
+ writeable = 0;
D("[ usb open read-only %s fd = %d]\n", dev_name, fd);
}
- length = read(fd, device->desc, sizeof(device->desc));
- D("usb_device_open read returned %d errno %d\n", fd, errno);
- if (length < 0)
- goto fail;
-
- device->fd = fd;
- device->desc_length = length;
- return device;
-fail:
- close(fd);
- free(device);
- return NULL;
+ struct usb_device* result = usb_device_new(dev_name, fd);
+ if (result)
+ result->writeable = writeable;
+ return result;
}
void usb_device_close(struct usb_device *device)
@@ -258,6 +247,53 @@
free(device);
}
+struct usb_device *usb_device_new(const char *dev_name, int fd)
+{
+ struct usb_device *device = calloc(1, sizeof(struct usb_device));
+ int length;
+
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ goto failed;
+ length = read(fd, device->desc, sizeof(device->desc));
+ D("usb_device_new read returned %d errno %d\n", fd, errno);
+ if (length < 0)
+ goto failed;
+
+ device->fd = fd;
+ device->desc_length = length;
+ // assume we are writeable, since usb_device_get_fd will only return writeable fds
+ device->writeable = 1;
+ return device;
+
+failed:
+ close(fd);
+ free(device);
+ return NULL;
+}
+
+static int usb_device_reopen_writeable(struct usb_device *device)
+{
+ if (device->writeable)
+ return 1;
+
+ int fd = open(device->dev_name, O_RDWR);
+ if (fd >= 0) {
+ close(device->fd);
+ device->fd = fd;
+ device->writeable = 1;
+ return 1;
+ }
+ D("usb_device_reopen_writeable failed errno %d\n", errno);
+ return 0;
+}
+
+int usb_device_get_fd(struct usb_device *device)
+{
+ if (!usb_device_reopen_writeable(device))
+ return -1;
+ return device->fd;
+}
+
const char* usb_device_get_name(struct usb_device *device)
{
return device->dev_name;
@@ -300,16 +336,8 @@
struct usbdevfs_ctrltransfer ctrl;
// this usually requires read/write permission
- if (!device->writeable) {
- int fd = open(device->dev_name, O_RDWR);
- if (fd > 0) {
- close(device->fd);
- device->fd = fd;
- device->writeable = 1;
- } else {
- return -1;
- }
- }
+ if (!usb_device_reopen_writeable(device))
+ return -1;
memset(&ctrl, 0, sizeof(ctrl));
ctrl.bRequestType = requestType;