[PATCH 5/6] Composite File Storage gadget support

Ragner Magalhaes <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
From: Ragner Magalhaes <[email protected]>

This patch adds some features that let the file-storage gadget
to work as a usb_function module.

Signed-off-by: Felipe Balbi <[email protected]>
Signed-off-by: Ragner Magalhaes <[email protected]>
---

 drivers/usb/gadget/file_storage.c |  119 ++++++++++++++++---------------------
 1 files changed, 51 insertions(+), 68 deletions(-)

diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index c6b6479..fcaf3b3 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -255,6 +255,7 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
+#include <linux/usb/composite.h>
 
 #include "gadget_chips.h"
 
@@ -640,6 +641,7 @@ struct fsg_dev {
 	/* lock protects: state, all the req_busy's, and cbbuf_cmnd */
 	spinlock_t		lock;
 	struct usb_gadget	*gadget;
+	struct usb_function	*f;
 
 	/* filesem protects: backing files in use */
 	struct rw_semaphore	filesem;
@@ -732,7 +734,7 @@ static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
 }
 
 static struct fsg_dev			*the_fsg;
-static struct usb_gadget_driver		fsg_driver;
+static struct usb_function		fsg_driver;
 
 static void	close_backing_file(struct lun *curlun);
 static void	close_all_backing_files(struct fsg_dev *fsg);
@@ -848,7 +850,8 @@ static void inline put_be32(u8 *buf, u32 val)
 #define STRING_PRODUCT		2
 #define STRING_SERIAL		3
 #define STRING_CONFIG		4
-#define STRING_INTERFACE	5
+
+#define STRING_INTERFACE	6
 
 /* There is only one configuration. */
 #define	CONFIG_VALUE		1
@@ -1052,9 +1055,10 @@ static struct usb_gadget_strings	stringtab = {
  * and with code managing interfaces and their altsettings.  They must
  * also handle different speeds and other-speed requests.
  */
-static int populate_config_buf(struct usb_gadget *gadget,
+static int populate_config_buf(struct fsg_dev *dev,
 		u8 *buf, u8 type, unsigned index)
 {
+	struct usb_gadget			*gadget = dev->gadget;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 	enum usb_device_speed			speed = gadget->speed;
 #endif
@@ -1074,9 +1078,15 @@ static int populate_config_buf(struct usb_gadget *gadget,
 		function = fs_function;
 
 	/* for now, don't advertise srp-only devices */
-	if (!gadget->is_otg)
+	if (!gadget->is_otg || is_composite())
 		function++;
 
+	if (is_composite()) {
+		buf += dev->ep0req->length;
+		len = EP0_BUFSIZE - dev->ep0req->length;
+		return usb_descriptor_fillbuf(buf, len, function);
+	}
+
 	len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
 	((struct usb_config_descriptor *) buf)->bDescriptorType = type;
 	return len;
@@ -1125,7 +1135,7 @@ static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
 
 static void fsg_disconnect(struct usb_gadget *gadget)
 {
-	struct fsg_dev		*fsg = get_gadget_data(gadget);
+	struct fsg_dev		*fsg = get_usb_function_data(gadget);
 
 	DBG(fsg, "disconnect or port reset\n");
 	raise_exception(fsg, FSG_STATE_DISCONNECT);
@@ -1415,10 +1425,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 		get_config:
 #endif
-			value = populate_config_buf(fsg->gadget,
-					req->buf,
-					w_value >> 8,
-					w_value & 0xff);
+			value = populate_config_buf(fsg, req->buf,
+					w_value >> 8, w_value & 0xff);
 			break;
 
 		case USB_DT_STRING:
@@ -1479,7 +1487,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
 			break;
 		}
 		VDBG(fsg, "get interface\n");
-		*(u8 *) req->buf = 0;
+		*(u8 *) req->buf = INTRF_FUNC2COMPOSITE(fsg->f,0);
 		value = 1;
 		break;
 
@@ -1497,13 +1505,16 @@ static int standard_setup_req(struct fsg_dev *fsg,
 static int fsg_setup(struct usb_gadget *gadget,
 		const struct usb_ctrlrequest *ctrl)
 {
-	struct fsg_dev		*fsg = get_gadget_data(gadget);
+	struct fsg_dev		*fsg = get_usb_function_data(gadget);
 	int			rc;
-	int			w_length = le16_to_cpu(ctrl->wLength);
 
 	++fsg->ep0_req_tag;		// Record arrival of a new request
 	fsg->ep0req->context = NULL;
-	fsg->ep0req->length = 0;
+	if (is_composite()) {
+		fsg->ep0req->complete = ep0_complete;
+		gadget->ep0->driver_data = fsg;
+	}
+
 	dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
 
 	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
@@ -1511,16 +1522,6 @@ static int fsg_setup(struct usb_gadget *gadget,
 	else
 		rc = standard_setup_req(fsg, ctrl);
 
-	/* Respond with data/status or defer until later? */
-	if (rc >= 0 && rc != DELAYED_STATUS) {
-		rc = min(rc, w_length);
-		fsg->ep0req->length = rc;
-		fsg->ep0req->zero = rc < w_length;
-		fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
-				"ep0-in" : "ep0-out");
-		rc = ep0_queue(fsg);
-	}
-
 	/* Device either stalls (rc < 0) or reports success */
 	return rc;
 }
@@ -3399,7 +3400,8 @@ static void handle_exception(struct fsg_dev *fsg)
 
 	case FSG_STATE_CONFIG_CHANGE:
 		rc = do_set_config(fsg, new_config);
-		if (fsg->ep0_req_tag != exception_req_tag)
+		if (fsg->ep0_req_tag != exception_req_tag
+				|| is_composite())
 			break;
 		if (rc != 0)			// STALL on errors
 			fsg_set_halt(fsg, fsg->ep0);
@@ -3485,7 +3487,7 @@ static int fsg_main_thread(void *fsg_)
 	/* In case we are exiting because of a signal, unregister the
 	 * gadget driver and close the backing file. */
 	if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) {
-		usb_gadget_unregister_driver(&fsg_driver);
+		usb_func_unregister(&fsg_driver);
 		close_all_backing_files(fsg);
 	}
 
@@ -3704,14 +3706,18 @@ static void lun_release(struct device *dev)
 	kref_put(&fsg->ref, fsg_release);
 }
 
+
 static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
 {
-	struct fsg_dev		*fsg = get_gadget_data(gadget);
+	struct fsg_dev		*fsg = get_usb_function_data(gadget);
 	int			i;
 	struct lun		*curlun;
-	struct usb_request	*req = fsg->ep0req;
 
 	DBG(fsg, "unbind\n");
+
+	if (is_composite())
+		do_set_interface(fsg, -1);
+
 	clear_bit(REGISTERED, &fsg->atomic_bitflags);
 
 	/* Unregister the sysfs attribute files and the LUNs */
@@ -3742,16 +3748,6 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
 			usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma,
 					mod_data.buflen);
 	}
-
-	/* Free the request and buffer for endpoint 0 */
-	if (req) {
-		if (req->buf)
-			usb_ep_free_buffer(fsg->ep0, req->buf,
-					req->dma, EP0_BUFSIZE);
-		usb_ep_free_request(fsg->ep0, req);
-	}
-
-	set_gadget_data(gadget, NULL);
 }
 
 
@@ -3851,7 +3847,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	char			*pathbuf, *p;
 
 	fsg->gadget = gadget;
-	set_gadget_data(gadget, fsg);
+	fsg->f = get_usb_function(gadget);
+	set_usb_function_data(fsg->f, fsg);
 	fsg->ep0 = gadget->ep0;
 	fsg->ep0->driver_data = fsg;
 
@@ -3888,7 +3885,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 		curlun->ro = mod_data.ro[i];
 		curlun->dev.release = lun_release;
 		curlun->dev.parent = &gadget->dev;
-		curlun->dev.driver = &fsg_driver.driver;
+		curlun->dev.driver = gadget->dev.driver;
 		dev_set_drvdata(&curlun->dev, fsg);
 		snprintf(curlun->dev.bus_id, BUS_ID_SIZE,
 				"%s-lun%d", gadget->dev.bus_id, i);
@@ -3919,7 +3916,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	}
 
 	/* Find all the endpoints we will use */
-	usb_ep_autoconfig_reset(gadget);
 	ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc);
 	if (!ep)
 		goto autoconf_fail;
@@ -3972,13 +3968,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	rc = -ENOMEM;
 
 	/* Allocate the request and buffer for endpoint 0 */
-	fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
-	if (!req)
-		goto out;
-	req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE,
-			&req->dma, GFP_KERNEL);
-	if (!req->buf)
-		goto out;
+	fsg->ep0req = req = get_usb_gadget_request(gadget);
 	req->complete = ep0_complete;
 
 	/* Allocate the data buffers */
@@ -4074,7 +4064,7 @@ out:
 
 static void fsg_suspend(struct usb_gadget *gadget)
 {
-	struct fsg_dev		*fsg = get_gadget_data(gadget);
+	struct fsg_dev		*fsg = get_usb_function_data(gadget);
 
 	DBG(fsg, "suspend\n");
 	set_bit(SUSPENDED, &fsg->atomic_bitflags);
@@ -4082,7 +4072,7 @@ static void fsg_suspend(struct usb_gadget *gadget)
 
 static void fsg_resume(struct usb_gadget *gadget)
 {
-	struct fsg_dev		*fsg = get_gadget_data(gadget);
+	struct fsg_dev		*fsg = get_usb_function_data(gadget);
 
 	DBG(fsg, "resume\n");
 	clear_bit(SUSPENDED, &fsg->atomic_bitflags);
@@ -4091,30 +4081,23 @@ static void fsg_resume(struct usb_gadget *gadget)
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_gadget_driver		fsg_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	.speed		= USB_SPEED_HIGH,
-#else
-	.speed		= USB_SPEED_FULL,
-#endif
-	.function	= (char *) longname,
+static struct usb_function fsg_driver = {
+	.name		= (char *) shortname,
+	.strings	= &stringtab,
+
+	.num_conf	= 1,
+	.config[0]	= &config_desc,
+
 	.bind		= fsg_bind,
 	.unbind		= fsg_unbind,
-	.disconnect	= fsg_disconnect,
+
 	.setup		= fsg_setup,
+	.disconnect	= fsg_disconnect,
+
 	.suspend	= fsg_suspend,
 	.resume		= fsg_resume,
-
-	.driver		= {
-		.name		= (char *) shortname,
-		.owner		= THIS_MODULE,
-		// .release = ...
-		// .suspend = ...
-		// .resume = ...
-	},
 };
 
-
 static int __init fsg_alloc(void)
 {
 	struct fsg_dev		*fsg;
@@ -4140,7 +4123,7 @@ static int __init fsg_init(void)
 	if ((rc = fsg_alloc()) != 0)
 		return rc;
 	fsg = the_fsg;
-	if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
+	if ((rc = usb_func_register(&fsg_driver)) != 0)
 		kref_put(&fsg->ref, fsg_release);
 	return rc;
 }
@@ -4153,7 +4136,7 @@ static void __exit fsg_cleanup(void)
 
 	/* Unregister the driver iff the thread hasn't already done so */
 	if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
-		usb_gadget_unregister_driver(&fsg_driver);
+		usb_func_unregister(&fsg_driver);
 
 	/* Wait for the thread to finish up */
 	wait_for_completion(&fsg->thread_notifier);

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.