[PATCH] PTP: ported from gadgetfs to functionfs kernel interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adapts PTP-gadget driver from gadgetfs interface to
functionfs interface. With functionfs one can create usb multifunction
composite gadget with some functions implemented in kernel space (like
USB Ethernet) and other (like the PTP) in userspace.

Signed-off-by: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx>
Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
---
 Makefile          |    9 +-
 README            |    2 +-
 README-functionfs |   65 +++++
 ptp.c             |  800 ++++++++++++++---------------------------------------
 usbstring.c       |  142 ----------
 usbstring.h       |   38 ---
 6 files changed, 284 insertions(+), 772 deletions(-)
 create mode 100644 README-functionfs
 delete mode 100644 usbstring.c
 delete mode 100644 usbstring.h

diff --git a/Makefile b/Makefile
index d56d320..b1f9652 100644
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,15 @@
 CPPFLAGS	:= -Wall -I$(KERNEL_SRC)/include
 
-ptp:		ptp.o usbstring.o
+ptp:		ptp.o
 	$(CROSS_COMPILE)gcc -lpthread -o $@ $^
 
-ptp.o:		ptp.c usbstring.h
-	$(CROSS_COMPILE)gcc $(CPPFLAGS) -c -o $@ $<
-
-usbstring.o:	usbstring.c usbstring.h
+ptp.o:		ptp.c
 	$(CROSS_COMPILE)gcc $(CPPFLAGS) -c -o $@ $<
 
 all:		ptp
 
 clean:
-	rm -f ptp ptp.o usbstring.o
+	rm -f ptp ptp.o
 
 install:	ptp
 	install -m 0755 -t $(DESTDIR)/usr/local/bin/ ptp
diff --git a/README b/README
index ff12403..7fc0028 100644
--- a/README
+++ b/README
@@ -7,7 +7,7 @@ This is an open-source project, licensed under GPL v3, hence the author is
 hoping, that it will be useful to others, and that others will contribute to it,
 eventually making it a complete implementation of the standard.
 
-The driver works completely in user-space and uses gadgetfs to communicate with
+The driver works completely in user-space and uses functionfs to communicate with
 USB gadget hardware.
 
 The code is based on the gadgetfs examples from
diff --git a/README-functionfs b/README-functionfs
new file mode 100644
index 0000000..d651d47
--- /dev/null
+++ b/README-functionfs
@@ -0,0 +1,65 @@
+This version of PTP driver uses USB FunctionFS interface to communicate
+with Linux Kernel. This interface allows to create a multifunction
+composite gadget which consists of 2 or more usb functions. Some of
+these functions (like USB Ethernet) can be implemented in the kernel
+space, while the other in user-space. For more information please refer
+to kernel/drivers/usb/gadget/f_fs.c and kernel/tools/usb/ffs-test.c.
+
+You can test this driver together with g_ffs.ko Linux kernel module:
+$ insmod g_ffs.ko
+$ mkdir /dev/usbffs
+$ mount usbffs /dev/usbffs -t functionfs
+$ ./ptp <path to images directory>
+
+If you want to use PTP on functionfs together with other usb functions
+connected to WindowsXP/Vista host, you will probably encouter some
+strange problems. It looks that there is a bug in the WindowsXP/Vista
+drivers that sets the target of usb setup request always to zero. To let
+make it working correctly you need to either set your functionfs
+interface number to zero or add the following workaround in your kernel
+multifunction driver:
+
+--->8---
+
+/* Still Image class-specific requests: */
+#define USB_REQ_PTP_CANCEL_REQUEST		0x64
+#define USB_REQ_PTP_GET_EXTENDED_EVENT_DATA	0x65
+#define USB_REQ_PTP_DEVICE_RESET_REQUEST	0x66
+#define USB_REQ_PTP_GET_DEVICE_STATUS_REQUEST	0x67
+
+#define USB_REQ_PTP_TYPE_MASK	(USB_TYPE_MASK | USB_RECIP_MASK)
+#define USB_REQ_PTP_TYPE		(USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+static int
+multi_composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *_ctrl)
+{
+	struct usb_ctrlrequest *ctrl = (struct usb_ctrlrequest *)_ctrl;
+
+	/* hack for broken PTP Windows XP/Vista drivers */
+	if (multi_ffs_data &&
+	    (ctrl->bRequest >= USB_REQ_PTP_CANCEL_REQUEST &&
+	     ctrl->bRequest <= USB_REQ_PTP_GET_DEVICE_STATUS_REQUEST) &&
+	    (ctrl->bRequestType & USB_REQ_PTP_TYPE_MASK) == USB_REQ_PTP_TYPE &&
+	     ctrl->wIndex == 0) {
+		printk(KERN_INFO "broken PTP/MTP 0x%02x setup request, force interface to %d\n",
+		       ctrl->bRequest, ffs_interface);
+		ctrl->wIndex = cpu_to_le16(ffs_interface);
+	}
+
+	return composite_setup(gadget, ctrl);
+}
+
+--->8---
+
+The above function can be used to hijack gadget setup callback in the
+composite framework and fix the interface number to the one used by
+functionfs interface. You can enable it with the following call:
+
+--->8---
+	composite_driver.setup = multi_composite_setup;
+--->8---
+
+With the following workaround I've managed to get PTP Interface working
+together with RNDIS, ACM and Mass Storage USB functions in the single
+Multifunction USB Gadget.
+
+Marek Szyprowski <m.szyprowski@xxxxxxxxxxx>
diff --git a/ptp.c b/ptp.c
index 4c4b383..1d5442e 100644
--- a/ptp.c
+++ b/ptp.c
@@ -2,10 +2,17 @@
  * Copyright (C) 2009
  * Guennadi Liakhovetski, DENX Software Engineering, <lg@xxxxxxx>
  *
+ * Copyright (C) 2010 Samsung Electronics
+ * USB functionfs conversion by Marek Szyprowski <m.szyprowski@xxxxxxxxxxx>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 3 as
  * published by the Free Software Foundation.
  */
+
+#define _BSD_SOURCE /* for endian.h */
+
+#include <endian.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -32,10 +39,8 @@
 #include <asm/byteorder.h>
 
 #include <linux/types.h>
-#include <linux/usb/gadgetfs.h>
 #include <linux/usb/ch9.h>
-
-#include "usbstring.h"
+#include <linux/usb/functionfs.h>
 
 #define min(a,b) ({ typeof(a) __a = (a); typeof(b) __b = (b); __a < __b ? __a : __b; })
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
@@ -48,16 +53,9 @@ static int verbose;
 #define USB_REQ_PTP_DEVICE_RESET_REQUEST	0x66
 #define USB_REQ_PTP_GET_DEVICE_STATUS_REQUEST	0x67
 
-#define DRIVER_VENDOR_NUM	0x1d6b
-#define DRIVER_PRODUCT_NUM	0x0100
-#define DRIVER_MFGR		"Linux"
-#define DRIVER_PRODUCT		"PTP Gadget"
-#define DRIVER_CONFIG		"Configuration 0"
-#define DRIVER_INTERFACE	"Source/Sink"
-
 /* Will be used for bcdDevice: remember to update on major changes */
 #define MAJOR			1
-#define MINOR			0
+#define MINOR			1
 #define DRIVER_VERSION		((MAJOR << 8) | MINOR)
 #define VERSION_STRING		__stringify(MAJOR) "." __stringify(MINOR)
 
@@ -68,160 +66,165 @@ static int verbose;
 
 /*-------------------------------------------------------------------------*/
 
-/* these descriptors are modified based on what controller we find */
-
-#define	STRINGID_MFGR		1
-#define	STRINGID_PRODUCT	2
-#define	STRINGID_CONFIG		3
-#define	STRINGID_INTERFACE	4
-
-static struct usb_device_descriptor device_desc = {
-	.bLength =		sizeof device_desc,
-	.bDescriptorType =	USB_DT_DEVICE,
-
-	.bcdUSB =		__constant_cpu_to_le16(0x0200),
-	.bcdDevice =		__constant_cpu_to_le16(DRIVER_VERSION),
-	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
-	.bDeviceSubClass =	0,
-	.bDeviceProtocol =	0,
-	/* .bMaxPacketSize0 ... set by gadgetfs */
-	.idVendor =		__constant_cpu_to_le16(DRIVER_VENDOR_NUM),
-	.idProduct =		__constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
-	.iManufacturer =	STRINGID_MFGR,
-	.iProduct =		STRINGID_PRODUCT,
-	.bNumConfigurations =	1,
-};
-
-#define	MAX_USB_POWER		1
-
-#define	CONFIG_VALUE		1
-
-static const struct usb_config_descriptor config = {
-	.bLength =		sizeof config,
-	.bDescriptorType =	USB_DT_CONFIG,
-
-	/* must compute wTotalLength ... */
-	.bNumInterfaces =	1,
-	.bConfigurationValue =	CONFIG_VALUE,
-	.iConfiguration =	STRINGID_CONFIG,
-	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-	.bMaxPower =		(MAX_USB_POWER + 1) / 2,
-};
-
 /* USB subclass value = the protocol encapsulation */
 #define USB_SC_IMAGE_CAPTURE	0x01		/* Still Image Capture Subclass */
 #define USB_PR_CB		0x01		/* Control/Bulk w/o interrupt */
 
-static struct usb_interface_descriptor source_sink_intf = {
-	.bLength =		sizeof source_sink_intf,
-	.bDescriptorType =	USB_DT_INTERFACE,
-
-	.bInterfaceClass =	USB_CLASS_STILL_IMAGE,
-	.bInterfaceSubClass =	USB_SC_IMAGE_CAPTURE,
-	.bInterfaceProtocol =	USB_PR_CB,
-	.iInterface =		STRINGID_INTERFACE,
-};
-
 #define MAX_PACKET_SIZE_FS 64
 #define MAX_PACKET_SIZE_HS 512
 
-/* Full speed configurations are used for full-speed only devices as
- * well as dual-speed ones (the only kind with high speed support).
- */
-static struct usb_endpoint_descriptor fs_source_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	/* NOTE some controllers may need FS bulk max packet size
-	 * to be smaller.  it would be a chip-specific option.
-	 */
-	.wMaxPacketSize =	__constant_cpu_to_le16(MAX_PACKET_SIZE_FS),
-};
-
-static struct usb_endpoint_descriptor fs_sink_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	__constant_cpu_to_le16(MAX_PACKET_SIZE_FS),
-};
-
 /* some devices can handle other status packet sizes */
 #define STATUS_MAXPACKET	8
-//#define	LOG2_STATUS_POLL_MSEC	3
-
-static struct usb_endpoint_descriptor fs_status_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-
-	.bmAttributes =		USB_ENDPOINT_XFER_INT,
-	.wMaxPacketSize =	__constant_cpu_to_le16(STATUS_MAXPACKET),
-//	.bInterval =		(1 << LOG2_STATUS_POLL_MSEC),
-	.bInterval =		10,
-};
-
-static const struct usb_endpoint_descriptor *fs_eps[] = {
-	&fs_source_desc,
-	&fs_sink_desc,
-	&fs_status_desc,
-};
 
+/******************** Little Endian Handling ********************************/
 
-/* High speed configurations are used only in addition to a full-speed
- * ones ... since all high speed devices support full speed configs.
- * Of course, not all hardware supports high speed configurations.
- */
-
-static struct usb_endpoint_descriptor hs_source_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
+#define cpu_to_le16(x)  htole16(x)
+#define cpu_to_le32(x)  htole32(x)
+#define le32_to_cpu(x)  le32toh(x)
+#define le16_to_cpu(x)  le16toh(x)
 
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	__constant_cpu_to_le16(MAX_PACKET_SIZE_HS),
-};
+static inline __u16 get_unaligned_le16(const void *_ptr)
+{
+	const __u8 *ptr = _ptr;
+	return ptr[0] | (ptr[1] << 8);
+}
 
-static struct usb_endpoint_descriptor hs_sink_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
+static inline __u32 get_unaligned_le32(const void *_ptr)
+{
+	const __u8 *ptr = _ptr;
+	return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
+}
 
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	__constant_cpu_to_le16(MAX_PACKET_SIZE_HS),
-};
+static inline void put_unaligned_le16(__u16 val, void *_ptr)
+{
+	__u8 *ptr = _ptr;
+	*ptr++ = val;
+	*ptr++ = val >> 8;
+}
 
-static struct usb_endpoint_descriptor hs_status_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
+static inline void put_unaligned_le32(__u32 val, void *_ptr)
+{
+	__u8 *ptr = _ptr;
+	*ptr++ = val;
+	*ptr++ = val >>  8;
+	*ptr++ = val >> 16;
+	*ptr++ = val >> 24;
+}
 
-	.bmAttributes =		USB_ENDPOINT_XFER_INT,
-	.wMaxPacketSize =	__constant_cpu_to_le16(STATUS_MAXPACKET),
-//	.bInterval =		LOG2_STATUS_POLL_MSEC + 3,
-	.bInterval =		10,
+/******************** Descriptors and Strings *******************************/
+
+static const struct {
+	struct usb_functionfs_descs_head header;
+	struct {
+		struct usb_interface_descriptor intf;
+		struct usb_endpoint_descriptor_no_audio source;
+		struct usb_endpoint_descriptor_no_audio sink;
+		struct usb_endpoint_descriptor_no_audio status;
+	} __attribute__((packed)) fs_descs, hs_descs;
+} __attribute__((packed)) descriptors = {
+	.header = {
+		.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+		.length = cpu_to_le32(sizeof descriptors),
+		.fs_count = 4,
+		.hs_count = 4,
+	},
+	.fs_descs = {
+		.intf = {
+			.bLength = sizeof descriptors.fs_descs.intf,
+			.bDescriptorType = USB_DT_INTERFACE,
+			.bNumEndpoints = 3,
+
+			.bInterfaceClass = USB_CLASS_STILL_IMAGE,
+			.bInterfaceSubClass = USB_SC_IMAGE_CAPTURE,
+			.bInterfaceProtocol = USB_PR_CB,
+			.iInterface = 1, /* first string from the provided table */
+		},
+		.source = {
+			.bLength = sizeof descriptors.fs_descs.source,
+			.bDescriptorType = USB_DT_ENDPOINT,
+			.bEndpointAddress = 1 | USB_DIR_OUT,
+			.bmAttributes = USB_ENDPOINT_XFER_BULK,
+			.wMaxPacketSize = MAX_PACKET_SIZE_FS,
+		},
+		.sink = {
+			.bLength = sizeof descriptors.fs_descs.sink,
+			.bDescriptorType = USB_DT_ENDPOINT,
+			.bEndpointAddress = 2 | USB_DIR_IN,
+			.bmAttributes = USB_ENDPOINT_XFER_BULK,
+			.wMaxPacketSize = MAX_PACKET_SIZE_FS,
+		},
+		.status = {
+			.bLength = sizeof descriptors.fs_descs.status,
+			.bDescriptorType = USB_DT_ENDPOINT,
+			.bEndpointAddress = 3 | USB_DIR_IN,
+			.bmAttributes = USB_ENDPOINT_XFER_INT,
+			.bInterval = 10,
+			.wMaxPacketSize = __constant_cpu_to_le16(STATUS_MAXPACKET),
+		},
+	},
+	.hs_descs = {
+		.intf = {
+			.bLength = sizeof descriptors.hs_descs.intf,
+			.bDescriptorType = USB_DT_INTERFACE,
+			.bNumEndpoints = 3,
+
+			.bInterfaceClass = USB_CLASS_STILL_IMAGE,
+			.bInterfaceSubClass = USB_SC_IMAGE_CAPTURE,
+			.bInterfaceProtocol = USB_PR_CB,
+			.iInterface = 1, /* first string from the provided table */
+		},
+		.source = {
+			.bLength = sizeof descriptors.hs_descs.source,
+			.bDescriptorType = USB_DT_ENDPOINT,
+			.bEndpointAddress = 1 | USB_DIR_OUT,
+			.bmAttributes = USB_ENDPOINT_XFER_BULK,
+			.wMaxPacketSize = MAX_PACKET_SIZE_HS,
+		},
+		.sink = {
+			.bLength = sizeof descriptors.hs_descs.sink,
+			.bDescriptorType = USB_DT_ENDPOINT,
+			.bEndpointAddress = 2 | USB_DIR_IN,
+			.bmAttributes = USB_ENDPOINT_XFER_BULK,
+			.wMaxPacketSize = MAX_PACKET_SIZE_HS,
+		},
+		.status = {
+			.bLength = sizeof descriptors.hs_descs.status,
+			.bDescriptorType = USB_DT_ENDPOINT,
+			.bEndpointAddress = 3 | USB_DIR_IN,
+			.bmAttributes = USB_ENDPOINT_XFER_INT,
+			.bInterval = 10,
+			.wMaxPacketSize = __constant_cpu_to_le16(STATUS_MAXPACKET),
+		},
+	},
 };
 
-static const struct usb_endpoint_descriptor *hs_eps[] = {
-	&hs_source_desc,
-	&hs_sink_desc,
-	&hs_status_desc,
+#define STR_INTERFACE_ "PTP Interface"
+
+static const struct {
+	struct usb_functionfs_strings_head header;
+	struct {
+		__le16 code;
+		const char str1[sizeof STR_INTERFACE_];
+	} __attribute__((packed)) lang0;
+} __attribute__((packed)) strings = {
+	.header = {
+		.magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
+		.length = cpu_to_le32(sizeof strings),
+		.str_count = cpu_to_le32(1),
+		.lang_count = cpu_to_le32(1),
+	},
+	.lang0 = {
+		cpu_to_le16(0x0409), /* en-us */
+		STR_INTERFACE_,
+	},
 };
 
-/*-------------------------------------------------------------------------*/
+#define STR_INTERFACE strings.lang0.str1
 
+/******************** Descriptors and Strings *******************************/
 
 static char driver_mfgr[64];
 
-static struct usb_string stringtab[] = {
-	{ STRINGID_MFGR,	driver_mfgr, },
-	{ STRINGID_PRODUCT,	DRIVER_PRODUCT, },
-	{ STRINGID_CONFIG,	DRIVER_CONFIG, },
-	{ STRINGID_INTERFACE,	DRIVER_INTERFACE, },
-};
-
-static struct usb_gadget_strings strings = {
-	.language =	0x0409,		/* "en-us" */
-	.strings =	stringtab,
-};
-
 /*-------------------------------------------------------------------------*/
 
 /* kernel drivers could autoconfigure like this too ... if
@@ -237,8 +240,6 @@ static char	*EP_IN_NAME, *EP_OUT_NAME, *EP_STATUS_NAME;
  */
 #define	USB_BUFSIZE	(7 * 1024)
 
-static enum usb_device_speed current_speed;
-
 #define CHECK_COUNT(cnt, min, max, op) do {			\
 	if (cnt & 3 || cnt < min || cnt > max) {		\
 		fprintf(stderr, "Wrong " op " size: %u\n",	\
@@ -585,294 +586,33 @@ static int autoconfig(void)
 	struct utsname	uts;
 	int ret;
 
-	/* NetChip 2280 PCI device or dummy_hcd, high/full speed */
-	if (stat(DEVNAME = "net2280", &statb) == 0 ||
-			stat(DEVNAME = "dummy_udc", &statb) == 0) {
-		HIGHSPEED = 1;
-
-		fs_source_desc.bEndpointAddress
-			= hs_source_desc.bEndpointAddress
-			= USB_DIR_IN | 7;
-		EP_IN_NAME = "ep-a";
-		fs_sink_desc.bEndpointAddress = hs_sink_desc.bEndpointAddress
-			= USB_DIR_OUT | 3;
-		EP_OUT_NAME = "ep-b";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress
-			= hs_status_desc.bEndpointAddress
-			= USB_DIR_IN | 11;
-		EP_STATUS_NAME = "ep-f";
-
-	/* Intel PXA 2xx processor, full speed only */
-	} else if (stat(DEVNAME = "pxa2xx_udc", &statb) == 0) {
-		HIGHSPEED = 0;
-
-		fs_source_desc.bEndpointAddress = USB_DIR_IN | 6;
-		EP_IN_NAME = "ep6in-bulk";
-		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 7;
-		EP_OUT_NAME = "ep7out-bulk";
-
-		/* using bulk for this since the pxa interrupt endpoints
-		 * always use the no-toggle scheme (discouraged).
-		 */
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress = USB_DIR_IN | 11;
-		EP_STATUS_NAME = "ep11in-bulk";
-#if 0
-	/* AMD au1x00 processor, full speed only */
-	} else if (stat(DEVNAME = "au1x00_udc", &statb) == 0) {
-		HIGHSPEED = 0;
-
-		fs_source_desc.bEndpointAddress = USB_DIR_IN | 2;
-		EP_IN_NAME = "ep2in";
-		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 4;
-		EP_OUT_NAME = "ep4out";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
-		EP_STATUS_NAME = "ep3in";
-
-	/* Intel SA-1100 processor, full speed only */
-	} else if (stat(DEVNAME = "sa1100", &statb) == 0) {
-		HIGHSPEED = 0;
-
-		fs_source_desc.bEndpointAddress = USB_DIR_IN | 2;
-		EP_IN_NAME = "ep2in-bulk";
-		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1;
-		EP_OUT_NAME = "ep1out-bulk";
-
-		source_sink_intf.bNumEndpoints = 2;
-		EP_STATUS_NAME = 0;
-#endif
-
-	/* Toshiba TC86c001 PCI device, full speed only */
-	} else if (stat(DEVNAME = "goku_udc", &statb) == 0) {
-		HIGHSPEED = 0;
-
-		fs_source_desc.bEndpointAddress = USB_DIR_IN | 2;
-		EP_IN_NAME = "ep2-bulk";
-		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1;
-		EP_OUT_NAME = "ep1-bulk";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
-		EP_STATUS_NAME = "ep3-bulk";
-
-	/* Renesas SH77xx processors, full speed only */
-	} else if (stat(DEVNAME = "sh_udc", &statb) == 0) {
-		HIGHSPEED = 0;
-
-		fs_source_desc.bEndpointAddress = USB_DIR_IN | 2;
-		EP_IN_NAME = "ep2in-bulk";
-		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 1;
-		EP_OUT_NAME = "ep1out-bulk";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
-		EP_STATUS_NAME = "ep3in-bulk";
-
-	/* OMAP 1610 and newer devices, full speed only, fifo mode 0 or 3 */
-	} else if (stat(DEVNAME = "omap_udc", &statb) == 0) {
-		HIGHSPEED = 0;
-
-		fs_source_desc.bEndpointAddress = USB_DIR_IN | 1;
-		EP_IN_NAME = "ep1in-bulk";
-		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2;
-		EP_OUT_NAME = "ep2out-bulk";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
-		EP_STATUS_NAME = "ep3in-int";
-
-	/* Something based on Mentor USB Highspeed Dual-Role Controller */
-	} else if (stat(DEVNAME = "musb_hdrc", &statb) == 0) {
-		HIGHSPEED = 1;
-
-		fs_source_desc.bEndpointAddress
-			= hs_source_desc.bEndpointAddress
-			= USB_DIR_IN | 1;
-		EP_IN_NAME = "ep1in";
-		fs_sink_desc.bEndpointAddress = hs_sink_desc.bEndpointAddress
-			= USB_DIR_OUT | 1;
-		EP_OUT_NAME = "ep1out";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress
-			= hs_status_desc.bEndpointAddress
-			= USB_DIR_IN | 3;
-		EP_STATUS_NAME = "ep3in";
-
-	/* Atmel AT91 processors, full speed only */
-	} else if (stat(DEVNAME = "at91_udc", &statb) == 0) {
-		HIGHSPEED = 0;
-
-		fs_source_desc.bEndpointAddress = USB_DIR_IN | 1;
-		EP_IN_NAME = "ep1";
-		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2;
-		EP_OUT_NAME = "ep2";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
-		EP_STATUS_NAME = "ep3-int";
-
-	/* Sharp LH740x processors, full speed only */
-	} else if (stat(DEVNAME = "lh740x_udc", &statb) == 0) {
-		HIGHSPEED = 0;
-
-		fs_source_desc.bEndpointAddress = USB_DIR_IN | 1;
-		EP_IN_NAME = "ep1in-bulk";
-		fs_sink_desc.bEndpointAddress = USB_DIR_OUT | 2;
-		EP_OUT_NAME = "ep2out-bulk";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress = USB_DIR_IN | 3;
-		EP_STATUS_NAME = "ep3in-int";
-
-	/* Atmel AT32AP700x processors, high/full speed */
-	} else if (stat(DEVNAME = "atmel_usba_udc", &statb) == 0) {
-		HIGHSPEED = 1;
-
-		fs_source_desc.bEndpointAddress
-			= hs_source_desc.bEndpointAddress
-			= USB_DIR_IN | 1;
-		EP_IN_NAME = "ep1in-bulk";
-		fs_sink_desc.bEndpointAddress
-			= hs_sink_desc.bEndpointAddress
-			= USB_DIR_OUT | 2;
-		EP_OUT_NAME = "ep2out-bulk";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress
-			= hs_status_desc.bEndpointAddress
-			= USB_DIR_IN | 3;
-		EP_STATUS_NAME = "ep3in-int";
-
-	/* Freescale i.MX31 SoC, high/full speed */
-	} else if (stat(DEVNAME = "fsl-usb2-udc", &statb) == 0) {
-		HIGHSPEED = 1;
-
-		fs_source_desc.bEndpointAddress
-			= hs_source_desc.bEndpointAddress
-			= USB_DIR_IN | 1;
-		EP_IN_NAME = "ep1in";
-		fs_sink_desc.bEndpointAddress
-			= hs_sink_desc.bEndpointAddress
-			= USB_DIR_OUT | 1;
-		EP_OUT_NAME = "ep1out";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress
-			= hs_status_desc.bEndpointAddress
-			= USB_DIR_IN | 2;
-		EP_STATUS_NAME = "ep2in";
-	} else if (stat(DEVNAME = "arc_udc", &statb) == 0) {
+	if (stat(DEVNAME = "ep0", &statb) == 0) {
 		HIGHSPEED = 1;
-
-		fs_source_desc.bEndpointAddress
-			= hs_source_desc.bEndpointAddress
-			= USB_DIR_IN | 1;
-		EP_IN_NAME = "ep1in";
-		fs_sink_desc.bEndpointAddress
-			= hs_sink_desc.bEndpointAddress
-			= USB_DIR_OUT | 1;
-		EP_OUT_NAME = "ep1out";
-
-		source_sink_intf.bNumEndpoints = 3;
-		fs_status_desc.bEndpointAddress
-			= hs_status_desc.bEndpointAddress
-			= USB_DIR_IN | 2;
-		EP_STATUS_NAME = "ep2in";
+		EP_OUT_NAME = "ep1";
+		EP_IN_NAME = "ep2";
+		EP_STATUS_NAME = "ep3";
 	} else {
 		DEVNAME = 0;
 		return -ENODEV;
 	}
 
 	ret = uname(&uts);
-	snprintf(driver_mfgr, sizeof(driver_mfgr), DRIVER_MFGR " %s with %s",
-		 ret ? "unknown" : uts.release, DEVNAME);
+	snprintf(driver_mfgr, sizeof(driver_mfgr), "PTP Interface %s with %s",
+		 ret ? "unknown" : uts.release, "functionfs");
 
 	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
-/* you should be able to open and configure endpoints
- * whether or not the host is connected
- */
-static int ep_config(char *name,
-		     struct usb_endpoint_descriptor *fs,
-		     struct usb_endpoint_descriptor *hs)
-{
-	int	fd, err;
-	char	buf[USB_BUFSIZE];
-
-	/* open and initialize with endpoint descriptor(s) */
-	fd = open(name, O_RDWR);
-	if (fd < 0) {
-		err = -errno;
-		fprintf(stderr, "open %s error %d (%s)\n",
-			name, errno, strerror(errno));
-		return err;
-	}
-
-	/* one (fs or ls) or two (fs + hs) sets of config descriptors */
-	*(uint32_t *)buf = 1;	/* tag for this format */
-	memcpy(buf + 4, fs, USB_DT_ENDPOINT_SIZE);
-	if (HIGHSPEED)
-		memcpy(buf + 4 + USB_DT_ENDPOINT_SIZE,
-			hs, USB_DT_ENDPOINT_SIZE);
-	err = write(fd, buf, 4 + USB_DT_ENDPOINT_SIZE
-			+ (HIGHSPEED ? USB_DT_ENDPOINT_SIZE : 0));
-	if (err < 0) {
-		err = -errno;
-		fprintf(stderr, "config %s error %d (%s)\n",
-			name, errno, strerror(errno));
-		close(fd);
-		return err;
-	} else if (verbose)
-		fprintf(stderr, "%s start fd %d\n", name, fd);
-
-	return fd;
-}
-
-#define source_open(name) \
-	ep_config(name, &fs_source_desc, &hs_source_desc)
-#define sink_open(name) \
-	ep_config(name, &fs_sink_desc, &hs_sink_desc)
-#define int_open(name) \
-	ep_config(name, &fs_status_desc, &hs_status_desc)
-
-/*-------------------------------------------------------------------------*/
-
-static char *build_config(char *cp, const struct usb_endpoint_descriptor **ep)
-{
-	struct usb_config_descriptor *c;
-	int i;
-
-	c = (struct usb_config_descriptor *)cp;
-
-	memcpy(cp, &config, config.bLength);
-	cp += config.bLength;
-	memcpy(cp, &source_sink_intf, source_sink_intf.bLength);
-	cp += source_sink_intf.bLength;
-
-	for (i = 0; i < source_sink_intf.bNumEndpoints; i++) {
-		memcpy(cp, ep[i], USB_DT_ENDPOINT_SIZE);
-		cp += USB_DT_ENDPOINT_SIZE;
-	}
-	c->wTotalLength = __cpu_to_le16(cp - (char *)c);
-	return cp;
-}
-
 static void init_device(void)
 {
-	char		buf[4096], *cp = buf;
 	int		err;
+	ssize_t ret;
 
 	err = autoconfig();
 	if (err < 0) {
-		fprintf(stderr, "?? don't recognize /dev/gadget bulk device\n");
+		fprintf(stderr, "?? don't recognize /dev/usbffs bulk device\n");
 		control = err;
 		return;
 	}
@@ -884,42 +624,21 @@ static void init_device(void)
 		return;
 	}
 
-	*(uint32_t *)cp = 0;	/* tag for this format */
-	cp += 4;
-
-	/* write full then high speed configs */
-	cp = build_config(cp, fs_eps);
-	if (HIGHSPEED)
-		cp = build_config(cp, hs_eps);
-
-	/* and device descriptor at the end */
-	memcpy(cp, &device_desc, sizeof device_desc);
-	cp += sizeof device_desc;
-
-	err = write(control, buf, cp - buf);
-	if (err < 0) {
-		perror("write dev descriptors");
-		close(control);
-		control = -errno;
-		return;
-	} else if (err != cp - buf) {
-		fprintf(stderr, "dev init, wrote %d expected %d\n",
-				err, cp - buf);
-		close(control);
-		control = -errno;
-		return;
+	fprintf(stderr, "%s: writing descriptors\n", DEVNAME);
+	ret = write(control, &descriptors, sizeof descriptors);
+	if (ret < 0) {
+		fprintf(stderr, "%s: write: descriptors", DEVNAME);
+		control = err;
 	}
-	return;
-}
 
-static const char *speed(enum usb_device_speed s)
-{
-	switch (s) {
-	case USB_SPEED_LOW:	return "low speed";
-	case USB_SPEED_FULL:	return "full speed";
-	case USB_SPEED_HIGH:	return "high speed";
-	default:		return "UNKNOWN speed";
+	fprintf(stderr, "%s: writing strings\n", DEVNAME);
+	ret = write(control, &strings, sizeof strings);
+	if(ret < 0) {
+		fprintf(stderr, "%s: write: strings", DEVNAME);
+		control = err;
 	}
+
+	return;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1620,18 +1339,18 @@ static int start_io(void)
 	if (bulk_in >= 0 && bulk_out >= 0)
 		return 0;
 
-	snprintf(buf, sizeof(buf), "/dev/gadget/%s", EP_IN_NAME);
-	bulk_in = source_open(buf);
+	snprintf(buf, sizeof(buf), "/dev/usbffs/%s", EP_IN_NAME);
+	bulk_in = open(buf, O_RDWR);
 	if (bulk_in < 0)
 		return bulk_in;
 
-	snprintf(buf, sizeof(buf), "/dev/gadget/%s", EP_OUT_NAME);
-	bulk_out = sink_open(buf);
+	snprintf(buf, sizeof(buf), "/dev/usbffs/%s", EP_OUT_NAME);
+	bulk_out = open(buf, O_RDWR);
 	if (bulk_out < 0)
 		return bulk_out;
 
-	snprintf(buf, sizeof(buf), "/dev/gadget/%s", EP_STATUS_NAME);
-	interrupt = int_open(buf);
+	snprintf(buf, sizeof(buf), "/dev/usbffs/%s", EP_STATUS_NAME);
+	interrupt = open(buf, O_RDWR);
 	if (interrupt < 0)
 		return interrupt;
 
@@ -1678,11 +1397,11 @@ static int reset_interface(void)
 
 	pthread_kill(bulk_pthread, SIGINT);
 
-	err = ioctl(bulk_in, GADGETFS_CLEAR_HALT);
+	err = ioctl(bulk_in, FUNCTIONFS_CLEAR_HALT);
 	if (err < 0)
 		perror("reset source fd");
 
-	err = ioctl(bulk_out, GADGETFS_CLEAR_HALT);
+	err = ioctl(bulk_out, FUNCTIONFS_CLEAR_HALT);
 	if (err < 0)
 		perror("reset sink fd");
 
@@ -1694,9 +1413,9 @@ static int reset_interface(void)
 	return 0;
 }
 
-static void handle_control(struct usb_ctrlrequest *setup)
+static void handle_control(const struct usb_ctrlrequest *setup)
 {
-	int		err, tmp;
+	int		err;
 	uint8_t		buf[256];
 	uint16_t	value, index, length;
 
@@ -1716,108 +1435,6 @@ static void handle_control(struct usb_ctrlrequest *setup)
 	*/
 
 	switch (setup->bRequest) {	/* usb 2.0 spec ch9 requests */
-	case USB_REQ_GET_DESCRIPTOR:
-		if (setup->bRequestType != USB_DIR_IN)
-			goto stall;
-		switch (value >> 8) {
-		case USB_DT_STRING:
-			tmp = value & 0xff;
-			if (verbose > 1)
-				fprintf(stderr,
-					"... get string %d lang %04x\n",
-					tmp, index);
-			if (tmp != 0 && index != strings.language)
-				goto stall;
-			err = usb_gadget_get_string(&strings, tmp, buf);
-			if (err < 0)
-				goto stall;
-			tmp = err;
-			if (length < tmp)
-				tmp = length;
-			err = write(control, buf, tmp);
-			if (err < 0) {
-				if (errno == EIDRM)
-					fprintf(stderr, "string timeout\n");
-				else
-					perror("write string data");
-			} else if (err != tmp) {
-				fprintf(stderr, "short string write, %d\n",
-					err);
-			}
-			break;
-		default:
-			goto stall;
-		}
-		return;
-	case USB_REQ_SET_CONFIGURATION:
-		if (setup->bRequestType != USB_DIR_OUT)
-			goto stall;
-		if (verbose)
-			fprintf(stderr, "CONFIG #%d\n", value);
-
-		/* Kernel is normally waiting for us to finish reconfiguring
-		 * the device.
-		 *
-		 * Some hardware can't, notably older PXA2xx hardware.  (With
-		 * racey and restrictive config change automagic.  PXA 255 is
-		 * OK, most PXA 250s aren't.  If it has a UDC CFR register,
-		 * it can handle deferred response for SET_CONFIG.)  To handle
-		 * such hardware, don't write code this way ... instead, keep
-		 * the endpoints always active and don't rely on seeing any
-		 * config change events, either this or SET_INTERFACE.
-		 */
-		switch (value) {
-		case CONFIG_VALUE:
-			start_io();
-			break;
-		case 0:
-			stop_io();
-			break;
-		default:
-			/* kernel bug -- "can't happen" */
-			fprintf(stderr, "? illegal config\n");
-			goto stall;
-		}
-
-		/* ... ack (a write would stall) */
-		err = read(control, &err, 0);
-		if (err)
-			perror("ack SET_CONFIGURATION");
-		return;
-	case USB_REQ_GET_INTERFACE:
-		if (setup->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
-				|| index != 0
-				|| length > 1)
-			goto stall;
-
-		/* only one altsetting in this driver */
-		buf[0] = 0;
-		err = write(control, buf, length);
-		if (err < 0) {
-			if (errno == EIDRM)
-				fprintf(stderr, "GET_INTERFACE timeout\n");
-			else
-				perror("write GET_INTERFACE data");
-		} else if (err != length) {
-			fprintf(stderr, "short GET_INTERFACE write, %d\n",
-				err);
-		}
-		return;
-	case USB_REQ_SET_INTERFACE:
-		if (setup->bRequestType != USB_RECIP_INTERFACE
-				|| index != 0
-				|| value != 0)
-			goto stall;
-
-		err = reset_interface();
-		if (err)
-			goto stall;
-
-		/* ... and ack (a write would stall) */
-		err = read(control, &err, 0);
-		if (err)
-			perror("ack SET_INTERFACE");
-		return;
 	/* Still Image class-specific requests */
 	case USB_REQ_PTP_CANCEL_REQUEST:
 		return;
@@ -1826,7 +1443,6 @@ static void handle_control(struct usb_ctrlrequest *setup)
 		goto stall;
 	case USB_REQ_PTP_DEVICE_RESET_REQUEST:
 		if (setup->bRequestType != 0x21
-				|| index != 0
 				|| value != 0)
 			goto stall;
 
@@ -1834,6 +1450,9 @@ static void handle_control(struct usb_ctrlrequest *setup)
 		if (err)
 			goto stall;
 
+		/* reset session */
+		session = -EINVAL;
+
 		/* ... and ack (a write would stall) */
 		err = read(control, &err, 0);
 		if (err)
@@ -1841,7 +1460,6 @@ static void handle_control(struct usb_ctrlrequest *setup)
 		return;
 	case USB_REQ_PTP_GET_DEVICE_STATUS_REQUEST:
 		if (setup->bRequestType != 0xa1
-				|| index != 0
 				|| value != 0)
 			goto stall;
 		else {
@@ -1882,7 +1500,16 @@ stall:
 
 static int read_control(void)
 {
-	struct usb_gadgetfs_event event[NEVENT];
+	static const char *const names[] = {
+		[FUNCTIONFS_BIND] = "BIND",
+		[FUNCTIONFS_UNBIND] = "UNBIND",
+		[FUNCTIONFS_ENABLE] = "ENABLE",
+		[FUNCTIONFS_DISABLE] = "DISABLE",
+		[FUNCTIONFS_SETUP] = "SETUP",
+		[FUNCTIONFS_SUSPEND] = "SUSPEND",
+		[FUNCTIONFS_RESUME] = "RESUME",
+	};
+	const struct usb_functionfs_event event[NEVENT];
 	int i, nevent, ret;
 
 	ret = read(control, &event, sizeof(event));
@@ -1897,36 +1524,39 @@ static int read_control(void)
 	nevent = ret / sizeof event[0];
 
 	for (i = 0; i < nevent; i++) {
+		fprintf(stderr, "Event %s\n", names[event->type]);
+
 		switch (event[i].type) {
-		case GADGETFS_NOP:
-			if (verbose)
-				fprintf(stderr, "NOP\n");
-			break;
-		case GADGETFS_CONNECT:
+		case FUNCTIONFS_BIND:
 			if (status != PTP_WAITCONFIG)
 				status = PTP_IDLE;
-			current_speed = event[i].u.speed;
-			if (verbose)
-				fprintf(stderr,
-					"CONNECT %s\n",
-				    speed(event[i].u.speed));
-			break;
-		case GADGETFS_SETUP:
-			if (status != PTP_WAITCONFIG)
-				status = PTP_IDLE;
-			handle_control(&event[i].u.setup);
 			break;
-		case GADGETFS_DISCONNECT:
+
+		case FUNCTIONFS_UNBIND:
 			status = PTP_WAITCONFIG;
-			current_speed = USB_SPEED_UNKNOWN;
-			if (verbose)
-				fprintf(stderr, "DISCONNECT\n");
 			break;
-		case GADGETFS_SUSPEND:
-			if (verbose)
-				fprintf(stderr, "SUSPEND\n");
+
+		case FUNCTIONFS_ENABLE:
+			/* reset session */
+			session = -EINVAL;
+
+			/* fallback */
+
+		case FUNCTIONFS_RESUME:
+			start_io();
+                        break;
+
+		case FUNCTIONFS_SUSPEND:
+		case FUNCTIONFS_DISABLE:
 			stop_io();
 			break;
+
+		case FUNCTIONFS_SETUP:
+			if (status != PTP_WAITCONFIG)
+				status = PTP_IDLE;
+			handle_control(&event[i].u.setup);
+			break;
+
 		default:
 			fprintf(stderr,
 				"* unhandled event %d\n",
@@ -1989,7 +1619,7 @@ static size_t put_string(iconv_t ic, char *buf, const char *s, size_t len)
 
 	ret = iconv(ic, &in, &inl, &buf, &outl);
 	if (inl || outl)
-		fprintf(stdout, "iconv() error %d: %u input / %u output bytes left!\n",
+		fprintf(stderr, "iconv() error %d: %u input / %u output bytes left!\n",
 			errno, inl, outl);
 
 	return ret;
@@ -2223,8 +1853,8 @@ int main(int argc, char *argv[])
 
 	enum_objects(root);
 
-	if (chdir("/dev/gadget") < 0) {
-		perror("can't chdir /dev/gadget");
+	if (chdir("/dev/usbffs") < 0) {
+		perror("can't chdir /dev/usbffs");
 		exit(EXIT_FAILURE);
 	}
 
diff --git a/usbstring.c b/usbstring.c
deleted file mode 100644
index 993acc2..0000000
--- a/usbstring.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2003 David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- */
-
-#include <errno.h>
-#include <string.h>
-
-#include <linux/types.h>
-#include <linux/usb/ch9.h>
-
-#include "usbstring.h"
-
-static inline void put_unaligned_le16(__u16 val, __u16 *cp)
-{
-	__u8	*p = (void *)cp;
-
-	*p++ = (__u8) val;
-	*p++ = (__u8) (val >> 8);
-}
-
-static int utf8_to_utf16le(const char *s, __u16 *cp, unsigned len)
-{
-	int	count = 0;
-	__u8	c;
-	__u16	uchar;
-
-	/* this insists on correct encodings, though not minimal ones.
-	 * BUT it currently rejects legit 4-byte UTF-8 code points,
-	 * which need surrogate pairs.  (Unicode 3.1 can use them.)
-	 */
-	while (len != 0 && (c = (__u8) *s++) != 0) {
-		if (c & 0x80) {
-			// 2-byte sequence:
-			// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
-			if ((c & 0xe0) == 0xc0) {
-				uchar = (c & 0x1f) << 6;
-
-				c = (__u8) *s++;
-				if ((c & 0xc0) != 0xc0)
-					goto fail;
-				c &= 0x3f;
-				uchar |= c;
-
-			// 3-byte sequence (most CJKV characters):
-			// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
-			} else if ((c & 0xf0) == 0xe0) {
-				uchar = (c & 0x0f) << 12;
-
-				c = (__u8) *s++;
-				if ((c & 0xc0) != 0xc0)
-					goto fail;
-				c &= 0x3f;
-				uchar |= c << 6;
-
-				c = (__u8) *s++;
-				if ((c & 0xc0) != 0xc0)
-					goto fail;
-				c &= 0x3f;
-				uchar |= c;
-
-				/* no bogus surrogates */
-				if (0xd800 <= uchar && uchar <= 0xdfff)
-					goto fail;
-
-			// 4-byte sequence (surrogate pairs, currently rare):
-			// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
-			//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
-			// (uuuuu = wwww + 1)
-			// FIXME accept the surrogate code points (only)
-
-			} else
-				goto fail;
-		} else
-			uchar = c;
-		put_unaligned_le16 (uchar, cp++);
-		count++;
-		len--;
-	}
-	return count;
-fail:
-	return -1;
-}
-
-
-/**
- * usb_gadget_get_string - fill out a string descriptor 
- * @table: of c strings encoded using UTF-8
- * @id: string id, from low byte of wValue in get string descriptor
- * @buf: at least 256 bytes
- *
- * Finds the UTF-8 string matching the ID, and converts it into a
- * string descriptor in utf16-le.
- * Returns length of descriptor (always even) or negative errno
- *
- * If your driver needs strings in multiple languages, you'll probably
- * "switch (wIndex) { ... }"  in your ep0 string descriptor logic,
- * using this routine after choosing which set of UTF-8 strings to use.
- *
- * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
- * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
- * characters.
- */
-int
-usb_gadget_get_string (struct usb_gadget_strings *table, int id, __u8 *buf)
-{
-	struct usb_string	*s;
-	int			len;
-
-	/* descriptor 0 has the language id */
-	if (id == 0) {
-		buf [0] = 4;
-		buf [1] = USB_DT_STRING;
-		buf [2] = (__u8) table->language;
-		buf [3] = (__u8) (table->language >> 8);
-		return 4;
-	}
-	for (s = table->strings; s && s->s; s++)
-		if (s->id == id)
-			break;
-
-	/* unrecognized: stall. */
-	if (!s || !s->s)
-		return -EINVAL;
-
-	/* string descriptors have length, tag, then UTF16-LE text */
-	len = strlen (s->s);
-	if (len > 126)
-		len = 126;
-	memset (buf + 2, 0, 2 * len);	/* zero all the bytes */
-	len = utf8_to_utf16le(s->s, (__u16 *)&buf[2], len);
-	if (len < 0)
-		return -EINVAL;
-	buf [0] = (len + 1) * 2;
-	buf [1] = USB_DT_STRING;
-	return buf [0];
-}
-
diff --git a/usbstring.h b/usbstring.h
deleted file mode 100644
index 982bec4..0000000
--- a/usbstring.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * (c) Copyright 2003 by David Brownell
- * All Rights Reserved.
- *
- * This software is licensed under the GNU LGPL version 2.
- */
-
-/* utility to simplify dealing with string descriptors */
-
-/**
- * struct usb_string - wraps a C string and its USB id
- * @id: the (nonzero) ID for this string
- * @s: the string, in UTF-8 encoding
- *
- * If you're using usb_gadget_get_string(), use this to wrap a string
- * together with its ID.
- */
-struct usb_string {
-	__u8			id;
-	const char		*s;
-};
-
-/**
- * struct usb_gadget_strings - a set of USB strings in a given language
- * @language: identifies the strings' language (0x0409 for en-us)
- * @strings: array of strings with their ids
- *
- * If you're using usb_gadget_get_string(), use this to wrap all the
- * strings for a given language.
- */
-struct usb_gadget_strings {
-	__u16			language;	/* 0x0409 for en-us */
-	struct usb_string	*strings;
-};
-
-/* put descriptor for string with that id into buf (buflen >= 256) */
-int usb_gadget_get_string (struct usb_gadget_strings *table, int id, __u8 *buf);
-
-- 
1.7.1.569.g6f426

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux