[2/2] usb: gadget: ffs: add ACM + FunctionFS configuration

Message ID 1376666868-32581-3-git-send-email-matt.porter@linaro.org
State Superseded
Headers show

Commit Message

Matt Porter Aug. 16, 2013, 3:27 p.m.
Adds an additional configuration to g_ffs to allow for
CDC ACM support in conjuction with FunctionFS. A module
parameter is added to allow for multiple ACM ports to
be instantiated.

Signed-off-by: Matt Porter <matt.porter@linaro.org>
---
 drivers/usb/gadget/Kconfig |    9 ++++++
 drivers/usb/gadget/g_ffs.c |   71 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)

Comments

Felipe Balbi Aug. 16, 2013, 3:32 p.m. | #1
On Fri, Aug 16, 2013 at 11:27:48AM -0400, Matt Porter wrote:
> Adds an additional configuration to g_ffs to allow for
> CDC ACM support in conjuction with FunctionFS. A module
> parameter is added to allow for multiple ACM ports to
> be instantiated.
> 
> Signed-off-by: Matt Porter <matt.porter@linaro.org>

the whole idea of the configfs interface was that we wouldn't add this
sort of patch to the kernel anymore. What's wrong with building your
device through configfs in userland ?
Matt Porter Aug. 16, 2013, 3:48 p.m. | #2
On 08/16/2013 11:32 AM, Felipe Balbi wrote:
> On Fri, Aug 16, 2013 at 11:27:48AM -0400, Matt Porter wrote:
>> Adds an additional configuration to g_ffs to allow for
>> CDC ACM support in conjuction with FunctionFS. A module
>> parameter is added to allow for multiple ACM ports to
>> be instantiated.
>>
>> Signed-off-by: Matt Porter <matt.porter@linaro.org>
>
> the whole idea of the configfs interface was that we wouldn't add this
> sort of patch to the kernel anymore. What's wrong with building your
> device through configfs in userland ?
>

That would be nice. Unless I missed it, we don't have support for ffs
via the gadget configfs framework. That's what drove this as I wanted 
ACM + a ffs driven function. I'll look into adding an ffs option.

Thanks,
Matt

Patch

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 1292a82..fa3c845 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -882,6 +882,15 @@  config USB_FUNCTIONFS_RNDIS
 	help
 	  Include a configuration with RNDIS function (Ethernet) and the Filesystem.
 
+config USB_FUNCTIONFS_ACM
+	bool "Include configuration with CDC ACM (Serial)"
+	depends on USB_FUNCTIONFS
+	select USB_U_SERIAL
+	select USB_F_ACM
+	help
+	  Include a configuration with CDC ACM function (Serial) and the
+	  Function Filesystem.
+
 config USB_FUNCTIONFS_GENERIC
 	bool "Include 'pure' configuration"
 	depends on USB_FUNCTIONFS
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index 686b776..0849d3c 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -53,6 +53,14 @@  USB_ETHERNET_MODULE_PARAMETERS();
 struct eth_dev;
 #endif
 
+static int acm_ports = 1;
+#ifdef CONFIG_USB_FUNCTIONFS_ACM
+#  include "u_serial.h"
+static int acm_bind_config(struct usb_configuration *c, int ports);
+module_param(acm_ports, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(acm_ports, "Number of ACM serial ports to instantiate");
+#endif
+
 #include "f_fs.c"
 
 #define DRIVER_NAME	"g_ffs"
@@ -127,6 +135,9 @@  static struct usb_string gfs_strings[] = {
 #ifdef CONFIG_USB_FUNCTIONFS_ETH
 	{ .s = "FunctionFS + ECM" },
 #endif
+#ifdef CONFIG_USB_FUNCTIONFS_ACM
+	{ .s = "FunctionFS + ACM" },
+#endif
 #ifdef CONFIG_USB_FUNCTIONFS_GENERIC
 	{ .s = "FunctionFS" },
 #endif
@@ -145,6 +156,7 @@  struct gfs_configuration {
 	struct usb_configuration c;
 	int (*eth)(struct usb_configuration *c, u8 *ethaddr,
 			struct eth_dev *dev);
+	int (*acm)(struct usb_configuration *c, int ports);
 } gfs_configurations[] = {
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
 	{
@@ -158,6 +170,12 @@  struct gfs_configuration {
 	},
 #endif
 
+#ifdef CONFIG_USB_FUNCTIONFS_ACM
+	{
+		.acm		= acm_bind_config,
+	},
+#endif
+
 #ifdef CONFIG_USB_FUNCTIONFS_GENERIC
 	{
 	},
@@ -456,6 +474,12 @@  static int gfs_do_config(struct usb_configuration *c)
 			return ret;
 	}
 
+	if (gc->acm) {
+		ret = gc->acm(c, acm_ports);
+		if (unlikely(ret < 0))
+			return ret;
+	}
+
 	for (i = 0; i < func_num; i++) {
 		ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data);
 		if (unlikely(ret < 0))
@@ -489,3 +513,50 @@  static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
 }
 
 #endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_ACM
+
+static struct usb_function_instance *fi[MAX_U_SERIAL_PORTS];
+static struct usb_function *f[MAX_U_SERIAL_PORTS];
+
+static int acm_bind_config(struct usb_configuration *c, int ports)
+{
+	int i, ret;
+
+	for (i = 0; i < ports; i++) {
+		fi[i] = usb_get_function_instance("acm");
+		if (IS_ERR(fi[i])) {
+			ret = PTR_ERR(fi[i]);
+			goto err_get_fi;
+		}
+
+		f[i] = usb_get_function(fi[i]);
+		if (IS_ERR(f[i])) {
+			ret = PTR_ERR(f[i]);
+			goto err_get_f;
+		}
+
+		ret = usb_add_function(c, f[i]);
+		if (ret)
+			goto err_add_f;
+	}
+
+	return 0;
+
+err_add_f:
+	usb_put_function(f[i]);
+err_get_f:
+	usb_put_function_instance(fi[i]);
+err_get_fi:
+	i--;
+	while (i >= 0) {
+		usb_remove_function(c, f[i]);
+		usb_put_function(f[i]);
+		usb_put_function_instance(fi[i]);
+		i--;
+	}
+
+	return ret;
+}
+
+#endif