Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PATCHv3 08/11] USB: gadget: g_multi: more configurable

272 views
Skip to first unread message

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:02 AM6/2/10
to
Added Kconfig options for each function used by g_multi so that
one can customize the gadget to a greater extend.

Note that it will be wise to change vendor and product ID when
customising the gadget.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---
Documentation/usb/gadget_multi.txt | 27 +++---
drivers/usb/gadget/Kconfig | 67 +++++++++-----
drivers/usb/gadget/multi.c | 166 ++++++++++++++++--------------------
3 files changed, 130 insertions(+), 130 deletions(-)

diff --git a/Documentation/usb/gadget_multi.txt b/Documentation/usb/gadget_multi.txt
index bd53a9f..65bccd8 100644
--- a/Documentation/usb/gadget_multi.txt
+++ b/Documentation/usb/gadget_multi.txt
@@ -2,20 +2,21 @@

* Overview

-The Multifunction Composite Gadget (or g_multi) is a composite gadget
-that makes extensive use of the composite framework to provide
-a... multifunction gadget.
+The Multifunction Composite Gadget (or g_multi) is a customisable
+composite gadget that makes extensive use of the composite framework
+to provide a... multifunction gadget.

In it's standard configuration it provides a single USB configuration
with RNDIS[1] (that is Ethernet), USB CDC[2] ACM (that is serial) and
USB Mass Storage functions.

-A CDC ECM (Ethernet) function may be turned on via a Kconfig option
-and RNDIS can be turned off. If they are both enabled the gadget will
-have two configurations -- one with RNDIS and another with CDC ECM[3].
+Each function can be disabled via a Kconfig option. There's also
+a CDC ECM (Ethernet) function which can be turned on. If CDC ECM and
+RNDIS are enabled the gadget will have two configurations -- one with
+RNDIS and another with CDC ECM[3].

-Please not that if you use non-standard configuration (that is enable
-CDC ECM) you may need to change vendor and/or product ID.
+Please not that if you use non-standard configuration you may need to
+change vendor and/or product ID.

* Host drivers

@@ -92,11 +93,11 @@ hesitate submitting it!

**** Customising the gadget

-If you intend to hack the g_multi gadget be advised that rearranging
-functions will obviously change interface numbers for each of the
-functionality. As an effect provided INFs won't work since they have
-interface numbers hard-coded in them (it's not hard to change those
-though).
+If you intend to customise (via Kconfig) or hack the g_multi gadget be
+advised that rearranging functions will obviously change interface
+numbers for each of the functionality. As an effect provided INFs
+won't work since they have interface numbers hard-coded in them (it's
+not hard to change those though).

This also means, that after experimenting with g_multi and changing
provided functions one should change gadget's vendor and/or product ID
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index c97f021..8052643 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -861,43 +861,62 @@ config USB_G_NOKIA

config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
- depends on BLOCK && NET
- select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
+ select USB_G_MULTI_ACM if !USB_G_MULTI_ANYTHING
help
- The Multifunction Composite Gadget provides Ethernet (RNDIS
- and/or CDC Ethernet), mass storage and ACM serial link
- interfaces.
-
- You will be asked to choose which of the two configurations is
- to be available in the gadget. At least one configuration must
- be chosen to make the gadget usable. Selecting more than one
- configuration will prevent Windows from automatically detecting
- the gadget as a composite gadget, so an INF file will be needed to
- use the gadget.
+ The Multifunction Composite Gadget provides several different
+ configurations and functions. Which interfaces are provided can
+ be configured at build time. If you choose this gadget additional
+ options will appear.

Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_multi".

-config USB_G_MULTI_RNDIS
- bool "RNDIS + CDC Serial + Storage configuration"
+config USB_G_MULTI_ANYTHING
+ bool
depends on USB_G_MULTI
+
+config USB_G_MULTI_RNDIS
+ bool "Include RNDIS function"
+ depends on USB_G_MULTI && NET
+ select USB_G_MULTI_ANYTHING
default y
help
- This option enables a configuration with RNDIS, CDC Serial and
- Mass Storage functions available in the Multifunction Composite
- Gadget. This is the configuration dedicated for Windows since RNDIS
- is Microsoft's protocol.
+ This option enables the RNDIS (Ethernet) function. It is
+ protocol dedicated for Windows since it's Microsoft's invention.
+
+ If you select also CDC ECM function gadget will have two
+ configurations one with RNDIS and another with CDC ECM.
+
+ If unsure, say "y".
+
+config USB_G_MULTI_ECM
+ bool "Include CDC ECM function"
+ depends on USB_G_MULTI && NET
+ select USB_G_MULTI_ANYTHING
+ help
+ This option enables the CDC ECM (Ethernet) function.
+
+ If you select also RNDIS function gadget will have two
+ configurations one with RNDIS and another with CDC ECM.

If unsure, say "y".

-config USB_G_MULTI_CDC
- bool "CDC Ethernet + CDC Serial + Storage configuration"
+config USB_G_MULTI_ACM
+ bool "Include CDC ACM function"
depends on USB_G_MULTI
- default n
+ default y
+ help
+ This option enables the CDC ACM (serial) function.
+
+ If unsure, say "y".
+
+config USB_G_MULTI_MSF
+ bool "Include mass storage function"
+ depends on USB_G_MULTI && BLOCK
+ select USB_G_MULTI_ANYTHING
+ default y
help
- This option enables a configuration with CDC Ethernet (ECM), CDC
- Serial and Mass Storage functions available in the Multifunction
- Composite Gadget.
+ This option enables the mass storage (or UMS) function.

If unsure, say "y".

diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index c7a5b58..6f6fd3e 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -57,19 +57,57 @@ MODULE_LICENSE("GPL");
#include "config.c"
#include "epautoconf.c"

-#include "f_mass_storage.c"
+/* Mass storage */
+#ifdef CONFIG_USB_G_MULTI_MSF
+# include "f_mass_storage.c"

-#include "u_serial.c"
-#include "f_acm.c"
+static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
+FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
+
+static struct fsg_common fsg_common;
+#else
+# define fsg_common_from_params(common, cdev, data) NULL
+# define fsg_bind_config(cdev, conf, common) ((int)0)
+# define fsg_common_put(common) do { } while (0)
+#endif

-#include "f_ecm.c"
-#include "f_subset.c"
-#ifdef USB_ETH_RNDIS
+/* CDC ACM */
+#ifdef CONFIG_USB_G_MULTI_ACM
+# include "u_serial.c"
+# include "f_acm.c"
+#else
+# define gserial_setup(conf, ports) ((int)0)
+# define gserial_cleanup() do { } while (0)
+# define acm_bind_config(conf, ports) ((int)0)
+#endif
+
+/* Ethernet */
+#ifdef CONFIG_USB_G_MULTI_ECM
+# include "f_ecm.c"
+# include "f_subset.c"
+#endif
+
+#ifdef CONFIG_USB_G_MULTI_RNDIS
# include "f_rndis.c"
# include "rndis.c"
#endif
-#include "u_ether.c"

+#if defined CONFIG_USB_G_MULTI_ECM || defined CONFIG_USB_G_MULTI_RNDIS
+# include "u_ether.c"
+static u8 hostaddr[ETH_ALEN];
+#else
+# define gether_setup(cdev, hostaddr) ((int)0)
+# define gether_cleanup() do { } while (0)
+#endif
+
+#ifndef CONFIG_USB_G_MULTI_ECM
+# define can_support_ecm(gadget) true
+# define ecm_bind_config(conf, ethaddr) ((int)0)
+#endif
+
+#ifndef CONFIG_USB_G_MULTI_RNDIS
+# define rndis_bind_config(conf, ethaddr) ((int)0)
+#endif


/***************************** Device Descriptor ****************************/
@@ -78,19 +116,6 @@ MODULE_LICENSE("GPL");
#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */


-enum {
- __MULTI_NO_CONFIG,
-#ifdef CONFIG_USB_G_MULTI_RNDIS
- MULTI_RNDIS_CONFIG_NUM,
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
- MULTI_CDC_CONFIG_NUM,
-#endif
- __MULTI_NUM_CONFIGS_HELPER,
- MULTI_NUM_CONFIGS = __MULTI_NUM_CONFIGS_HELPER - 1
-};
-
-
static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
@@ -104,7 +129,11 @@ static struct usb_device_descriptor device_desc = {
/* Vendor and product id can be overridden by module parameters. */
.idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
.idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),
- .bNumConfigurations = MULTI_NUM_CONFIGS,
+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM
+ .bNumConfigurations = 2,
+#else
+ .bNumConfigurations = 1,
+#endif
};


@@ -124,12 +153,6 @@ static const struct usb_descriptor_header *otg_desc[] = {
enum {
MULTI_STRING_MANUFACTURER_IDX,
MULTI_STRING_PRODUCT_IDX,
-#ifdef CONFIG_USB_G_MULTI_RNDIS
- MULTI_STRING_RNDIS_CONFIG_IDX,
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
- MULTI_STRING_CDC_CONFIG_IDX,
-#endif
};

static char manufacturer[50];
@@ -137,12 +160,6 @@ static char manufacturer[50];
static struct usb_string strings_dev[] = {
[MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
[MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC,
-#ifdef CONFIG_USB_G_MULTI_RNDIS
- [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
- [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM",
-#endif
{ } /* end of list */
};

@@ -159,19 +176,8 @@ static struct usb_gadget_strings *dev_strings[] = {

/****************************** Configurations ******************************/

-static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
-FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);

-static struct fsg_common fsg_common;
-
-static u8 hostaddr[ETH_ALEN];
-
-
-/********** RNDIS **********/
-
-#ifdef USB_ETH_RNDIS
-
-static __ref int rndis_do_config(struct usb_configuration *c)
+static __ref int first_do_config(struct usb_configuration *c)
{
int ret;

@@ -180,7 +186,11 @@ static __ref int rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}

+#ifdef CONFIG_USB_G_MULTI_RNDIS
ret = rndis_bind_config(c, hostaddr);
+#else
+ ret = ecm_bind_config(c, hostaddr);
+#endif
if (ret < 0)
return ret;

@@ -195,35 +205,17 @@ static __ref int rndis_do_config(struct usb_configuration *c)
return 0;
}

-static int rndis_config_register(struct usb_composite_dev *cdev)
-{
- static struct usb_configuration config = {
- .bind = rndis_do_config,
- .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,
- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- };
-
- config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
- config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
-
- return usb_add_config(cdev, &config);
-}
-
-#else
-
-static int rndis_config_register(struct usb_composite_dev *cdev)
-{
- return 0;
-}
-
-#endif
-
+static struct usb_configuration first_config_driver = {
+ .label = "First Configuration",
+ .bind = first_do_config,
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};

-/********** CDC ECM **********/

-#ifdef CONFIG_USB_G_MULTI_CDC
+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

-static __ref int cdc_do_config(struct usb_configuration *c)
+static __ref int second_do_config(struct usb_configuration *c)
{
int ret;

@@ -247,26 +239,12 @@ static __ref int cdc_do_config(struct usb_configuration *c)
return 0;
}

-static int cdc_config_register(struct usb_composite_dev *cdev)
-{
- static struct usb_configuration config = {
- .bind = cdc_do_config,
- .bConfigurationValue = MULTI_CDC_CONFIG_NUM,
- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- };
-
- config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
- config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
-
- return usb_add_config(cdev, &config);
-}
-
-#else
-
-static int cdc_config_register(struct usb_composite_dev *cdev)
-{
- return 0;
-}
+static struct usb_configuration second_config_driver = {
+ .label = "Second Configuration",
+ .bind = second_do_config,
+ .bConfigurationValue = 2,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};

#endif

@@ -331,13 +309,15 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
strings_dev[MULTI_STRING_PRODUCT_IDX].id;

/* register configurations */
- status = rndis_config_register(cdev);
+ status = usb_add_config(cdev, &first_config_driver);
if (unlikely(status < 0))
goto fail2;

- status = cdc_config_register(cdev);
+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM
+ status = usb_add_config(cdev, &second_config_driver);
if (unlikely(status < 0))
goto fail2;
+#endif

/* we're done */
dev_info(&gadget->dev, DRIVER_DESC "\n");
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:02 AM6/2/10
to
This patch changes msg_do_config() function so that it uses
a static object for a fsg_common structure instead of dynamically
allocated. This is a micro-optimisation.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/mass_storage.c | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index 705cc1f..a3349f2 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -143,7 +143,7 @@ static int msg_thread_exits(struct fsg_common *common)

static int __init msg_do_config(struct usb_configuration *c)
{
- struct fsg_common *common;
+ static struct fsg_common common, *retp;
struct fsg_config config;
int ret;

@@ -154,12 +154,13 @@ static int __init msg_do_config(struct usb_configuration *c)

fsg_config_from_params(&config, &mod_data);
config.thread_exits = msg_thread_exits;
- common = fsg_common_init(0, c->cdev, &config);
- if (IS_ERR(common))
- return PTR_ERR(common);

- ret = fsg_add(c->cdev, c, common);
- fsg_common_put(common);
+ retp = fsg_common_init(&common, c->cdev, &config);
+ if (IS_ERR(retp))
+ return PTR_ERR(retp);
+
+ ret = fsg_add(c->cdev, c, &common);
+ fsg_common_put(&common);
return ret;

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:03 AM6/2/10
to
FunctionFS had a bit unique name for function used to add it
to USB configuration. Renamed as to match naming convention
of other functions.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/f_fs.c | 6 +++---
drivers/usb/gadget/g_ffs.c | 2 +-
include/linux/usb/functionfs.h | 6 +++---
3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index d69eccf..3fe120f 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1480,9 +1480,9 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
}


-static int functionfs_add(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
- struct ffs_data *ffs)
+static int functionfs_bind_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *c,
+ struct ffs_data *ffs)
{
struct ffs_function *func;
int ret;
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index 4b0e4a0..2f26470 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -388,7 +388,7 @@ static int __gfs_do_config(struct usb_configuration *c,
return ret;
}

- ret = functionfs_add(c->cdev, c, gfs_ffs_data);
+ ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data);
if (unlikely(ret < 0))
return ret;

diff --git a/include/linux/usb/functionfs.h b/include/linux/usb/functionfs.h
index a34a2a0..6f649c1 100644
--- a/include/linux/usb/functionfs.h
+++ b/include/linux/usb/functionfs.h
@@ -180,9 +180,9 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
static void functionfs_unbind(struct ffs_data *ffs)
__attribute__((nonnull));

-static int functionfs_add(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
- struct ffs_data *ffs)
+static int functionfs_bind_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *c,
+ struct ffs_data *ffs)
__attribute__((warn_unused_result, nonnull));

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:03 AM6/2/10
to
The Multifunction Compasite Gadget have been cleaned up
and refactored so hopefully it looks prettier and works
at least as good as before changes.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/Kconfig | 1 +
drivers/usb/gadget/multi.c | 262 +++++++++++++++++++++++++-------------------
2 files changed, 148 insertions(+), 115 deletions(-)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 649c0c5..c97f021 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -862,6 +862,7 @@ config USB_G_NOKIA


config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"

depends on BLOCK && NET

+ select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
help


The Multifunction Composite Gadget provides Ethernet (RNDIS

and/or CDC Ethernet), mass storage and ACM serial link

diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index d3d3140..c7a5b58 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -24,6 +24,7 @@

#include <linux/kernel.h>
#include <linux/utsname.h>
+#include <linux/module.h>


#if defined USB_ETH_RNDIS
@@ -35,14 +36,13 @@


#define DRIVER_DESC "Multifunction Composite Gadget"
-#define DRIVER_VERSION "2009/07/21"

-/*-------------------------------------------------------------------------*/
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Michal Nazarewicz");
+MODULE_LICENSE("GPL");

-#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
-#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */

-/*-------------------------------------------------------------------------*/
+/***************************** All the files... *****************************/

/*
* kbuild is not very cooperative with respect to linking separately
@@ -57,6 +57,8 @@
#include "config.c"
#include "epautoconf.c"

+#include "f_mass_storage.c"
+
#include "u_serial.c"
#include "f_acm.c"

@@ -68,13 +70,26 @@
#endif
#include "u_ether.c"

-#undef DBG /* u_ether.c has broken idea about macros */
-#undef VDBG /* so clean up after it */
-#undef ERROR
-#undef INFO
-#include "f_mass_storage.c"

-/*-------------------------------------------------------------------------*/
+
+/***************************** Device Descriptor ****************************/
+
+#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
+#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */
+
+
+enum {
+ __MULTI_NO_CONFIG,
+#ifdef CONFIG_USB_G_MULTI_RNDIS
+ MULTI_RNDIS_CONFIG_NUM,
+#endif
+#ifdef CONFIG_USB_G_MULTI_CDC
+ MULTI_CDC_CONFIG_NUM,
+#endif
+ __MULTI_NUM_CONFIGS_HELPER,
+ MULTI_NUM_CONFIGS = __MULTI_NUM_CONFIGS_HELPER - 1
+};
+



static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,

@@ -82,80 +97,81 @@ static struct usb_device_descriptor device_desc = {

.bcdUSB = cpu_to_le16(0x0200),

- /* .bDeviceClass = USB_CLASS_COMM, */
- /* .bDeviceSubClass = 0, */
- /* .bDeviceProtocol = 0, */
- .bDeviceClass = 0xEF,
+ .bDeviceClass = USB_CLASS_MISC /* 0xEF */,
.bDeviceSubClass = 2,
.bDeviceProtocol = 1,
- /* .bMaxPacketSize0 = f(hardware) */



/* Vendor and product id can be overridden by module parameters. */
.idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
.idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),

- /* .bcdDevice = f(hardware) */
- /* .iManufacturer = DYNAMIC */
- /* .iProduct = DYNAMIC */
- /* NO SERIAL NUMBER */
- .bNumConfigurations = 1,
+ .bNumConfigurations = MULTI_NUM_CONFIGS,
};

-static struct usb_otg_descriptor otg_descriptor = {
- .bLength = sizeof otg_descriptor,
- .bDescriptorType = USB_DT_OTG,
-
- /* REVISIT SRP-only hardware is possible, although
- * it would not be called "OTG" ...
- */
- .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
-};



static const struct usb_descriptor_header *otg_desc[] = {

- (struct usb_descriptor_header *) &otg_descriptor,
+ (struct usb_descriptor_header *) &(struct usb_otg_descriptor){
+ .bLength = sizeof(struct usb_otg_descriptor),
+ .bDescriptorType = USB_DT_OTG,
+
+ /* REVISIT SRP-only hardware is possible, although
+ * it would not be called "OTG" ... */
+ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
+ },
NULL,
};


-/* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX 0
-#define STRING_PRODUCT_IDX 1
+enum {
+ MULTI_STRING_MANUFACTURER_IDX,
+ MULTI_STRING_PRODUCT_IDX,
+#ifdef CONFIG_USB_G_MULTI_RNDIS
+ MULTI_STRING_RNDIS_CONFIG_IDX,
+#endif
+#ifdef CONFIG_USB_G_MULTI_CDC
+ MULTI_STRING_CDC_CONFIG_IDX,
+#endif
+};



static char manufacturer[50];

static struct usb_string strings_dev[] = {

- [STRING_MANUFACTURER_IDX].s = manufacturer,
- [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+ [MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
+ [MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC,
+#ifdef CONFIG_USB_G_MULTI_RNDIS
+ [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
+#endif
+#ifdef CONFIG_USB_G_MULTI_CDC
+ [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM",
+#endif


{ } /* end of list */
};

-static struct usb_gadget_strings stringtab_dev = {
- .language = 0x0409, /* en-us */
- .strings = strings_dev,
-};
-


static struct usb_gadget_strings *dev_strings[] = {

- &stringtab_dev,
+ &(struct usb_gadget_strings){
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+ },
NULL,
};

-static u8 hostaddr[ETH_ALEN];



/****************************** Configurations ******************************/

-static struct fsg_module_parameters mod_data = {
- .stall = 1
-};
-FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);


+static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
+FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
+
+static struct fsg_common fsg_common;
+

+static u8 hostaddr[ETH_ALEN];

-static struct fsg_common *fsg_common;

+/********** RNDIS **********/

#ifdef USB_ETH_RNDIS

-static int __init rndis_do_config(struct usb_configuration *c)
+static __ref int rndis_do_config(struct usb_configuration *c)
{
int ret;

@@ -172,26 +188,42 @@ static int __init rndis_do_config(struct usb_configuration *c)
if (ret < 0)
return ret;

- ret = fsg_bind_config(c->cdev, c, fsg_common);
+ ret = fsg_bind_config(c->cdev, c, &fsg_common);


if (ret < 0)
return ret;

return 0;
}

-static struct usb_configuration rndis_config_driver = {
- .label = "Multifunction Composite (RNDIS + MS + ACM)",
- .bind = rndis_do_config,
- .bConfigurationValue = 2,
- /* .iConfiguration = DYNAMIC */


- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};

+static int rndis_config_register(struct usb_composite_dev *cdev)
+{
+ static struct usb_configuration config = {
+ .bind = rndis_do_config,
+ .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,


+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
+ config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
+
+ return usb_add_config(cdev, &config);
+}
+
+#else
+
+static int rndis_config_register(struct usb_composite_dev *cdev)
+{
+ return 0;
+}

#endif

+
+/********** CDC ECM **********/
+
#ifdef CONFIG_USB_G_MULTI_CDC

-static int __init cdc_do_config(struct usb_configuration *c)
+static __ref int cdc_do_config(struct usb_configuration *c)
{
int ret;

@@ -208,20 +240,33 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (ret < 0)
return ret;

- ret = fsg_bind_config(c->cdev, c, fsg_common);
+ ret = fsg_bind_config(c->cdev, c, &fsg_common);


if (ret < 0)
return ret;

return 0;
}

-static struct usb_configuration cdc_config_driver = {
- .label = "Multifunction Composite (CDC + MS + ACM)",
- .bind = cdc_do_config,
- .bConfigurationValue = 1,
- /* .iConfiguration = DYNAMIC */


- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};

+static int cdc_config_register(struct usb_composite_dev *cdev)
+{
+ static struct usb_configuration config = {
+ .bind = cdc_do_config,
+ .bConfigurationValue = MULTI_CDC_CONFIG_NUM,


+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
+ config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
+
+ return usb_add_config(cdev, &config);
+}
+
+#else
+
+static int cdc_config_register(struct usb_composite_dev *cdev)
+{
+ return 0;
+}

#endif

@@ -230,7 +275,7 @@ static struct usb_configuration cdc_config_driver = {
/****************************** Gadget Bind ******************************/


-static int __init multi_bind(struct usb_composite_dev *cdev)
+static int __ref multi_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
int status, gcnum;
@@ -252,67 +297,57 @@ static int __init multi_bind(struct usb_composite_dev *cdev)
goto fail0;

/* set up mass storage function */
- fsg_common = fsg_common_from_params(0, cdev, &mod_data);
- if (IS_ERR(fsg_common)) {
- status = PTR_ERR(fsg_common);
- goto fail1;
+ {
+ void *retp;
+ retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
+ if (IS_ERR(retp)) {
+ status = PTR_ERR(retp);
+ goto fail1;
+ }
}

-
+ /* set bcdDevice */
gcnum = usb_gadget_controller_number(gadget);
- if (gcnum >= 0)
+ if (gcnum >= 0) {
device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
- else {
- /* We assume that can_support_ecm() tells the truth;
- * but if the controller isn't recognized at all then
- * that assumption is a bit more likely to be wrong.
- */
- WARNING(cdev, "controller '%s' not recognized\n",
- gadget->name);
+ } else {
+ WARNING(cdev, "controller '%s' not recognized\n", gadget->name);
device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
}

+ /* allocate string descriptor numbers */

- /* Allocate string descriptor numbers ... note that string
- * contents can be overridden by the composite_dev glue.
- */
-
- /* device descriptor strings: manufacturer, product */
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
gadget->name);
- status = usb_string_id(cdev);
- if (status < 0)
- goto fail2;
- strings_dev[STRING_MANUFACTURER_IDX].id = status;
- device_desc.iManufacturer = status;

- status = usb_string_id(cdev);
- if (status < 0)
+ status = usb_string_ids_tab(cdev, strings_dev);
+ if (unlikely(status < 0))
goto fail2;
- strings_dev[STRING_PRODUCT_IDX].id = status;
- device_desc.iProduct = status;

-#ifdef USB_ETH_RNDIS
- /* register our first configuration */
- status = usb_add_config(cdev, &rndis_config_driver);
- if (status < 0)
+ device_desc.iManufacturer =
+ strings_dev[MULTI_STRING_MANUFACTURER_IDX].id;
+ device_desc.iProduct =
+ strings_dev[MULTI_STRING_PRODUCT_IDX].id;
+
+ /* register configurations */
+ status = rndis_config_register(cdev);
+ if (unlikely(status < 0))
goto fail2;
-#endif

-#ifdef CONFIG_USB_G_MULTI_CDC
- /* register our second configuration */
- status = usb_add_config(cdev, &cdc_config_driver);
- if (status < 0)
+ status = cdc_config_register(cdev);
+ if (unlikely(status < 0))
goto fail2;
-#endif

- dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
- fsg_common_put(fsg_common);
+ /* we're done */
+ dev_info(&gadget->dev, DRIVER_DESC "\n");
+ fsg_common_put(&fsg_common);
return 0;

+
+ /* error recovery */
fail2:
- fsg_common_put(fsg_common);
+ fsg_common_put(&fsg_common);
fail1:
gserial_cleanup();
fail0:
@@ -339,18 +374,15 @@ static struct usb_composite_driver multi_driver = {
.unbind = __exit_p(multi_unbind),
};

-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Michal Nazarewicz");
-MODULE_LICENSE("GPL");

-static int __init g_multi_init(void)
+static int __init multi_init(void)
{
return usb_composite_register(&multi_driver);
}
-module_init(g_multi_init);
+module_init(multi_init);

-static void __exit g_multi_cleanup(void)
+static void __exit multi_exit(void)
{
usb_composite_unregister(&multi_driver);
}
-module_exit(g_multi_cleanup);
+module_exit(multi_exit);

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:04 AM6/2/10
to
Mass Storage Function had a bit unique name for function

used to add it to USB configuration. Renamed as to match
naming convention of other functions.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/f_mass_storage.c | 13 ++++++++++---
drivers/usb/gadget/mass_storage.c | 2 +-
drivers/usb/gadget/multi.c | 4 ++--
3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 7d05a0b..072cbf9 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -3023,9 +3023,9 @@ static struct usb_gadget_strings *fsg_strings_array[] = {
NULL,
};

-static int fsg_add(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
- struct fsg_common *common)
+static int fsg_bind_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *c,
+ struct fsg_common *common)
{
struct fsg_dev *fsg;
int rc;
@@ -3072,6 +3072,13 @@ error_free_fsg:
return rc;
}

+static inline int __deprecated __maybe_unused
+fsg_add(struct usb_composite_dev *cdev,
+ struct usb_configuration *c,
+ struct fsg_common *common)
+{
+ return fsg_bind_config(cdev, c, common);
+}


/************************* Module parameters *************************/
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index a3349f2..d6975f4 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -159,7 +159,7 @@ static int __init msg_do_config(struct usb_configuration *c)
if (IS_ERR(retp))
return PTR_ERR(retp);

- ret = fsg_add(c->cdev, c, &common);
+ ret = fsg_bind_config(c->cdev, c, &common);
fsg_common_put(&common);
return ret;
}
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index a930d7f..d3d3140 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -172,7 +172,7 @@ static int __init rndis_do_config(struct usb_configuration *c)


if (ret < 0)
return ret;

- ret = fsg_add(c->cdev, c, fsg_common);
+ ret = fsg_bind_config(c->cdev, c, fsg_common);


if (ret < 0)
return ret;

@@ -208,7 +208,7 @@ static int __init cdc_do_config(struct usb_configuration *c)


if (ret < 0)
return ret;

- ret = fsg_add(c->cdev, c, fsg_common);
+ ret = fsg_bind_config(c->cdev, c, fsg_common);
if (ret < 0)

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:04 AM6/2/10
to
usb_string_ids_tab() and usb_string_ids_n() functions added to
the composite framework. The first accepts an array of
usb_string object and for each registeres a string id and the
second registeres a given number of ids and returns the first.

This may simplify string ids registration since gadgets and
composite functions won't have to call usb_string_id() several
times and each time check for errer status -- all this will be
done with a single call.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/composite.c | 71 +++++++++++++++++++++++++++++++++++++--
include/linux/usb/composite.h | 4 ++
2 files changed, 71 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 391d169..125167e 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -673,20 +673,83 @@ static int get_string(struct usb_composite_dev *cdev,
* string IDs. Drivers for functions, configurations, or gadgets will
* then store that ID in the appropriate descriptors and string table.
*
- * All string identifier should be allocated using this routine, to
- * ensure that for example different functions don't wrongly assign
- * different meanings to the same identifier.
+ * All string identifier should be allocated using this,
+ * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure
+ * that for example different functions don't wrongly assign different
+ * meanings to the same identifier.
*/
int usb_string_id(struct usb_composite_dev *cdev)
{
if (cdev->next_string_id < 254) {
- /* string id 0 is reserved */
+ /* string id 0 is reserved by USB spec for list of
+ * supported languages */
+ /* 255 reserved as well? -- mina86 */
cdev->next_string_id++;
return cdev->next_string_id;
}
return -ENODEV;
}

+/**
+ * usb_string_ids() - allocate unused string IDs in batch
+ * @cdev: the device whose string descriptor IDs are being allocated
+ * @str: an array of usb_string objects to assign numbers to
+ * Context: single threaded during gadget setup
+ *
+ * @usb_string_ids() is called from bind() callbacks to allocate
+ * string IDs. Drivers for functions, configurations, or gadgets will
+ * then copy IDs from the string table to the appropriate descriptors
+ * and string table for other languages.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
+ * example different functions don't wrongly assign different meanings
+ * to the same identifier.
+ */
+int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
+{
+ int next = cdev->next_string_id;
+
+ for (; str->s; ++str) {
+ if (unlikely(next >= 254))
+ return -ENODEV;
+ str->id = ++next;
+ }
+
+ cdev->next_string_id = next;


+
+ return 0;
+}

+
+/**
+ * usb_string_ids_n() - allocate unused string IDs in batch
+ * @cdev: the device whose string descriptor IDs are being allocated
+ * @n: number of string IDs to allocate
+ * Context: single threaded during gadget setup
+ *
+ * Returns the first requested ID. This ID and next @n-1 IDs are now
+ * valid IDs. At least providind that @n is non zore because if it
+ * is, returns last requested ID which is now very useful information.
+ *
+ * @usb_string_ids_n() is called from bind() callbacks to allocate
+ * string IDs. Drivers for functions, configurations, or gadgets will
+ * then store that ID in the appropriate descriptors and string table.
+ *
+ * All string identifier should be allocated using this,
+ * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
+ * example different functions don't wrongly assign different meanings
+ * to the same identifier.
+ */
+int usb_string_ids_n(struct usb_composite_dev *c, unsigned n)
+{
+ unsigned next = c->next_string_id;
+ if (unlikely(n > 254 || (unsigned)next + n > 254))
+ return -ENODEV;
+ c->next_string_id += n;
+ return next + 1;
+}
+
+
/*-------------------------------------------------------------------------*/

static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 139353e..f378075 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -342,6 +342,10 @@ struct usb_composite_dev {
};

extern int usb_string_id(struct usb_composite_dev *c);
+extern int usb_string_ids_tab(struct usb_composite_dev *c,
+ struct usb_string *str);
+extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
+

/* messaging utils */
#define DBG(d, fmt, args...) \

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:04 AM6/2/10
to
Added an Install Mode to the Multifunction Composite Gadget. This
mode makes the gadget appear as a mass storage device with first
logical unit simulating CD-ROM until an eject on that logical unit
is requested because then gadget switches to the "full flagged"
gadget.

The intend is that in Install Mode the gadget will provide only
a CD-ROM with drivers for host platform. After the drivers are
intstalled the gadget will switch to the proper gadget and the
newly installed drivers will handle it.

When the device is disconnected form the host machine (or host
reboots or whatever that couses suspend or disconnect) the gadget
will switch to Install Mode again.

Because disconnect is a normal situation on re-enumeration gadget
"ignores" all disconnects and suspends during the first 10 seconds
after an eject.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Documentation/usb/gadget_multi.txt | 61 ++++
drivers/usb/gadget/Kconfig | 22 ++
drivers/usb/gadget/multi.c | 596 +++++++++++++++++++++++++++++-------
3 files changed, 567 insertions(+), 112 deletions(-)

diff --git a/Documentation/usb/gadget_multi.txt b/Documentation/usb/gadget_multi.txt
index 65bccd8..9319f1d 100644
--- a/Documentation/usb/gadget_multi.txt
+++ b/Documentation/usb/gadget_multi.txt
@@ -18,6 +18,11 @@ RNDIS and another with CDC ECM[3].


Please not that if you use non-standard configuration you may need to
change vendor and/or product ID.

+The driver provides also an "install mode" which you may also call
+NoCD ore ZereCD (expect the later is a trademark) which lets one
+develop an image with drivers which install automatically on systems
+like Windows.
+
* Host drivers

To make use of the gadget one needs to make it work on host side --
@@ -35,6 +40,10 @@ This is also true for two configuration set-up with RNDIS
configuration being the first one. Linux host will use the second
configuration with CDC ECM which should work better under Linux.

+The only exception is when install mode is enabled in which case the
+gadget will appear as a plain mass storage device unless it is
+ejected. Read appropriate section of this document to find out more.
+
** Windows host drivers

For the gadget two work under Windown two conditions have to be met:
@@ -129,6 +138,54 @@ For more exotic systems I have even less to say...

Any testing and drivers *are* *welcome*!

+* Install mode
+
+The install mode makes the gadget appear as a plain mass storage
+device the first time it is connected (and after each disconnect).
+This lets one develop an "autorun" CD-ROM image with drivers and put
+it as the first logical unit.
+
+** Workings of the install mode
+
+As you may know, mass storage gadget may provide several logical units
+and its easier to think of them as separate drives. When install mode
+is enabled, g_multi forces the first logical unit to be a read-only
+CD-ROM. When install mode is enabled but mass storage itself is not
+then exactly one logical unit is set.
+
+When an eject request is made on that logical unit, the file is not
+really closed but the gadget switches it's mode to the full flagged
+gadget with all the other functions. If mass storage is among them,
+the firs logical unit will be the CD-ROM image with drivers (which may
+be seen as a bad thing).
+
+When gadget is disconnected and connected afterwards it will work
+again in install mode. Some heuristics are used here -- if
+disconnection (or suspend) happens no longer then 10 seconds after
+last eject on the first logical unit then on next enumeration gadget
+will claim to be full flagged otherwise it'll stick to install mode.
+
+** Interoperability with host
+
+As said, the idea behind install mode is that hosts that require
+drivers will be able to get them without the need for additional
+CD-ROM or another medium provided with the device.
+
+CD-ROM image should provide an "autorun" functionality witch will
+install drivers and eject the emulated CD-ROM to switch gadget into
+the other mode which will be handled by newly installed drivers. If
+drivers are installed already, they should "catch" the install mode
+device by product and vendor IDs and issue an eject.
+
+This mode is not very Linux-friendly though since Linux and Linux
+based systems have no notion of autorun (which from security point of
+view is a good thing) and there's no way of adding some file on the
+image which will make gadget eject the device.
+
+Fortunately, there's USB_ModeSwitch[8] and/or udev[9] which
+should handle it just fine. A single rule need to be added and
+everything should work fine.
+
* Authors

This document has been written by Michal Nazarewicz
@@ -158,3 +215,7 @@ any user input.
[7] Possibility to say `git rev-list --author='Your Name'
linus/master|wc -l` returns non-zero -- priceless. :]

+[8] [[http://www.draisberghof.de/usb_modeswitch/]]
+
+[9] [[http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html]]
+
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 8052643..21500eb 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -920,6 +920,28 @@ config USB_G_MULTI_MSF



If unsure, say "y".

+config USB_G_MULTI_INSTALL
+ bool "Install Mode"


+ depends on USB_G_MULTI && BLOCK

+ default n
+ help
+ This option enables an "Install Mode" configuration. You may
+ also refer to in as NoCD or ZeroCD (although the later is
+ a trademark).
+
+ This mode makes gadget appear as an USB Mass Storage device
+ emulating a CD-ROM the first time it is connected. The intend
+ is that you can put drivers for your gadget on the disk image.
+
+ When eject request is sent to the logical translation unit
+ gadget switches its mode to the full flagged gadget with all the
+ other functions.
+
+ When device is disconnected, gadget once again switches to the
+ Install Mode configuration.
+
+ If unsure, say "n".
+
config USB_G_HID
tristate "HID Gadget"
help
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 6f6fd3e..4aab815 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -25,6 +25,8 @@
#include <linux/kernel.h>
#include <linux/utsname.h>
#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>


#if defined USB_ETH_RNDIS
@@ -57,18 +59,27 @@ MODULE_LICENSE("GPL");
#include "config.c"
#include "epautoconf.c"

-/* Mass storage */
-#ifdef CONFIG_USB_G_MULTI_MSF
+/* Mass storage & Install Mode */
+#if defined CONFIG_USB_G_MULTI_MSF || defined CONFIG_USB_G_MULTI_INSTALL
# include "f_mass_storage.c"
-


static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };

FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
-
static struct fsg_common fsg_common;
#else
-# define fsg_common_from_params(common, cdev, data) NULL


# define fsg_bind_config(cdev, conf, common) ((int)0)

-# define fsg_common_put(common) do { } while (0)
+#endif
+
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+static unsigned install_mode = 1, next_install_mode = 1;
+#else
+# define install_mode false
+# define next_install_mode false
+#endif
+
+#ifdef CONFIG_USB_G_MULTI_MSF
+# define have_fsg true
+#else
+# define have_fsg false
#endif

/* CDC ACM */
@@ -76,8 +87,6 @@ static struct fsg_common fsg_common;
# include "u_serial.c"
# include "f_acm.c"
#else
-# define gserial_setup(conf, ports) ((int)0)
-# define gserial_cleanup() do { } while (0)
# define acm_bind_config(conf, ports) ((int)0)
#endif

@@ -95,9 +104,6 @@ static struct fsg_common fsg_common;
#if defined CONFIG_USB_G_MULTI_ECM || defined CONFIG_USB_G_MULTI_RNDIS
# include "u_ether.c"
static u8 hostaddr[ETH_ALEN];
-#else
-# define gether_setup(cdev, hostaddr) ((int)0)
-# define gether_cleanup() do { } while (0)
#endif

#ifndef CONFIG_USB_G_MULTI_ECM
@@ -110,14 +116,34 @@ static u8 hostaddr[ETH_ALEN];
#endif


+/******************************** Prototypes ********************************/
+
+static unsigned long multi_initialised;
+
+static int multi_setup(struct usb_composite_dev *cdev);
+static void multi_cleanup(void);
+static int multi_bind(struct usb_composite_dev *cdev);
+static int multi_register(void);
+static void multi_unregister(void);
+
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+static int multi_eject(struct fsg_common *common,
+ struct fsg_lun *lun, int num);
+static void multi_disconnect(struct usb_composite_dev *cdev);
+#else
+# define multi_disconnect NULL
+#endif
+
+
+
/***************************** Device Descriptor ****************************/

+/* Main device */


#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */

#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */

-

-static struct usb_device_descriptor device_desc = {
- .bLength = sizeof device_desc,
+static struct usb_device_descriptor multi_device_desc = {
+ .bLength = sizeof multi_device_desc,
.bDescriptorType = USB_DT_DEVICE,

.bcdUSB = cpu_to_le16(0x0200),
@@ -136,7 +162,31 @@ static struct usb_device_descriptor device_desc = {
#endif
};

+/* Install mode */
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+
+#define MULTI_INSTALL_VENDOR_NUM 0x0525 /* XXX NetChip */
+#define MULTI_INSTALL_PRODUCT_NUM 0xa4ad /* XXX */
+
+static struct usb_device_descriptor install_mode_device_desc = {
+ .bLength = sizeof install_mode_device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = cpu_to_le16(0x0200),
+
+ .bDeviceClass = USB_CLASS_MASS_STORAGE,
+ .bDeviceSubClass = USB_SC_SCSI,
+ .bDeviceProtocol = USB_PR_BULK,

+ /* Vendor and product id can be overridden by module parameters. */
+ .idVendor = cpu_to_le16(MULTI_INSTALL_VENDOR_NUM),
+ .idProduct = cpu_to_le16(MULTI_INSTALL_PRODUCT_NUM),
+ .bNumConfigurations = 1,
+};
+
+#endif
+
+/* Other descs */


static const struct usb_descriptor_header *otg_desc[] = {

(struct usb_descriptor_header *) &(struct usb_otg_descriptor){

.bLength = sizeof(struct usb_otg_descriptor),
@@ -150,9 +200,17 @@ static const struct usb_descriptor_header *otg_desc[] = {
};


+/* Strings */
enum {
MULTI_STRING_MANUFACTURER_IDX,
MULTI_STRING_PRODUCT_IDX,
+ MULTI_STRING_FIRST_CFG_IDX,


+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

+ MULTI_STRING_SECOND_CFG_IDX,
+#endif
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ MULTI_STRING_INSTALL_MODE_IDX,
+#endif
};

static char manufacturer[50];
@@ -160,24 +218,42 @@ static char manufacturer[50];


static struct usb_string strings_dev[] = {
[MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
[MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC,

+ [MULTI_STRING_FIRST_CFG_IDX].s = "First Configuration",


+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

+ [MULTI_STRING_SECOND_CFG_IDX].s = "Second Configuration",
+#endif
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ [MULTI_STRING_INSTALL_MODE_IDX].s = "Install Mode [NoCD]",
+#endif


{ } /* end of list */
};

-static struct usb_gadget_strings *dev_strings[] = {
- &(struct usb_gadget_strings){


- .language = 0x0409, /* en-us */
- .strings = strings_dev,

+/* The driver */
+static struct usb_composite_driver multi_driver = {
+ .name = "g_multi",
+ .dev = &multi_device_desc,
+ .strings = (struct usb_gadget_strings *[]) {


+ &(struct usb_gadget_strings) {
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+ },

+ NULL,
},
- NULL,
+ .bind = multi_bind,
+ .disconnect = multi_disconnect,
+ .suspend = multi_disconnect,
};

-
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+# define device_desc (*(struct usb_device_descriptor *)multi_driver.dev)
+#else
+# define device_desc multi_device_desc
+#endif


/****************************** Configurations ******************************/

-
-static __ref int first_do_config(struct usb_configuration *c)
+static int first_do_config(struct usb_configuration *c)
{
int ret;

@@ -186,36 +262,51 @@ static __ref int first_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}

+ /* First configuration can have either RNDIS or ECM. This
+ * depends on wthether RNDIS is turned on. If it is then
+ * first config is always RNDIS because even if ECM is on as
+ * well it is the second config. */


#ifdef CONFIG_USB_G_MULTI_RNDIS
ret = rndis_bind_config(c, hostaddr);

#else
ret = ecm_bind_config(c, hostaddr);
#endif
- if (ret < 0)
+ if (unlikely(ret < 0))
return ret;

ret = acm_bind_config(c, 0);
- if (ret < 0)
+ if (unlikely(ret < 0))
return ret;

- ret = fsg_bind_config(c->cdev, c, &fsg_common);
- if (ret < 0)
- return ret;
+ if (have_fsg) {
+ /* We need to check if we want mass storage since it
+ * may have been forced on by the install mode even
+ * though user does not want it in the proper USB
+ * configurations. */


+ ret = fsg_bind_config(c->cdev, c, &fsg_common);

+ if (unlikely(ret < 0))
+ return ret;
+ }

return 0;
}

-static struct usb_configuration first_config_driver = {
- .label = "First Configuration",
- .bind = first_do_config,
- .bConfigurationValue = 1,


- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};
-

+static int add_first_config(struct usb_composite_dev *cdev)
+{
+ static struct usb_configuration driver = {


+ .bind = first_do_config,
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ driver.iConfiguration = strings_dev[MULTI_STRING_FIRST_CFG_IDX].id;
+ driver.label = strings_dev[MULTI_STRING_FIRST_CFG_IDX].s;
+ return usb_add_config(cdev, &driver);
+}



#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

-static __ref int second_do_config(struct usb_configuration *c)
+static int second_do_config(struct usb_configuration *c)
{
int ret;

@@ -225,144 +316,425 @@ static __ref int second_do_config(struct usb_configuration *c)
}

ret = ecm_bind_config(c, hostaddr);
- if (ret < 0)
+ if (unlikely(ret < 0))
return ret;

ret = acm_bind_config(c, 0);
- if (ret < 0)
+ if (unlikely(ret < 0))
return ret;

- ret = fsg_bind_config(c->cdev, c, &fsg_common);
- if (ret < 0)
- return ret;
+ if (have_fsg) {
+ /* We need to check if we want mass storage since it
+ * may have been forced on by the install mode even
+ * though user does not want it in the proper USB
+ * configurations. */


+ ret = fsg_bind_config(c->cdev, c, &fsg_common);

+ if (unlikely(ret < 0))
+ return ret;
+ }

return 0;
}

-static struct usb_configuration second_config_driver = {
- .label = "Second Configuration",
- .bind = second_do_config,
- .bConfigurationValue = 2,


- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};

+static int add_second_config(struct usb_composite_dev *cdev)
+{
+ static struct usb_configuration driver = {


+ .bind = second_do_config,
+ .bConfigurationValue = 2,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ driver.iConfiguration = strings_dev[MULTI_STRING_FIRST_CFG_IDX].id;
+ driver.label = strings_dev[MULTI_STRING_FIRST_CFG_IDX].s;
+ return usb_add_config(cdev, &driver);
+}
+
+#else
+
+static int add_second_config(struct usb_composite_dev *cdev)


+{
+ return 0;
+}

+
+#endif
+
+
+/********************************* Worker ********************************/
+
+#if defined CONFIG_USB_G_MULTI_INSTALL
+
+#ifdef MODULE
+static unsigned multi_exiting;
+#else
+# define multi_exiting false
+#endif
+
+
+static void multi_worker_func(struct work_struct *work)
+{
+ /* Make sure, the next state is read corretly. */
+ smp_rmb();
+
+ /* multi_exit() has been called -- no need to do anything. */
+ if (multi_exiting)
+ return;
+
+ /* Switch only if anything actually changes. */
+ if (!test_bit(0, &multi_initialised))
+ goto unregistered;

+ if (install_mode != next_install_mode)
+ goto registered;
+
+ /* Ther's no reason to re-enumerate. */
+ return;
+
+
+registered:
+ /* Unregister the driver to force re-enumeration. */
+ multi_unregister();
+ msleep(5);
+
+unregistered:
+ /* While we were waiting the next state could change, so make
+ * sure we are reading the changed state. This is not critical
+ * since another worker will be scheduled anyways (see
+ * multi_worker_schedule()) but we could avoid unnecesary
+ * switch. On the other hand this barier is critical for
+ * cheking multi_exiting, read further. */
+ smp_rmb();
+
+ /* As we were waiting, multi_exit() has been called. */
+ if (multi_exiting)
+ return;
+
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ install_mode = next_install_mode;
#endif

+ multi_register();
+}
+
+/* Configuration switching can be requested from different contexts so
+ * to avoid any troubles which may arrise from the fact that IRQs are
+ * disabled, USB functions are in unknown state, etc. we introduce
+ * a worker which does all that. It also allows the job to be done
+ * after some delay. For instance after eject let the mass storage
+ * function settle down. */
+static DECLARE_DELAYED_WORK(multi_worker, multi_worker_func);
+
+static void multi_worker_exit(void)
+{
+ multi_exiting = 1;
+ /* See description of the usage of smp_rmb() in
+ * multi_worker_func(). */
+ smp_wmb();
+ cancel_delayed_work_sync(&multi_worker);
+}
+
+static void multi_worker_schedule(void)
+{
+ /* Make sure the new stats is written before worker starts. */
+ smp_wmb();
+ /* Cancel or wait for completion if worker is scheduled. */
+ cancel_delayed_work(&multi_worker);
+ /* Run the worker with a 1/64 of a second (~15 ms) delay to
+ * let everything settle up. */
+ schedule_delayed_work(&multi_worker, HZ >> 6);
+}
+
+# define __dyn_init
+# define __dyn_ref
+# define __dyn_exit
+#else
+# define __dyn_init __init
+# define __dyn_ref __ref
+# define __dyn_exit __exit
+# define multi_worker_exit() do { } while (0)
+#endif
+
+
+/****************************** Install Mode *****************************/
+
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+
+static int install_mode_do_config(struct usb_configuration *c)
+{
+ if (gadget_is_otg(c->cdev->gadget)) {
+ c->descriptors = otg_desc;
+ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+ return fsg_bind_config(c->cdev, c, &fsg_common);
+}
+
+static int add_install_mode_config(struct usb_composite_dev *cdev)
+{
+ static struct usb_configuration driver = {
+ .bind = install_mode_do_config,


+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ driver.iConfiguration = strings_dev[MULTI_STRING_INSTALL_MODE_IDX].id;
+ driver.label = strings_dev[MULTI_STRING_INSTALL_MODE_IDX].s;
+ return usb_add_config(cdev, &driver);
+}
+
+
+/* Jiffies of the last eject request on LUN 0. */
+static unsigned long multi_eject_jiffies;
+
+static int multi_eject(struct fsg_common *common,
+ struct fsg_lun *lun, int num)
+{
+ if (num)
+ return 0;
+
+ multi_eject_jiffies = jiffies;
+ next_install_mode = 0;
+ multi_worker_schedule();
+
+ return 1; /* Prevent realy unmounting the device */
+}
+
+static void multi_disconnect(struct usb_composite_dev *cdev)
+{
+ printk(KERN_INFO "multi_disconnect()\n");
+
+ /* Change back to install mode only if there was an eject
+ * (this is checked by looking if multi_eject_jiffies is
+ * non-zero), we are not switching to install mode already (no
+ * point in doing anything if next_install_mode is aleady one)
+ * and at least 10 seconds passed since last eject. */
+ /* Funky stuff may happen when jiffies wrap but we do not
+ * care. */
+ if (multi_eject_jiffies && !next_install_mode &&
+ jiffies >= multi_eject_jiffies + 10 * HZ) {
+ next_install_mode = 1;
+ multi_worker_schedule();
+ }
+}
+
+#else
+
+static int add_install_mode_config(struct usb_composite_dev *cdev)


+{
+ return 0;
+}

+
+#endif


/****************************** Gadget Bind ******************************/

+#if defined CONFIG_USB_G_MULTI_MSF || defined CONFIG_USB_G_MULTI_INSTALL

-static int __ref multi_bind(struct usb_composite_dev *cdev)
+static int __dyn_init multi_fsg_setup(struct usb_composite_dev *cdev)
{
- struct usb_gadget *gadget = cdev->gadget;
- int status, gcnum;
+ struct fsg_config cfg;
+ void *ret;
+
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ /* In install mode, make the first logical unit a read
+ * only removable CD-ROM. In addition if mass storage
+ * is used only for install mode, sot number of
+ * logical units to 1. */
+ if (!have_fsg)
+ fsg_mod_data.luns = 1;
+ fsg_mod_data.ro[0] = 1;
+ fsg_mod_data.removable[0] = 1;
+ fsg_mod_data.cdrom[0] = 1;
+ fsg_mod_data.removable_count =
+ max(fsg_mod_data.removable_count, 1u);
+#endif

- if (!can_support_ecm(cdev->gadget)) {
- dev_err(&gadget->dev, "controller '%s' not usable\n",
- gadget->name);
- return -EINVAL;
+ fsg_config_from_params(&cfg, &fsg_mod_data);
+
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ {
+ static const struct fsg_operations ops = {
+ .pre_eject = multi_eject,
+ };
+ cfg.ops = &ops;
}
+#endif
+
+ ret = fsg_common_init(&fsg_common, cdev, &cfg);
+ return unlikely(IS_ERR(ret)) ? PTR_ERR(ret) : 0;
+}
+
+#endif
+

+static int __dyn_init multi_setup(struct usb_composite_dev *cdev)
+{
+ int ret;
+
+#if defined CONFIG_USB_G_MULTI_RNDIS || defined CONFIG_USB_G_MULTI_ECM
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- return status;
+ if (!test_and_set_bit(1, &multi_initialised)) {
+ ret = gether_setup(cdev->gadget, hostaddr);
+ if (unlikely(ret < 0)) {
+ clear_bit(1, &multi_initialised);
+ goto fail;
+ }
+ }
+#endif

+#if defined CONFIG_USB_G_MULTI_ACM
/* set up serial link layer */
- status = gserial_setup(cdev->gadget, 1);
- if (status < 0)
- goto fail0;
+ if (!test_and_set_bit(2, &multi_initialised)) {
+ ret = gserial_setup(cdev->gadget, 1);
+ if (unlikely(ret < 0)) {
+ clear_bit(2, &multi_initialised);
+ goto fail;
+ }
+ }
+#endif

- /* set up mass storage function */
- {
- void *retp;
- retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
- if (IS_ERR(retp)) {
- status = PTR_ERR(retp);
- goto fail1;
+#if defined CONFIG_USB_G_MULTI_MSF || defined CONFIG_USB_G_MULTI_INSTALL
+ /* set up mass storage */
+ if (!test_and_set_bit(3, &multi_initialised)) {
+ ret = multi_fsg_setup(cdev);
+ if (unlikely(ret < 0)) {
+ clear_bit(3, &multi_initialised);
+ goto fail;
}
}
+#endif

- /* set bcdDevice */
- gcnum = usb_gadget_controller_number(gadget);
- if (gcnum >= 0) {
- device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
- } else {
- WARNING(cdev, "controller '%s' not recognized\n", gadget->name);
- device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
+ return 0;
+
+fail:
+ multi_cleanup();
+ return ret;
+}
+
+static void multi_cleanup(void)
+{
+#if defined CONFIG_USB_G_MULTI_MSF || defined CONFIG_USB_G_MULTI_INSTALL
+ if (test_and_clear_bit(3, &multi_initialised))
+ fsg_common_put(&fsg_common);
+#endif
+
+#if defined CONFIG_USB_G_MULTI_ACM
+ if (test_and_clear_bit(2, &multi_initialised))
+ gserial_cleanup();
+#endif
+
+#if defined CONFIG_USB_G_MULTI_RNDIS || defined CONFIG_USB_G_MULTI_ECM
+ if (test_and_clear_bit(1, &multi_initialised))
+ gether_cleanup();
+#endif
+}
+
+
+static int __dyn_ref multi_bind(struct usb_composite_dev *cdev)
+{
+ struct usb_gadget *gadget = cdev->gadget;
+ int status;
+
+ if (!can_support_ecm(cdev->gadget)) {
+ dev_err(&gadget->dev, "controller '%s' not usable\n",
+ gadget->name);
+ return -EINVAL;
}

- /* allocate string descriptor numbers */
+ /* Set up functions */
+ status = multi_setup(cdev);
+ if (unlikely(status < 0))
+ return status;

- snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
- init_utsname()->sysname, init_utsname()->release,
- gadget->name);


+ /* allocate string descriptor numbers */

+ if (!*manufacturer)
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);

status = usb_string_ids_tab(cdev, strings_dev);
if (unlikely(status < 0))
- goto fail2;
+ goto fail;
+
+ printk(KERN_INFO "install_mode = %d\n", install_mode);



+ /* register configurations */

+ if (install_mode) {
+ status = add_install_mode_config(cdev);
+ } else {
+ status = add_first_config(cdev);
+ if (unlikely(status < 0))
+ goto fail;
+
+ status = add_second_config(cdev);
+ if (unlikely(status < 0))
+ goto fail;
+ }
+
+ /* Fill the rest of the device descriptor */
device_desc.iManufacturer =
strings_dev[MULTI_STRING_MANUFACTURER_IDX].id;
device_desc.iProduct =
strings_dev[MULTI_STRING_PRODUCT_IDX].id;

- /* register configurations */
- status = usb_add_config(cdev, &first_config_driver);
- if (unlikely(status < 0))
- goto fail2;
-
-#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM
- status = usb_add_config(cdev, &second_config_driver);
- if (unlikely(status < 0))
- goto fail2;
-#endif
+ status = usb_gadget_controller_number(cdev->gadget);
+ device_desc.bcdDevice =
+ cpu_to_le16(0x300 | (status < 0 ? 0x99 : status));



/* we're done */
dev_info(&gadget->dev, DRIVER_DESC "\n");

- fsg_common_put(&fsg_common);
return 0;


/* error recovery */
-fail2:
- fsg_common_put(&fsg_common);
-fail1:
- gserial_cleanup();
-fail0:
- gether_cleanup();
+fail:
+ multi_cleanup();
return status;
}

-static int __exit multi_unbind(struct usb_composite_dev *cdev)
+
+/*************************** Other init/exit ****************************/
+
+static int __dyn_init multi_register(void)
{
- gserial_cleanup();
- gether_cleanup();
- return 0;
-}
+ int ret = 0;

+ if (!test_and_set_bit(0, &multi_initialised)) {
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ multi_driver.dev = install_mode
+ ? &install_mode_device_desc
+ : &multi_device_desc;
+#endif

-/****************************** Some noise ******************************/
+ ret = usb_composite_register(&multi_driver);
+ if (unlikely(ret)) {
+ clear_bit(0, &multi_initialised);
+ printk(KERN_ERR
+ "g_multi: failed registering the driver: %d\n",
+ ret);
+ }
+ }

+ return ret;
+}

-static struct usb_composite_driver multi_driver = {
- .name = "g_multi",
- .dev = &device_desc,
- .strings = dev_strings,
- .bind = multi_bind,
- .unbind = __exit_p(multi_unbind),
-};
+static void __dyn_exit multi_unregister(void)
+{
+ if (test_and_clear_bit(0, &multi_initialised))
+ usb_composite_unregister(&multi_driver);
+}


-static int __init multi_init(void)
+static __init int multi_init(void)
{
- return usb_composite_register(&multi_driver);
+ return multi_register();
}
module_init(multi_init);

-static void __exit multi_exit(void)
+static __exit void multi_exit(void)
{
- usb_composite_unregister(&multi_driver);
+ multi_worker_exit();
+ multi_unregister();
+ multi_cleanup();
}
module_exit(multi_exit);

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:03 AM6/2/10
to
Use usb_string_ids_n() function to simplify string ids
registeration.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/f_fs.c | 30 ++++++++++++------------------
1 files changed, 12 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 3fe120f..97c2ac2 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1377,7 +1377,8 @@ static void ffs_data_reset(struct ffs_data *ffs)



static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)

{
- unsigned i, count;
+ struct usb_gadget_strings **lang;
+ int first_id;

ENTER();

@@ -1385,7 +1386,9 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
|| test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
return -EBADFD;

- ffs_data_get(ffs);
+ first_id = usb_string_ids_n(cdev, ffs->strings_count);
+ if (unlikely(first_id < 0))
+ return first_id;

ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
if (unlikely(!ffs->ep0req))
@@ -1393,25 +1396,16 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
ffs->ep0req->complete = ffs_ep0_complete;
ffs->ep0req->context = ffs;

- /* Get strings identifiers */
- for (count = ffs->strings_count, i = 0; i < count; ++i) {
- struct usb_gadget_strings **lang;
-
- int id = usb_string_id(cdev);
- if (unlikely(id < 0)) {
- usb_ep_free_request(cdev->gadget->ep0, ffs->ep0req);
- ffs->ep0req = NULL;
- return id;
- }
-
- lang = ffs->stringtabs;
- do {
- (*lang)->strings[i].id = id;
- ++lang;
- } while (*lang);
+ lang = ffs->stringtabs;
+ for (lang = ffs->stringtabs; *lang; ++lang) {
+ struct usb_string *str = (*lang)->strings;
+ int id = first_id;
+ for (; str->s; ++id, ++str)
+ str->id = id;
}

ffs->gadget = cdev->gadget;
+ ffs_data_get(ffs);
return 0;

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:03 AM6/2/10
to
Added a disconnect() callback to compasite devices which
is called by composite glue when its disconnect callback
is called by gadget.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/composite.c | 2 ++
include/linux/usb/composite.h | 2 ++
2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 125167e..e483f80 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -956,6 +956,8 @@ static void composite_disconnect(struct usb_gadget *gadget)
spin_lock_irqsave(&cdev->lock, flags);
if (cdev->config)
reset_config(cdev);
+ if (composite->disconnect)
+ composite->disconnect(cdev);
spin_unlock_irqrestore(&cdev->lock, flags);
}

diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index f378075..890bc14 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -276,6 +276,8 @@ struct usb_composite_driver {
int (*bind)(struct usb_composite_dev *);
int (*unbind)(struct usb_composite_dev *);

+ void (*disconnect)(struct usb_composite_dev *);
+
/* global suspend hooks */
void (*suspend)(struct usb_composite_dev *);
void (*resume)(struct usb_composite_dev *);

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:04 AM6/2/10
to
A short documentation of the g_multi driver along with INF
files for Windows XP SP3 are provided.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Documentation/usb/gadget_multi.txt | 159 +++++++++++++++++++++++
Documentation/usb/gadget_multi_rndis.inf | 200 +++++++++++++++++++++++++++++
Documentation/usb/gadget_multi_serial.inf | 44 +++++++
3 files changed, 403 insertions(+), 0 deletions(-)
create mode 100644 Documentation/usb/gadget_multi.txt
create mode 100644 Documentation/usb/gadget_multi_rndis.inf
create mode 100644 Documentation/usb/gadget_multi_serial.inf

diff --git a/Documentation/usb/gadget_multi.txt b/Documentation/usb/gadget_multi.txt
new file mode 100644
index 0000000..bd53a9f
--- /dev/null
+++ b/Documentation/usb/gadget_multi.txt
@@ -0,0 +1,159 @@
+ -*- org -*-
+
+* Overview
+
+The Multifunction Composite Gadget (or g_multi) is a composite gadget
+that makes extensive use of the composite framework to provide
+a... multifunction gadget.
+
+In it's standard configuration it provides a single USB configuration
+with RNDIS[1] (that is Ethernet), USB CDC[2] ACM (that is serial) and
+USB Mass Storage functions.
+
+A CDC ECM (Ethernet) function may be turned on via a Kconfig option
+and RNDIS can be turned off. If they are both enabled the gadget will
+have two configurations -- one with RNDIS and another with CDC ECM[3].
+
+Please not that if you use non-standard configuration (that is enable
+CDC ECM) you may need to change vendor and/or product ID.
+
+* Host drivers
+
+To make use of the gadget one needs to make it work on host side --
+without that there's no hope of achieving anything with the gadget.
+As one might expect, things one need to do very from system to system.
+
+** Linux host drivers
+
+Since the gadget uses standard composite framework and appears as such
+to Linux host it does not need any additional drivers on Linux host
+side. All the functions are handled by respective drivers developed
+for them.
+
+This is also true for two configuration set-up with RNDIS
+configuration being the first one. Linux host will use the second
+configuration with CDC ECM which should work better under Linux.
+
+** Windows host drivers
+
+For the gadget two work under Windown two conditions have to be met:
+
+*** Detecting as composite gadget
+
+First of all, Windows need to detect the gadget as an USB composite
+gadget which on its own have some conditions[4]. If they are met,
+Windows lets USB Generic Parent Driver[5] handle the device which then
+tries to much drivers for each individual interface (sort of, don't
+get into too many details).
+
+The good news is, you do not have to worry about most of conditions!
+
+The only thing to worry is that the gadget has to have a single
+configuration so a dual RNDIS and CDC ECM gadget won't work unless you
+create a proper INF -- and of course, if you do submit it!
+
+*** Attaching drivers for each function
+
+The other, trickier thing is making Windows attach drivers to each
+individual function.
+
+For mass storage it is trivial since Windows detect it's an interface
+implementing USB Mass Storage class and selects appropriate driver.
+
+Things are harder with RDNIS and CDC ACM.
+
+**** RNDIS
+
+To make Windows select RNDIS drivers for the first function in the
+gadget, one needs to use the [[file:gadget_multi_rndis.inf]] file
+provided with this document. It "attaches" Window's RNDIS driver to
+the first interface of the gadget.
+
+Please note, that while testing we encountered some issues[6] when
+RNDIS was not the first interface. You do not need to worry abut it
+unless you are trying to develop your own gadget in which case watch
+out for this bug.
+
+**** CDC ACM
+
+Similarly, [[file:gadget_multi_serial.inf]] is provided for CDC ACM.
+Note, however that it also requires an usbser.sys file which can be
+extracted form Windows XP SP3 cab files.
+
+There is another usbser.sys file floating around the Internet but as
+we were testing the gadget it failed to work. It is very likely that
+one needs usbser.sys in version intended for one's version of Windows.
+
+We do net claim to be experts as far as INF files are considered so we
+think that there should be a better way of defining files in the
+[[file:gadget_multi_serial.inf]] so that it will work regardless of SP
+version installed. Again, if you happen to hack a better INF do not
+hesitate submitting it!
+
+**** Customising the gadget
+
+If you intend to hack the g_multi gadget be advised that rearranging
+functions will obviously change interface numbers for each of the
+functionality. As an effect provided INFs won't work since they have
+interface numbers hard-coded in them (it's not hard to change those
+though).
+
+This also means, that after experimenting with g_multi and changing
+provided functions one should change gadget's vendor and/or product ID
+so there will be no collision with other customised gadgets or the
+original gadget.
+
+Failing to comply may cause brain damage after wondering for hours why
+things don't work as intended before realising Windows have cached
+some drivers information (changing USB port may sometimes help).
+
+**** Improvements in INF files
+
+It needs to be noted that we are not Windows driver experts and as
+such we do not claim that provided INF files are flawless or that they
+will work on each and every Windows versions (they were tested on
+Windows XP SP3 only).
+
+The bottom line is, if you can improve the INF files, please do and
+share the results[7]. :)
+
+** Other systems
+
+At this moment, drivers for any other systems have not been tested.
+Knowing how MacOS is based on BSD and BSD is an Open Source it is
+believed that it should (read: "I have no idea whether it will") work
+out-of-the-box.
+
+For more exotic systems I have even less to say...
+
+Any testing and drivers *are* *welcome*!
+
+* Authors
+
+This document has been written by Michal Nazarewicz
+([[mailto:min...@mina86.com]]) and the INF files have been hacked by
+Marek Szyprowski ([[mailto:m.szyp...@samsung.com]]) basing on the
+[[file:linux.inf]] file provided for Ethernet gadget and description
+from [[file:gadget_serial.txt]].
+
+* Footnotes
+
+[1] Remote Network Driver Interface Specification,
+[[http://msdn.microsoft.com/en-us/library/ee484414.aspx]].
+
+[2] Communications Device Class Abstract Control Model, spec for this
+and other USB classes can be found at
+[[http://www.usb.org/developers/devclass_docs/]].
+
+[3] CDC Ethernet Control Model.
+
+[4] [[http://msdn.microsoft.com/en-us/library/ff537109(v=VS.85).aspx]].
+
+[5] [[http://msdn.microsoft.com/en-us/library/ff539234(v=VS.85).aspx]].
+
+[6] To put it in some other nice words, Windows failed to respond to
+any user input.
+
+[7] Possibility to say `git rev-list --author='Your Name'
+linus/master|wc -l` returns non-zero -- priceless. :]
+
diff --git a/Documentation/usb/gadget_multi_rndis.inf b/Documentation/usb/gadget_multi_rndis.inf
new file mode 100644
index 0000000..2222fd0
--- /dev/null
+++ b/Documentation/usb/gadget_multi_rndis.inf
@@ -0,0 +1,200 @@
+; MS-Windows driver config matching some basic modes of the
+; Linux-USB Ethernet/RNDIS gadget firmware:
+;
+; - RNDIS plus CDC Ethernet ... this may be familiar as a DOCSIS
+; cable modem profile, and supports most non-Microsoft USB hosts
+;
+; - RNDIS plus CDC Subset ... used by hardware that incapable of
+; full CDC Ethernet support.
+;
+; Microsoft only directly supports RNDIS drivers, and bundled them into XP.
+; The Microsoft "Remote NDIS USB Driver Kit" is currently found at:
+; http://www.microsoft.com/whdc/hwdev/resources/HWservices/rndis.mspx
+
+
+[Version]
+Signature = "$CHICAGO$"
+Class = Net
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %Linux%
+Compatible = 1
+MillenniumPreferred = .ME
+DriverVer = 03/30/2004,0.0.0.0
+; catalog file would be used by WHQL
+;CatalogFile = Linux.cat
+
+[Manufacturer]
+%Linux% = LinuxDevices,NT.5.1
+
+[LinuxDevices]
+; NetChip IDs, used by both firmware modes
+%LinuxDevice% = RNDIS, USB\VID_0525&PID_a4ab&MI_00
+
+[LinuxDevices.NT.5.1]
+%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4ab&MI_00
+
+[ControlFlags]
+ExcludeFromSelect=*
+
+; Windows 98, Windows 98 Second Edition specific sections --------
+
+[RNDIS]
+DeviceID = usb8023
+MaxInstance = 512
+DriverVer = 03/30/2004,0.0.0.0
+AddReg = RNDIS_AddReg_98, RNDIS_AddReg_Common
+
+[RNDIS_AddReg_98]
+HKR, , DevLoader, 0, *ndis
+HKR, , DeviceVxDs, 0, usb8023.sys
+HKR, NDIS, LogDriverName, 0, "usb8023"
+HKR, NDIS, MajorNdisVersion, 1, 5
+HKR, NDIS, MinorNdisVersion, 1, 0
+HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5"
+HKR, Ndi\Interfaces, DefLower, 0, "ethernet"
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5"
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_98"
+HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_98"
+HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_98"
+HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4ab&MI_00"
+
+[RNDIS_Install_98]
+CopyFiles=RNDIS_CopyFiles_98
+
+[RNDIS_CopyFiles_98]
+usb8023.sys, usb8023w.sys, , 0
+rndismp.sys, rndismpw.sys, , 0
+
+; Windows Millennium Edition specific sections --------------------
+
+[RNDIS.ME]
+DeviceID = usb8023
+MaxInstance = 512
+DriverVer = 03/30/2004,0.0.0.0
+AddReg = RNDIS_AddReg_ME, RNDIS_AddReg_Common
+Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
+BusType = 15
+
+[RNDIS_AddReg_ME]
+HKR, , DevLoader, 0, *ndis
+HKR, , DeviceVxDs, 0, usb8023.sys
+HKR, NDIS, LogDriverName, 0, "usb8023"
+HKR, NDIS, MajorNdisVersion, 1, 5
+HKR, NDIS, MinorNdisVersion, 1, 0
+HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5"
+HKR, Ndi\Interfaces, DefLower, 0, "ethernet"
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5"
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_ME"
+HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_ME"
+HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_ME"
+HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4ab&MI_00"
+
+[RNDIS_Install_ME]
+CopyFiles=RNDIS_CopyFiles_ME
+
+[RNDIS_CopyFiles_ME]
+usb8023.sys, usb8023m.sys, , 0
+rndismp.sys, rndismpm.sys, , 0
+
+; Windows 2000 specific sections ---------------------------------
+
+[RNDIS.NT]
+Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
+BusType = 15
+DriverVer = 03/30/2004,0.0.0.0
+AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common
+CopyFiles = RNDIS_CopyFiles_NT
+
+[RNDIS.NT.Services]
+AddService = USB_RNDIS, 2, RNDIS_ServiceInst_NT, RNDIS_EventLog
+
+[RNDIS_CopyFiles_NT]
+; no rename of files on Windows 2000, use the 'k' names as is
+usb8023k.sys, , , 0
+rndismpk.sys, , , 0
+
+[RNDIS_ServiceInst_NT]
+DisplayName = %ServiceDisplayName%
+ServiceType = 1
+StartType = 3
+ErrorControl = 1
+ServiceBinary = %12%\usb8023k.sys
+LoadOrderGroup = NDIS
+AddReg = RNDIS_WMI_AddReg_NT
+
+[RNDIS_WMI_AddReg_NT]
+HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismpk.sys"
+
+; Windows XP specific sections -----------------------------------
+
+[RNDIS.NT.5.1]
+Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
+BusType = 15
+DriverVer = 03/30/2004,0.0.0.0
+AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common
+; no copyfiles - the files are already in place
+
+[RNDIS.NT.5.1.Services]
+AddService = USB_RNDIS, 2, RNDIS_ServiceInst_51, RNDIS_EventLog
+
+[RNDIS_ServiceInst_51]
+DisplayName = %ServiceDisplayName%
+ServiceType = 1
+StartType = 3
+ErrorControl = 1
+ServiceBinary = %12%\usb8023.sys
+LoadOrderGroup = NDIS
+AddReg = RNDIS_WMI_AddReg_51
+
+[RNDIS_WMI_AddReg_51]
+HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismp.sys"
+
+; Windows 2000 and Windows XP common sections --------------------
+
+[RNDIS_AddReg_NT]
+HKR, Ndi, Service, 0, "USB_RNDIS"
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+
+[RNDIS_EventLog]
+AddReg = RNDIS_EventLog_AddReg
+
+[RNDIS_EventLog_AddReg]
+HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll"
+HKR, , TypesSupported, 0x00010001, 7
+
+; Common Sections -------------------------------------------------
+
+[RNDIS_AddReg_Common]
+HKR, NDI\params\NetworkAddress, ParamDesc, 0, %NetworkAddress%
+HKR, NDI\params\NetworkAddress, type, 0, "edit"
+HKR, NDI\params\NetworkAddress, LimitText, 0, "12"
+HKR, NDI\params\NetworkAddress, UpperCase, 0, "1"
+HKR, NDI\params\NetworkAddress, default, 0, " "
+HKR, NDI\params\NetworkAddress, optional, 0, "1"
+
+[SourceDisksNames]
+1=%SourceDisk%,,1
+
+[SourceDisksFiles]
+usb8023m.sys=1
+rndismpm.sys=1
+usb8023w.sys=1
+rndismpw.sys=1
+usb8023k.sys=1
+rndismpk.sys=1
+
+[DestinationDirs]
+RNDIS_CopyFiles_98 = 10, system32/drivers
+RNDIS_CopyFiles_ME = 10, system32/drivers
+RNDIS_CopyFiles_NT = 12
+
+[Strings]
+ServiceDisplayName = "USB Remote NDIS Network Device Driver"
+NetworkAddress = "Network Address"
+Linux = "Linux Developer Community"
+LinuxDevice = "RNDIS Gadget/Linux Multifunction Gadget"
+SourceDisk = "Linux RNDIS Gadget Driver Install Disk"
+
diff --git a/Documentation/usb/gadget_multi_serial.inf b/Documentation/usb/gadget_multi_serial.inf
new file mode 100644
index 0000000..b04ace1
--- /dev/null
+++ b/Documentation/usb/gadget_multi_serial.inf
@@ -0,0 +1,44 @@
+[Version]
+Signature="$Windows NT$"
+Class=Ports
+ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
+Provider=%LINUX%
+DriverVer=08/17/2004,0.0.2.1
+; Copyright (C) 2004 Al Borchers (albor...@steinerpoint.com)
+
+[Manufacturer]
+%LINUX%=GSerialDeviceList
+
+[GSerialDeviceList]
+%GSERIAL%=GSerialInstall, USB\VID_0525&PID_A4AB&MI_02
+
+[DestinationDirs]
+DefaultDestDir=10,System32\Drivers
+
+[GSerialInstall]
+CopyFiles=GSerialCopyFiles
+AddReg=GSerialAddReg
+
+[GSerialCopyFiles]
+usbser.sys
+
+[GSerialAddReg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,usbser.sys
+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
+
+[GSerialInstall.Services]
+AddService = usbser,0x0002,GSerialService
+
+[GSerialService]
+DisplayName = %GSERIAL_DISPLAY_NAME%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %10%\System32\Drivers\usbser.sys
+LoadOrderGroup = Base
+
+[Strings]
+LINUX = "Linux"
+GSERIAL = "Serial Gadget/Linux Multifunction Gadget"
+GSERIAL_DISPLAY_NAME = "Serial Gadget/Linux Multifunction Gadget"

Michal Nazarewicz

unread,
Jun 2, 2010, 8:50:02 AM6/2/10
to
Added pre_eject() and post_eject() callbacks which are
called befor and after removable logical unit is ejected.
The first can prevent logical unit from being ejected.

This commit also changes the way callbacks are passed to
the function from gadget. A fsg_operations structure has
been created which lists all callbacks -- this is passed
to the fsg_config.

This is important because it changes the way thread_exits()
callback is passed.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/f_mass_storage.c | 109 ++++++++++++++++++++++------------
drivers/usb/gadget/mass_storage.c | 4 +-
2 files changed, 73 insertions(+), 40 deletions(-)

diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 072cbf9..e9e45ba 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -316,6 +316,27 @@ static const char fsg_string_interface[] = "Mass Storage";
/*-------------------------------------------------------------------------*/

struct fsg_dev;
+struct fsg_common;
+
+/* FSF callback functions */
+struct fsg_operations {
+ /* Callback function to call when thread exits. If no
+ * callback is set or it returns value lower then zero MSF
+ * will force eject all LUNs it operates on (including those
+ * marked as non-removable or with prevent_medium_removal flag
+ * set). */
+ int (*thread_exits)(struct fsg_common *common);
+
+ /* Called prior to ejection. Negative return means error,
+ * zero means to continue with ejection, positive means not to
+ * eject. */
+ int (*pre_eject)(struct fsg_common *common,


+ struct fsg_lun *lun, int num);

+ /* Called after ejection. Negative return means error, zero
+ * or positive is just a success. */
+ int (*post_eject)(struct fsg_common *common,


+ struct fsg_lun *lun, int num);

+};


/* Data shared by all the FSG instances. */
@@ -370,8 +391,8 @@ struct fsg_common {
struct completion thread_notifier;
struct task_struct *thread_task;

- /* Callback function to call when thread exits. */
- int (*thread_exits)(struct fsg_common *common);
+ /* Callback functions. */
+ const struct fsg_operations *ops;
/* Gadget's private data. */
void *private_data;

@@ -395,12 +416,8 @@ struct fsg_config {
const char *lun_name_format;
const char *thread_name;

- /* Callback function to call when thread exits. If no
- * callback is set or it returns value lower then zero MSF
- * will force eject all LUNs it operates on (including those
- * marked as non-removable or with prevent_medium_removal flag
- * set). */
- int (*thread_exits)(struct fsg_common *common);
+ /* Callback functions. */
+ const struct fsg_operations *ops;
/* Gadget's private data. */
void *private_data;

@@ -436,6 +453,7 @@ static inline int __fsg_is_set(struct fsg_common *common,
if (common->fsg)
return 1;
ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
+ WARN_ON(1);
return 0;
}

@@ -1396,43 +1414,55 @@ static int do_start_stop(struct fsg_common *common)
} else if (!curlun->removable) {
curlun->sense_data = SS_INVALID_COMMAND;
return -EINVAL;
- }
-
- loej = common->cmnd[4] & 0x02;
- start = common->cmnd[4] & 0x01;
-
- /* eject code from file_storage.c:do_start_stop() */
-
- if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
- (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
+ } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
+ (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL;
}

- if (!start) {
- /* Are we allowed to unload the media? */
- if (curlun->prevent_medium_removal) {
- LDBG(curlun, "unload attempt prevented\n");
- curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
- return -EINVAL;
- }
- if (loej) { /* Simulate an unload/eject */
- up_read(&common->filesem);
- down_write(&common->filesem);
- fsg_lun_close(curlun);
- up_write(&common->filesem);
- down_read(&common->filesem);
- }
- } else {
+ loej = common->cmnd[4] & 0x02;
+ start = common->cmnd[4] & 0x01;

- /* Our emulation doesn't support mounting; the medium is
- * available for use as soon as it is loaded. */
+ /* Our emulation doesn't support mounting; the medium is
+ * available for use as soon as it is loaded. */
+ if (start) {
if (!fsg_lun_is_open(curlun)) {
curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
return -EINVAL;
}
+ return 0;
}
- return 0;
+
+ /* Are we allowed to unload the media? */
+ if (curlun->prevent_medium_removal) {
+ LDBG(curlun, "unload attempt prevented\n");
+ curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
+ return -EINVAL;
+ }
+
+ if (!loej)
+ return 0;
+
+ /* Simulate an unload/eject */
+ if (common->ops && common->ops->pre_eject) {
+ int r = common->ops->pre_eject(common, curlun,
+ curlun - common->luns);
+ if (unlikely(r < 0))
+ return r;
+ else if (r)


+ return 0;
+ }
+

+ up_read(&common->filesem);
+ down_write(&common->filesem);
+ fsg_lun_close(curlun);
+ up_write(&common->filesem);
+ down_read(&common->filesem);
+
+ return common->ops && common->ops->post_eject
+ ? min(0, common->ops->post_eject(common, curlun,
+ curlun - common->luns))
+ : 0;
}


@@ -2657,7 +2687,8 @@ static int fsg_main_thread(void *common_)
common->thread_task = NULL;
spin_unlock_irq(&common->lock);

- if (!common->thread_exits || common->thread_exits(common) < 0) {
+ if (!common->ops || !common->ops->thread_exits
+ || common->ops->thread_exits(common) < 0) {
struct fsg_lun *curlun = common->luns;
unsigned i = common->nluns;

@@ -2733,6 +2764,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
common->free_storage_on_release = 0;
}

+ common->ops = cfg->ops;
common->private_data = cfg->private_data;

common->gadget = gadget;
@@ -2854,7 +2886,6 @@ buffhds_first_it:


/* Tell the thread to start working */
- common->thread_exits = cfg->thread_exits;
common->thread_task =
kthread_create(fsg_main_thread, common,
OR(cfg->thread_name, "file-storage"));
@@ -3151,8 +3182,8 @@ fsg_config_from_params(struct fsg_config *cfg,
cfg->product_name = 0;
cfg->release = 0xffff;

- cfg->thread_exits = 0;
- cfg->private_data = 0;
+ cfg->ops = NULL;
+ cfg->private_data = NULL;

/* Finalise */
cfg->can_stall = params->stall;
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index d6975f4..cd94703 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -153,7 +153,9 @@ static int __init msg_do_config(struct usb_configuration *c)
}

fsg_config_from_params(&config, &mod_data);
- config.thread_exits = msg_thread_exits;
+ config.ops = &(const struct fsg_operations){
+ .thread_exits = msg_thread_exits,


+ };

retp = fsg_common_init(&common, c->cdev, &config);

if (IS_ERR(retp))

Xiaofan Chen

unread,
Jun 2, 2010, 9:10:02 AM6/2/10
to
On Wed, Jun 2, 2010 at 8:45 PM, Michal Nazarewicz
<m.naza...@samsung.com> wrote:

> +**** Improvements in INF files
> +
> +It needs to be noted that we are not Windows driver experts and as
> +such we do not claim that provided INF files are flawless or that they
> +will work on each and every Windows versions (they were tested on
> +Windows XP SP3 only).
> +
> +The bottom line is, if you can improve the INF files, please do and
> +share the results[7]. :)

Seems to be very true. I think both INF files are very outdated. But
I am not familiar with RNDIS to comment on that one.

But the following INF file for serial is really outdated. For example,
it probably does not work under Vista/Win7. It also do not
support 64bit OS.

A proper example from Microchip (USB Stack V2.7).


; Windows USB CDC ACM Setup File
; Copyright (c) 2000 Microsoft Corporation
; Copyright (C) 2007 Microchip Technology Inc.

[Version]
Signature="$Windows NT$"
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%MFGNAME%
LayoutFile=layout.inf
CatalogFile=%MFGFILENAME%.cat
DriverVer=11/15/2007,5.1.2600.0

[Manufacturer]
%MFGNAME%=DeviceList, NTamd64

[DestinationDirs]
DefaultDestDir=12


;------------------------------------------------------------------------------
; Windows 2000/XP/Vista-32bit Sections
;------------------------------------------------------------------------------

[DriverInstall.nt]
include=mdmcpq.inf
CopyFiles=DriverCopyFiles.nt
AddReg=DriverInstall.nt.AddReg

[DriverCopyFiles.nt]
usbser.sys,,,0x20

[DriverInstall.nt.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,%DRIVERFILENAME%.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"

[DriverInstall.nt.Services]
AddService=usbser, 0x00000002, DriverService.nt

[DriverService.nt]
DisplayName=%SERVICE%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\%DRIVERFILENAME%.sys

;------------------------------------------------------------------------------
; Vista-64bit Sections
;------------------------------------------------------------------------------

[DriverInstall.NTamd64]
include=mdmcpq.inf
CopyFiles=DriverCopyFiles.NTamd64
AddReg=DriverInstall.NTamd64.AddReg

[DriverCopyFiles.NTamd64]
%DRIVERFILENAME%.sys,,,0x20

[DriverInstall.NTamd64.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,%DRIVERFILENAME%.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"

[DriverInstall.NTamd64.Services]
AddService=usbser, 0x00000002, DriverService.NTamd64

[DriverService.NTamd64]
DisplayName=%SERVICE%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\%DRIVERFILENAME%.sys


;------------------------------------------------------------------------------
; Vendor and Product ID Definitions
;------------------------------------------------------------------------------
; When developing your USB device, the VID and PID used in the PC side
; application program and the firmware on the microcontroller must match.
; Modify the below line to use your VID and PID. Use the format as shown below.
; Note: One INF file can be used for multiple devices with different
VID and PIDs.
; For each supported device, append ",USB\VID_xxxx&PID_yyyy" to the
end of the line.
;------------------------------------------------------------------------------
[SourceDisksFiles]
[SourceDisksNames]
[DeviceList]
%DESCRIPTION%=DriverInstall, USB\VID_04D8&PID_000A

[DeviceList.NTamd64]
%DESCRIPTION%=DriverInstall, USB\VID_04D8&PID_000A


;------------------------------------------------------------------------------
; String Definitions
;------------------------------------------------------------------------------
;Modify these strings to customize your device
;------------------------------------------------------------------------------
[Strings]
MFGFILENAME="mchpcdc"
DRIVERFILENAME ="usbser"
MFGNAME="Microchip Technology, Inc."
INSTDISK="Microchip Technology, Inc. Installation Disc"
DESCRIPTION="Communications Port"
SERVICE="USB RS-232 Emulation Driver"


--
Xiaofan http://mcuee.blogspot.com

Xiaofan Chen

unread,
Jun 2, 2010, 9:20:02 AM6/2/10
to
On Wed, Jun 2, 2010 at 9:02 PM, Xiaofan Chen <xiao...@gmail.com> wrote:
> On Wed, Jun 2, 2010 at 8:45 PM, Michal Nazarewicz
> <m.naza...@samsung.com> wrote:
>
>> +**** Improvements in INF files
>> +
>> +It needs to be noted that we are not Windows driver experts and as
>> +such we do not claim that provided INF files are flawless or that they
>> +will work on each and every Windows versions (they were tested on
>> +Windows XP SP3 only).
>> +
>> +The bottom line is, if you can improve the INF files, please do and
>> +share the results[7]. :)
>
> Seems to be very true. I think both INF files are very outdated. But
> I am not familiar with RNDIS to comment on that one.
>

I can see that the INF file for the USB RNDIS still contains the
Win98SE/ME section, not so sure if you want to support them.

For later versions (XP and later), Microsoft has publish the
proper template.
http://msdn.microsoft.com/en-us/library/ff570620.aspx

Michał Nazarewicz

unread,
Jun 2, 2010, 9:30:01 AM6/2/10
to
On Wed, 02 Jun 2010 15:02:54 +0200, Xiaofan Chen <xiao...@gmail.com> wrote:
> Seems to be very true. I think both INF files are very outdated. But
> I am not familiar with RNDIS to comment on that one.
>
> But the following INF file for serial is really outdated. For example,
> it probably does not work under Vista/Win7. It also do not
> support 64bit OS.

Thanks for the comments, we're try to check those INFs as soon as possible.

--
Best regards, _ _
| Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o
| Computer Science, Michał "mina86" Nazarewicz (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--

Xiaofan Chen

unread,
Jun 2, 2010, 10:10:03 AM6/2/10
to
On Wed, Jun 2, 2010 at 8:45 PM, Michal Nazarewicz
<m.naza...@samsung.com> wrote:

> +**** Customising the gadget
> +
> +If you intend to hack the g_multi gadget be advised that rearranging
> +functions will obviously change interface numbers for each of the
> +functionality. �As an effect provided INFs won't work since they have
> +interface numbers hard-coded in them (it's not hard to change those
> +though).

Probably you can show an example of how to add the "&MI_mm"
to the VID/PID.

A good reference here:
http://www.cygnal.org/ubb/Forum9/HTML/001050.html

> +This also means, that after experimenting with g_multi and changing
> +provided functions one should change gadget's vendor and/or product ID
> +so there will be no collision with other customised gadgets or the
> +original gadget.
> +
> +Failing to comply may cause brain damage after wondering for hours why
> +things don't work as intended before realising Windows have cached
> +some drivers information (changing USB port may sometimes help).
> +

This is indeed quite true. However, you may not need to really change
the VID/PID (it will work but not necessary) if you use the nice
usbdeview utility to remove the phantom USB device.
http://www.nirsoft.net/utils/usb_devices_view.html

--
Xiaofan http://mcuee.blogspot.com

Michał Nazarewicz

unread,
Jun 2, 2010, 11:50:03 AM6/2/10
to
On Wed, 02 Jun 2010 15:02:54 +0200, Xiaofan Chen <xiao...@gmail.com> wrote:
> [Version]
> Signature="$Windows NT$"
> Class=Ports
> ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
> Provider=%MFGNAME%
> LayoutFile=layout.inf
> CatalogFile=%MFGFILENAME%.cat

So, what is this cat file for? I changed the IDs and the INF file started
working even though I expected that this file will be required. I'm wondering
is it because I have something installed on my Windows box that others may
miss?

And what's with the layout.inf.

--
Best regards, _ _
| Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o
| Computer Science, Michał "mina86" Nazarewicz (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--

Xiaofan Chen

unread,
Jun 3, 2010, 1:10:01 AM6/3/10
to
2010/6/2 Michał Nazarewicz <m.naza...@samsung.com>:

> On Wed, 02 Jun 2010 15:02:54 +0200, Xiaofan Chen <xiao...@gmail.com> wrote:
>>
>> [Version]
>> Signature="$Windows NT$"
>> Class=Ports
>> ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
>> Provider=%MFGNAME%
>> LayoutFile=layout.inf
>> CatalogFile=%MFGFILENAME%.cat
>
> So, what is this cat file for?  I changed the IDs and the INF file started
> working even though I expected that this file will be required.  I'm
> wondering is it because I have something installed on my Windows
> box that others may miss?

You do not need the cat file in this case. Microchip's Driver Package is
WHQLed, in that case, the cat file will have the necessary
digital certificate (Verisign Class 3 code signing certificate for WHQL).
You can also sign your driver package with other valid certificates
(GlobalSign) for KMCS requirement. In this case, the kernel driver
is already signed by Microsoft, you do not need the signed driver
package (cat file) to load the driver in 64bit Vista/Win7. But there
will be a warning (for 32bit/64bit XP/Vista/Win7). Once you pay
money and go through WHQL process, the warning will not be there.

In a word, that line can be deleted.

> And what's with the layout.inf.

Ah, I think that should not be there now. Only system provided
INF file should have that line (eg: mdmcpq.inf which is included
in the Microchip INF file). You can remove that line.

More information:
http://support.microsoft.com/kb/837637

--
Xiaofan http://mcuee.blogspot.com

Xiaofan Chen

unread,
Jun 3, 2010, 1:20:01 AM6/3/10
to
2010/6/3 Xiaofan Chen <xiao...@gmail.com>:

> 2010/6/2 Michał Nazarewicz <m.naza...@samsung.com>:
>> On Wed, 02 Jun 2010 15:02:54 +0200, Xiaofan Chen <xiao...@gmail.com> wrote:
>>>
>>> [Version]
>>> Signature="$Windows NT$"
>>> Class=Ports
>>> ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
>>> Provider=%MFGNAME%
>>> LayoutFile=layout.inf
>>> CatalogFile=%MFGFILENAME%.cat
>>
>> So, what is this cat file for?  I changed the IDs and the INF file started
>> working even though I expected that this file will be required.  I'm
>> wondering is it because I have something installed on my Windows
>> box that others may miss?
>
> You do not need the cat file in this case. Microchip's Driver Package is
> WHQLed, in that case, the cat file will have the necessary
> digital certificate (Verisign Class 3 code signing certificate for WHQL).
> You can also sign your driver package with other valid certificates
> (GlobalSign) for KMCS requirement. In this case, the kernel driver
> is already signed by Microsoft, you do not need the signed driver
> package (cat file) to load the driver in 64bit Vista/Win7. But there
> will be a warning (for 32bit/64bit XP/Vista/Win7). Once you pay
> money and go through WHQL process, the warning will not be there.
>
> In a word, that line can be deleted.

Just hope the Linux USB developers will not be bored by this kind
of Windows specific information.

Here is the nice writeup by Microsoft about KMCS.
http://www.microsoft.com/whdc/driver/install/drvsign/kmcs-walkthrough.mspx

So if your employer (Samsung) or others is quite nice and submit the
driver package (the inf and cat file for CDC-ACM) for WHQL and got
approved, in the future, uses of the inf file will not see the red color
warning. This might be desired for corporate customers.

BTW, I am one of the admins of the open source libusb-win32 project.
Actually we want to get some donations to sign the kernel libusb0.sys
driver so that it can work under 64bit Vista/Win7. Therefore I came
to know a bit of the things.

>> And what's with the layout.inf.
> Ah, I think that should not be there now. Only system provided
> INF file should have that line (eg: mdmcpq.inf which is included

> in the INF file). You can remove that line.

Michal Nazarewicz

unread,
Jun 3, 2010, 5:10:03 AM6/3/10
to
>>> On Wed, 02 Jun 2010 15:02:54 +0200, Xiaofan Chen <xiao...@gmail.com> wrote:
>>>> LayoutFile=layout.inf
>>>> CatalogFile=%MFGFILENAME%.cat

>> 2010/6/2 Michał Nazarewicz <m.naza...@samsung.com>:


>>> So, what is this cat file for?

> 2010/6/3 Xiaofan Chen <xiao...@gmail.com>:


>> In a word, that line can be deleted.

In that case, I'll try to test the new INF files on various Windows
versions and will probably send updated patchset to the list.

Xiaofan Chen <xiao...@gmail.com> writes:
> Just hope the Linux USB developers will not be bored by this kind
> of Windows specific information.

Someone has to do that. If there's someone who knows that stuff it'll
be a sin not to use his expertise. :)

> Here is the nice writeup by Microsoft about KMCS.
> http://www.microsoft.com/whdc/driver/install/drvsign/kmcs-walkthrough.mspx

Wow... Honestly, 56 pages? They sure know how to make "openssl dgst
-sign" complicated...

I'll have to put that on my TODO list thought it may take some time till
I get to singing drivers.

> So if your employer (Samsung) or others is quite nice and submit the
> driver package (the inf and cat file for CDC-ACM) for WHQL and got
> approved, in the future, uses of the inf file will not see the red color
> warning. This might be desired for corporate customers.

I *personally* see how it may be a problem for _any_ corporation since
singing is like saying "yes, we guarantee it won't destroy your computer
nor it will summon demons" and by releasing signed driver you in effect
loose control over it. Again, further signature investigations are on
my TODO list.

--
Best regards, _ _

.o. | Liege of Serenly Enlightened Majesty of o' \,=./ `o
..o | Computer Science, Michal "mina86" Nazarewicz (o o)
ooo +--<mina86-tlen.pl>--<jid:mina86-jabber.org>--ooO--(_)--Ooo--

Xiaofan Chen

unread,
Jun 3, 2010, 6:40:04 AM6/3/10
to
On Thu, Jun 3, 2010 at 5:02 PM, Michal Nazarewicz <min...@mina86.com> wrote:
>> So if your employer (Samsung) or others is quite nice and submit the
>> driver package (the inf and cat file for CDC-ACM) for WHQL and got
>> approved, in the future, users of the inf file will not see the red color

>> warning. This might be desired for corporate customers.
>
> I *personally* see how it may be a problem for _any_ corporation since
> singing is like saying "yes, we guarantee it won't destroy your computer
> nor it will summon demons" and by releasing signed driver you in effect
> loose control over it.  Again, further signature investigations are on
> my TODO list.
>

As I mentioned before, WHQL submission is not necessary for
drivers using usbser.sys. It will work under 32bit/64bit Windows.
The warning just scares some innocent customers.

You do not need the catalog file here. Those vendors who likes to get
the WHQL can pay the money to get it (for their particular VID/PID).

For drivers like libusb-win32 (libusb0.sys), it is a big problem since
you can not load it under 64bit Vista/Win7. libusb-win32 is quite
nice project to port Linux libusb based application to Windows.
So we in the libusb-win32 project plan to get the money through
donation to buy the digital certificate so that it can work under
64bit Vista/Win7 and users can load it (with the red warning
since the driver package are not signed with the digital
certificate, inf file is part of the driver package). Corporate
users of libusb-win32 (eg: Atmel) can choose to go for WHQL so that
their users will not see the red warning.
(ref: http://sourceforge.net/news/?group_id=78138 )

usbser.sys is already signed by Microsoft, so you will not
face such issue. Same thing for the drivers of USB RNDIS.

Michal Nazarewicz

unread,
Jun 7, 2010, 8:40:02 AM6/7/10
to
Use usb_string_ids_n() function to simplify string ids
registeration.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

--

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:02 AM6/7/10
to
FunctionFS had a bit unique name for function used to add it

to USB configuration. Renamed as to match naming convention
of other functions.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/f_fs.c | 6 +++---
drivers/usb/gadget/g_ffs.c | 2 +-
include/linux/usb/functionfs.h | 6 +++---

3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index d69eccf..3fe120f 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c


@@ -1480,9 +1480,9 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
}


-static int functionfs_add(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
- struct ffs_data *ffs)
+static int functionfs_bind_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *c,


+ struct ffs_data *ffs)
{
struct ffs_function *func;
int ret;
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index 4b0e4a0..2f26470 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -388,7 +388,7 @@ static int __gfs_do_config(struct usb_configuration *c,

return ret;
}


- ret = functionfs_add(c->cdev, c, gfs_ffs_data);
+ ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data);

if (unlikely(ret < 0))
return ret;

diff --git a/include/linux/usb/functionfs.h b/include/linux/usb/functionfs.h
index a34a2a0..6f649c1 100644
--- a/include/linux/usb/functionfs.h
+++ b/include/linux/usb/functionfs.h
@@ -180,9 +180,9 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
static void functionfs_unbind(struct ffs_data *ffs)
__attribute__((nonnull));

-static int functionfs_add(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
- struct ffs_data *ffs)
+static int functionfs_bind_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *c,
+ struct ffs_data *ffs)
__attribute__((warn_unused_result, nonnull));

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:04 AM6/7/10
to
Updated the INF file for the g_ether gadegt. It should work with most
recent Windows systems now. The file hase been also renamed to
linux-rndis.inf rather then linux.inf.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Documentation/usb/linux-rndis.inf | 79 +++++++++++++++
Documentation/usb/linux.inf | 200 -------------------------------------
2 files changed, 79 insertions(+), 200 deletions(-)
create mode 100644 Documentation/usb/linux-rndis.inf
delete mode 100644 Documentation/usb/linux.inf

diff --git a/Documentation/usb/linux-rndis.inf b/Documentation/usb/linux-rndis.inf
new file mode 100644
index 0000000..fa608fa
--- /dev/null
+++ b/Documentation/usb/linux-rndis.inf
@@ -0,0 +1,79 @@
+;
+; Remote NDIS template device setup file
+; Copyright (c) Microsoft Corporation
+;
+; This is the template for the INF installation script
+; for the RNDIS-over-USB host driver.
+; This INF works for Windows XP SP2, Windows XP x64,
+; Windows Server 2003 SP1 x86, x64, and ia64, and
+; Windows Vista x86 and x64.
+; This INF will work with Windows XP, Windows XP SP1,
+; and Windows 2003 after applying specific hotfixes.
+;
+; Hacked for Linux by Michal Nazarewicz <min...@mina86.com>
+; No, I do not understand this file, don't blame me if it
+; does not work... Original found at:
+; <http://msdn.microsoft.com/en-us/library/ff570620.aspx>.
+; Thanks to Xiaofan Chen for pointing to this template.
+;
+
+[Version]
+Signature = "$Windows NT$"


+Class = Net
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %Linux%

+DriverVer = 06/21/2006,6.0.6000.16384
+;CatalogFile = device.cat
+
+[Manufacturer]
+%Linux% = RndisDevices,NTx86,NTamd64,NTia64
+
+; Decoration for x86 architecture
+[RndisDevices.NTx86]
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
+
+; Decoration for x64 architecture
+[RndisDevices.NTamd64]
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
+
+; Decoration for ia64 architecture
+[RndisDevices.NTia64]
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
+
+;@@@ This is the common setting for setup
+[ControlFlags]
+ExcludeFromSelect=*
+
+; DDInstall section
+; References the in-build Netrndis.inf


+[RNDIS.NT.5.1]
+Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
+BusType = 15

+; NEVER REMOVE THE FOLLOWING REFERENCE FOR NETRNDIS.INF
+include = netrndis.inf
+needs = Usb_Rndis.ndi
+AddReg = Rndis_AddReg_Vista
+
+; DDInstal.Services section
+[RNDIS.NT.5.1.Services]
+include = netrndis.inf
+needs = Usb_Rndis.ndi.Services
+
+; Optional registry settings. You can modify as needed.
+[RNDIS_AddReg_Vista]
+HKR, NDI\params\VistaProperty, ParamDesc, 0, %Vista_Property%
+HKR, NDI\params\VistaProperty, type, 0, "edit"
+HKR, NDI\params\VistaProperty, LimitText, 0, "12"
+HKR, NDI\params\VistaProperty, UpperCase, 0, "1"
+HKR, NDI\params\VistaProperty, default, 0, " "
+HKR, NDI\params\VistaProperty, optional, 0, "1"
+
+; No sys copyfiles - the sys files are already in-build
+; (part of the operating system).
+; We do not support XP SP1-, 2003 SP1-, ME, 9x.
+
+; Modify these strings for your device as needed.
+[Strings]


+Linux = "Linux Developer Community"

+RndisDevice = "Ethernet/RNDIS Gadget"
+Vista_Property = "Optional Vista Property"
diff --git a/Documentation/usb/linux.inf b/Documentation/usb/linux.inf
deleted file mode 100644
index 2f7217d..0000000
--- a/Documentation/usb/linux.inf
+++ /dev/null
@@ -1,200 +0,0 @@
-; MS-Windows driver config matching some basic modes of the
-; Linux-USB Ethernet/RNDIS gadget firmware:
-;
-; - RNDIS plus CDC Ethernet ... this may be familiar as a DOCSIS
-; cable modem profile, and supports most non-Microsoft USB hosts
-;
-; - RNDIS plus CDC Subset ... used by hardware that incapable of
-; full CDC Ethernet support.
-;
-; Microsoft only directly supports RNDIS drivers, and bundled them into XP.
-; The Microsoft "Remote NDIS USB Driver Kit" is currently found at:
-; http://www.microsoft.com/whdc/hwdev/resources/HWservices/rndis.mspx
-
-
-[Version]
-Signature = "$CHICAGO$"
-Class = Net
-ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
-Provider = %Linux%
-Compatible = 1
-MillenniumPreferred = .ME
-DriverVer = 03/30/2004,0.0.0.0
-; catalog file would be used by WHQL
-;CatalogFile = Linux.cat
-
-[Manufacturer]
-%Linux% = LinuxDevices,NT.5.1
-
-[LinuxDevices]
-; NetChip IDs, used by both firmware modes
-%LinuxDevice% = RNDIS, USB\VID_0525&PID_a4a2
-
-[LinuxDevices.NT.5.1]
-%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
-
-[ControlFlags]
-ExcludeFromSelect=*
-
-; Windows 98, Windows 98 Second Edition specific sections --------
-
-[RNDIS]
-DeviceID = usb8023
-MaxInstance = 512
-DriverVer = 03/30/2004,0.0.0.0
-AddReg = RNDIS_AddReg_98, RNDIS_AddReg_Common
-
-[RNDIS_AddReg_98]
-HKR, , DevLoader, 0, *ndis
-HKR, , DeviceVxDs, 0, usb8023.sys
-HKR, NDIS, LogDriverName, 0, "usb8023"
-HKR, NDIS, MajorNdisVersion, 1, 5
-HKR, NDIS, MinorNdisVersion, 1, 0
-HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5"
-HKR, Ndi\Interfaces, DefLower, 0, "ethernet"
-HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5"
-HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
-HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_98"
-HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_98"
-HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_98"
-HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4a2"
-
-[RNDIS_Install_98]
-CopyFiles=RNDIS_CopyFiles_98
-
-[RNDIS_CopyFiles_98]
-usb8023.sys, usb8023w.sys, , 0
-rndismp.sys, rndismpw.sys, , 0
-
-; Windows Millennium Edition specific sections --------------------
-
-[RNDIS.ME]
-DeviceID = usb8023
-MaxInstance = 512
-DriverVer = 03/30/2004,0.0.0.0
-AddReg = RNDIS_AddReg_ME, RNDIS_AddReg_Common
-Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
-BusType = 15
-
-[RNDIS_AddReg_ME]
-HKR, , DevLoader, 0, *ndis
-HKR, , DeviceVxDs, 0, usb8023.sys
-HKR, NDIS, LogDriverName, 0, "usb8023"
-HKR, NDIS, MajorNdisVersion, 1, 5
-HKR, NDIS, MinorNdisVersion, 1, 0
-HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5"
-HKR, Ndi\Interfaces, DefLower, 0, "ethernet"
-HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5"
-HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
-HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_ME"
-HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_ME"
-HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_ME"
-HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4a2"
-
-[RNDIS_Install_ME]
-CopyFiles=RNDIS_CopyFiles_ME
-
-[RNDIS_CopyFiles_ME]
-usb8023.sys, usb8023m.sys, , 0
-rndismp.sys, rndismpm.sys, , 0
-
-; Windows 2000 specific sections ---------------------------------
-
-[RNDIS.NT]
-Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
-BusType = 15
-DriverVer = 03/30/2004,0.0.0.0
-AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common
-CopyFiles = RNDIS_CopyFiles_NT
-
-[RNDIS.NT.Services]
-AddService = USB_RNDIS, 2, RNDIS_ServiceInst_NT, RNDIS_EventLog
-
-[RNDIS_CopyFiles_NT]
-; no rename of files on Windows 2000, use the 'k' names as is
-usb8023k.sys, , , 0
-rndismpk.sys, , , 0
-
-[RNDIS_ServiceInst_NT]
-DisplayName = %ServiceDisplayName%
-ServiceType = 1
-StartType = 3
-ErrorControl = 1
-ServiceBinary = %12%\usb8023k.sys
-LoadOrderGroup = NDIS
-AddReg = RNDIS_WMI_AddReg_NT
-
-[RNDIS_WMI_AddReg_NT]
-HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismpk.sys"
-
-; Windows XP specific sections -----------------------------------
-
-[RNDIS.NT.5.1]
-Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
-BusType = 15
-DriverVer = 03/30/2004,0.0.0.0
-AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common
-; no copyfiles - the files are already in place
-
-[RNDIS.NT.5.1.Services]
-AddService = USB_RNDIS, 2, RNDIS_ServiceInst_51, RNDIS_EventLog
-
-[RNDIS_ServiceInst_51]
-DisplayName = %ServiceDisplayName%
-ServiceType = 1
-StartType = 3
-ErrorControl = 1
-ServiceBinary = %12%\usb8023.sys
-LoadOrderGroup = NDIS
-AddReg = RNDIS_WMI_AddReg_51
-
-[RNDIS_WMI_AddReg_51]
-HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismp.sys"
-
-; Windows 2000 and Windows XP common sections --------------------
-
-[RNDIS_AddReg_NT]
-HKR, Ndi, Service, 0, "USB_RNDIS"
-HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
-HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
-
-[RNDIS_EventLog]
-AddReg = RNDIS_EventLog_AddReg
-
-[RNDIS_EventLog_AddReg]
-HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll"
-HKR, , TypesSupported, 0x00010001, 7
-
-; Common Sections -------------------------------------------------
-
-[RNDIS_AddReg_Common]
-HKR, NDI\params\NetworkAddress, ParamDesc, 0, %NetworkAddress%
-HKR, NDI\params\NetworkAddress, type, 0, "edit"
-HKR, NDI\params\NetworkAddress, LimitText, 0, "12"
-HKR, NDI\params\NetworkAddress, UpperCase, 0, "1"
-HKR, NDI\params\NetworkAddress, default, 0, " "
-HKR, NDI\params\NetworkAddress, optional, 0, "1"
-
-[SourceDisksNames]
-1=%SourceDisk%,,1
-
-[SourceDisksFiles]
-usb8023m.sys=1
-rndismpm.sys=1
-usb8023w.sys=1
-rndismpw.sys=1
-usb8023k.sys=1
-rndismpk.sys=1
-
-[DestinationDirs]
-RNDIS_CopyFiles_98 = 10, system32/drivers
-RNDIS_CopyFiles_ME = 10, system32/drivers
-RNDIS_CopyFiles_NT = 12
-
-[Strings]
-ServiceDisplayName = "USB Remote NDIS Network Device Driver"
-NetworkAddress = "Network Address"
-Linux = "Linux Developer Community"
-LinuxDevice = "Linux USB Ethernet/RNDIS Gadget"
-SourceDisk = "Ethernet/RNDIS Gadget Driver Install Disk"
-

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:03 AM6/7/10
to
A short documentation of the g_multi driver along with INF
files for Windows XP SP3 are provided.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Documentation/usb/gadget_multi.txt | 149 +++++++++++++++++++++++++++++++++++
Documentation/usb/linux-cdc-acm.inf | 4 +-
Documentation/usb/linux-rndis.inf | 6 +-
3 files changed, 154 insertions(+), 5 deletions(-)
create mode 100644 Documentation/usb/gadget_multi.txt

diff --git a/Documentation/usb/gadget_multi.txt b/Documentation/usb/gadget_multi.txt
new file mode 100644
index 0000000..0bd9139
--- /dev/null
+++ b/Documentation/usb/gadget_multi.txt
@@ -0,0 +1,149 @@

+The good news is: you do not have to worry about most of the
+conditions!


+
+The only thing to worry is that the gadget has to have a single
+configuration so a dual RNDIS and CDC ECM gadget won't work unless you
+create a proper INF -- and of course, if you do submit it!
+

+*** Installing drivers for each function
+
+The other, trickier thing is making Windows install drivers for each


+individual function.
+
+For mass storage it is trivial since Windows detect it's an interface
+implementing USB Mass Storage class and selects appropriate driver.
+
+Things are harder with RDNIS and CDC ACM.
+
+**** RNDIS
+
+To make Windows select RNDIS drivers for the first function in the

+gadget, one needs to use the [[file:linux-rndis.inf]] file provided with
+this document. It "attaches" Window's RNDIS driver to the first
+interface of the gadget.


+
+Please note, that while testing we encountered some issues[6] when
+RNDIS was not the first interface. You do not need to worry abut it
+unless you are trying to develop your own gadget in which case watch
+out for this bug.
+
+**** CDC ACM
+

+Similarly, [[file:linux-cdc-acm.inf]] is provided for CDC ACM.
+


+**** Customising the gadget
+
+If you intend to hack the g_multi gadget be advised that rearranging
+functions will obviously change interface numbers for each of the
+functionality. As an effect provided INFs won't work since they have
+interface numbers hard-coded in them (it's not hard to change those

+though[7]).
+


+This also means, that after experimenting with g_multi and changing
+provided functions one should change gadget's vendor and/or product ID
+so there will be no collision with other customised gadgets or the
+original gadget.
+
+Failing to comply may cause brain damage after wondering for hours why
+things don't work as intended before realising Windows have cached

+some drivers information (changing USB port may sometimes help plus
+you might try using USBDeview[8] to remove the phantom device).
+
+**** INF testing
+
+Provided INF files have been tested on Windows XP SP3, Windows Vista
+and Windows 7, all 32-bit versions. It should work on 64-bit versions
+as well. It most likesy won't work on Windows prior to Windows XP
+SP2.


+
+** Other systems
+
+At this moment, drivers for any other systems have not been tested.
+Knowing how MacOS is based on BSD and BSD is an Open Source it is
+believed that it should (read: "I have no idea whether it will") work
+out-of-the-box.
+
+For more exotic systems I have even less to say...
+
+Any testing and drivers *are* *welcome*!
+
+* Authors
+
+This document has been written by Michal Nazarewicz

+([[mailto:min...@mina86.com]]) and INF files have been hacked with
+support of Marek Szyprowski ([[mailto:m.szyp...@samsung.com]]) and
+Xiaofan Chen ([[mailto:xiao...@gmail.com]]) basing on the MS RNDIS
+template[9] and Microchip's CDC ACM INF file.


+
+* Footnotes
+
+[1] Remote Network Driver Interface Specification,
+[[http://msdn.microsoft.com/en-us/library/ee484414.aspx]].
+
+[2] Communications Device Class Abstract Control Model, spec for this
+and other USB classes can be found at
+[[http://www.usb.org/developers/devclass_docs/]].
+
+[3] CDC Ethernet Control Model.
+
+[4] [[http://msdn.microsoft.com/en-us/library/ff537109(v=VS.85).aspx]]

+
+[6] To put it in some other nice words, Windows failed to respond to
+any user input.
+

+[7] You may find [[http://www.cygnal.org/ubb/Forum9/HTML/001050.html]]
+useful.
+
+[8] http://www.nirsoft.net/utils/usb_devices_view.html
+
+[9] [[http://msdn.microsoft.com/en-us/library/ff570620.aspx]]
diff --git a/Documentation/usb/linux-cdc-acm.inf b/Documentation/usb/linux-cdc-acm.inf
index 0e338e5..241d3d9 100644
--- a/Documentation/usb/linux-cdc-acm.inf
+++ b/Documentation/usb/linux-cdc-acm.inf
@@ -89,10 +89,10 @@ end of the line.
[SourceDisksFiles]
[SourceDisksNames]
[DeviceList]
-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7
+%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02

[DeviceList.NTamd64]
-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7
+%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02


;------------------------------------------------------------------------------
diff --git a/Documentation/usb/linux-rndis.inf b/Documentation/usb/linux-rndis.inf
index fa608fa..0cf87dc 100644
--- a/Documentation/usb/linux-rndis.inf
+++ b/Documentation/usb/linux-rndis.inf
@@ -30,15 +30,15 @@ DriverVer = 06/21/2006,6.0.6000.16384

; Decoration for x86 architecture
[RndisDevices.NTx86]
-%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00

; Decoration for x64 architecture
[RndisDevices.NTamd64]
-%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00

; Decoration for ia64 architecture
[RndisDevices.NTia64]
-%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00



;@@@ This is the common setting for setup

[ControlFlags]

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:03 AM6/7/10
to
Added pre_eject() and post_eject() callbacks which are
called befor and after removable logical unit is ejected.
The first can prevent logical unit from being ejected.

This commit also changes the way callbacks are passed to
the function from gadget. A fsg_operations structure has
been created which lists all callbacks -- this is passed
to the fsg_config.

This is important because it changes the way thread_exits()
callback is passed.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:04 AM6/7/10
to
Mass Storage Function had a bit unique name for function

used to add it to USB configuration. Renamed as to match
naming convention of other functions.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/f_mass_storage.c | 13 ++++++++++---
drivers/usb/gadget/mass_storage.c | 2 +-
drivers/usb/gadget/multi.c | 4 ++--

3 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 7d05a0b..072cbf9 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c


@@ -3023,9 +3023,9 @@ static struct usb_gadget_strings *fsg_strings_array[] = {
NULL,
};

-static int fsg_add(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
- struct fsg_common *common)
+static int fsg_bind_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *c,


+ struct fsg_common *common)
{
struct fsg_dev *fsg;
int rc;
@@ -3072,6 +3072,13 @@ error_free_fsg:
return rc;
}

+static inline int __deprecated __maybe_unused

+fsg_add(struct usb_composite_dev *cdev,
+ struct usb_configuration *c,


+ struct fsg_common *common)
+{
+ return fsg_bind_config(cdev, c, common);
+}


/************************* Module parameters *************************/

diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index a3349f2..d6975f4 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c


@@ -159,7 +159,7 @@ static int __init msg_do_config(struct usb_configuration *c)
if (IS_ERR(retp))
return PTR_ERR(retp);

- ret = fsg_add(c->cdev, c, &common);

+ ret = fsg_bind_config(c->cdev, c, &common);
fsg_common_put(&common);
return ret;
}
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index a930d7f..d3d3140 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c


@@ -172,7 +172,7 @@ static int __init rndis_do_config(struct usb_configuration *c)
if (ret < 0)

return ret;


- ret = fsg_add(c->cdev, c, fsg_common);
+ ret = fsg_bind_config(c->cdev, c, fsg_common);
if (ret < 0)
return ret;

@@ -208,7 +208,7 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (ret < 0)

return ret;


- ret = fsg_add(c->cdev, c, fsg_common);
+ ret = fsg_bind_config(c->cdev, c, fsg_common);
if (ret < 0)
return ret;

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:03 AM6/7/10
to
usb_string_ids_tab() and usb_string_ids_n() functions added to
the composite framework. The first accepts an array of
usb_string object and for each registeres a string id and the
second registeres a given number of ids and returns the first.

This may simplify string ids registration since gadgets and
composite functions won't have to call usb_string_id() several
times and each time check for errer status -- all this will be
done with a single call.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/composite.c | 71 +++++++++++++++++++++++++++++++++++++--
include/linux/usb/composite.h | 4 ++

2 files changed, 71 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 391d169..125167e 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c

+ return 0;
+}
+

diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 139353e..f378075 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h


@@ -342,6 +342,10 @@ struct usb_composite_dev {
};

extern int usb_string_id(struct usb_composite_dev *c);
+extern int usb_string_ids_tab(struct usb_composite_dev *c,
+ struct usb_string *str);
+extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
+

/* messaging utils */
#define DBG(d, fmt, args...) \

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:02 AM6/7/10
to
Added Kconfig options for each function used by g_multi so that
one can customize the gadget to a greater extend.

Note that it will be wise to change vendor and product ID when
customising the gadget.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Documentation/usb/gadget_multi.txt | 27 +++---
drivers/usb/gadget/Kconfig | 67 +++++++++-----
drivers/usb/gadget/multi.c | 166 ++++++++++++++++--------------------
3 files changed, 130 insertions(+), 130 deletions(-)

diff --git a/Documentation/usb/gadget_multi.txt b/Documentation/usb/gadget_multi.txt
index 0bd9139..ac3c547 100644
--- a/Documentation/usb/gadget_multi.txt
+++ b/Documentation/usb/gadget_multi.txt
@@ -2,20 +2,21 @@

* Overview

-The Multifunction Composite Gadget (or g_multi) is a composite gadget
-that makes extensive use of the composite framework to provide
-a... multifunction gadget.
+The Multifunction Composite Gadget (or g_multi) is a customisable
+composite gadget that makes extensive use of the composite framework
+to provide a... multifunction gadget.



In it's standard configuration it provides a single USB configuration

with RNDIS[1] (that is Ethernet), USB CDC[2] ACM (that is serial) and

USB Mass Storage functions.

-A CDC ECM (Ethernet) function may be turned on via a Kconfig option
-and RNDIS can be turned off. If they are both enabled the gadget will
-have two configurations -- one with RNDIS and another with CDC ECM[3].
+Each function can be disabled via a Kconfig option. There's also
+a CDC ECM (Ethernet) function which can be turned on. If CDC ECM and
+RNDIS are enabled the gadget will have two configurations -- one with
+RNDIS and another with CDC ECM[3].

-Please not that if you use non-standard configuration (that is enable
-CDC ECM) you may need to change vendor and/or product ID.
+Please not that if you use non-standard configuration you may need to
+change vendor and/or product ID.

* Host drivers

@@ -81,11 +82,11 @@ Similarly, [[file:linux-cdc-acm.inf]] is provided for CDC ACM.

**** Customising the gadget

-If you intend to hack the g_multi gadget be advised that rearranging
-functions will obviously change interface numbers for each of the
-functionality. As an effect provided INFs won't work since they have
-interface numbers hard-coded in them (it's not hard to change those
-though[7]).
+If you intend to customise (via Kconfig) or hack the g_multi gadget be
+advised that rearranging functions will obviously change interface
+numbers for each of the functionality. As an effect provided INFs
+won't work since they have interface numbers hard-coded in them (it's
+not hard to change those though[7]).



This also means, that after experimenting with g_multi and changing

provided functions one should change gadget's vendor and/or product ID

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 027f61b..6bf6c5c 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -862,43 +862,62 @@ config USB_G_NOKIA



config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"

- depends on BLOCK && NET
- select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
+ select USB_G_MULTI_ACM if !USB_G_MULTI_ANYTHING
help
- The Multifunction Composite Gadget provides Ethernet (RNDIS
- and/or CDC Ethernet), mass storage and ACM serial link
- interfaces.
-
- You will be asked to choose which of the two configurations is
- to be available in the gadget. At least one configuration must
- be chosen to make the gadget usable. Selecting more than one
- configuration will prevent Windows from automatically detecting
- the gadget as a composite gadget, so an INF file will be needed to
- use the gadget.
+ The Multifunction Composite Gadget provides several different
+ configurations and functions. Which interfaces are provided can
+ be configured at build time. If you choose this gadget additional
+ options will appear.

Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_multi".

-config USB_G_MULTI_RNDIS
- bool "RNDIS + CDC Serial + Storage configuration"
+config USB_G_MULTI_ANYTHING
+ bool
depends on USB_G_MULTI
+
+config USB_G_MULTI_RNDIS
+ bool "Include RNDIS function"
+ depends on USB_G_MULTI && NET
+ select USB_G_MULTI_ANYTHING
default y
help
- This option enables a configuration with RNDIS, CDC Serial and
- Mass Storage functions available in the Multifunction Composite
- Gadget. This is the configuration dedicated for Windows since RNDIS
- is Microsoft's protocol.
+ This option enables the RNDIS (Ethernet) function. It is
+ protocol dedicated for Windows since it's Microsoft's invention.
+
+ If you select also CDC ECM function gadget will have two
+ configurations one with RNDIS and another with CDC ECM.
+
+ If unsure, say "y".
+
+config USB_G_MULTI_ECM
+ bool "Include CDC ECM function"
+ depends on USB_G_MULTI && NET
+ select USB_G_MULTI_ANYTHING
+ help
+ This option enables the CDC ECM (Ethernet) function.
+
+ If you select also RNDIS function gadget will have two
+ configurations one with RNDIS and another with CDC ECM.



If unsure, say "y".

-config USB_G_MULTI_CDC
- bool "CDC Ethernet + CDC Serial + Storage configuration"
+config USB_G_MULTI_ACM
+ bool "Include CDC ACM function"
depends on USB_G_MULTI
- default n
+ default y
+ help
+ This option enables the CDC ACM (serial) function.
+
+ If unsure, say "y".
+
+config USB_G_MULTI_MSF
+ bool "Include mass storage function"


+ depends on USB_G_MULTI && BLOCK

+ select USB_G_MULTI_ANYTHING
+ default y
help
- This option enables a configuration with CDC Ethernet (ECM), CDC
- Serial and Mass Storage functions available in the Multifunction
- Composite Gadget.
+ This option enables the mass storage (or UMS) function.



If unsure, say "y".

diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index c7a5b58..6f6fd3e 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -57,19 +57,57 @@ MODULE_LICENSE("GPL");
#include "config.c"
#include "epautoconf.c"

-#include "f_mass_storage.c"
+/* Mass storage */
+#ifdef CONFIG_USB_G_MULTI_MSF
+# include "f_mass_storage.c"

-#include "u_serial.c"
-#include "f_acm.c"


+static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
+FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
+
+static struct fsg_common fsg_common;

+#else
+# define fsg_common_from_params(common, cdev, data) NULL
+# define fsg_bind_config(cdev, conf, common) ((int)0)
+# define fsg_common_put(common) do { } while (0)
+#endif

-#include "f_ecm.c"
-#include "f_subset.c"
-#ifdef USB_ETH_RNDIS
+/* CDC ACM */
+#ifdef CONFIG_USB_G_MULTI_ACM
+# include "u_serial.c"
+# include "f_acm.c"
+#else
+# define gserial_setup(conf, ports) ((int)0)
+# define gserial_cleanup() do { } while (0)
+# define acm_bind_config(conf, ports) ((int)0)
+#endif
+
+/* Ethernet */
+#ifdef CONFIG_USB_G_MULTI_ECM
+# include "f_ecm.c"
+# include "f_subset.c"
+#endif
+
+#ifdef CONFIG_USB_G_MULTI_RNDIS
# include "f_rndis.c"
# include "rndis.c"
#endif
-#include "u_ether.c"

+#if defined CONFIG_USB_G_MULTI_ECM || defined CONFIG_USB_G_MULTI_RNDIS
+# include "u_ether.c"
+static u8 hostaddr[ETH_ALEN];
+#else
+# define gether_setup(cdev, hostaddr) ((int)0)
+# define gether_cleanup() do { } while (0)
+#endif
+
+#ifndef CONFIG_USB_G_MULTI_ECM
+# define can_support_ecm(gadget) true
+# define ecm_bind_config(conf, ethaddr) ((int)0)
+#endif
+
+#ifndef CONFIG_USB_G_MULTI_RNDIS
+# define rndis_bind_config(conf, ethaddr) ((int)0)
+#endif


/***************************** Device Descriptor ****************************/
@@ -78,19 +116,6 @@ MODULE_LICENSE("GPL");


#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */


-enum {
- __MULTI_NO_CONFIG,
-#ifdef CONFIG_USB_G_MULTI_RNDIS
- MULTI_RNDIS_CONFIG_NUM,
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
- MULTI_CDC_CONFIG_NUM,
-#endif
- __MULTI_NUM_CONFIGS_HELPER,
- MULTI_NUM_CONFIGS = __MULTI_NUM_CONFIGS_HELPER - 1
-};
-
-


static struct usb_device_descriptor device_desc = {

.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
@@ -104,7 +129,11 @@ static struct usb_device_descriptor device_desc = {


/* Vendor and product id can be overridden by module parameters. */

.idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
.idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),

- .bNumConfigurations = MULTI_NUM_CONFIGS,


+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

+ .bNumConfigurations = 2,
+#else
+ .bNumConfigurations = 1,
+#endif
};


@@ -124,12 +153,6 @@ static const struct usb_descriptor_header *otg_desc[] = {
enum {
MULTI_STRING_MANUFACTURER_IDX,
MULTI_STRING_PRODUCT_IDX,
-#ifdef CONFIG_USB_G_MULTI_RNDIS
- MULTI_STRING_RNDIS_CONFIG_IDX,
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
- MULTI_STRING_CDC_CONFIG_IDX,
-#endif
};

static char manufacturer[50];
@@ -137,12 +160,6 @@ static char manufacturer[50];


static struct usb_string strings_dev[] = {
[MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
[MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC,

-#ifdef CONFIG_USB_G_MULTI_RNDIS
- [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
- [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM",
-#endif


{ } /* end of list */
};

@@ -159,19 +176,8 @@ static struct usb_gadget_strings *dev_strings[] = {

/****************************** Configurations ******************************/

-static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
-FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);

-static struct fsg_common fsg_common;
-
-static u8 hostaddr[ETH_ALEN];
-
-
-/********** RNDIS **********/
-
-#ifdef USB_ETH_RNDIS
-
-static __ref int rndis_do_config(struct usb_configuration *c)
+static __ref int first_do_config(struct usb_configuration *c)
{
int ret;

@@ -180,7 +186,11 @@ static __ref int rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}

+#ifdef CONFIG_USB_G_MULTI_RNDIS
ret = rndis_bind_config(c, hostaddr);
+#else
+ ret = ecm_bind_config(c, hostaddr);
+#endif


if (ret < 0)
return ret;

@@ -195,35 +205,17 @@ static __ref int rndis_do_config(struct usb_configuration *c)
return 0;
}

-static int rndis_config_register(struct usb_composite_dev *cdev)
-{
- static struct usb_configuration config = {
- .bind = rndis_do_config,
- .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,


- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- };
-

- config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
- config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
-
- return usb_add_config(cdev, &config);
-}
-
-#else
-
-static int rndis_config_register(struct usb_composite_dev *cdev)
-{
- return 0;
-}
-
-#endif
-
+static struct usb_configuration first_config_driver = {
+ .label = "First Configuration",


+ .bind = first_do_config,
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};

-/********** CDC ECM **********/

-#ifdef CONFIG_USB_G_MULTI_CDC


+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

-static __ref int cdc_do_config(struct usb_configuration *c)
+static __ref int second_do_config(struct usb_configuration *c)
{
int ret;

@@ -247,26 +239,12 @@ static __ref int cdc_do_config(struct usb_configuration *c)
return 0;
}

-static int cdc_config_register(struct usb_composite_dev *cdev)
-{
- static struct usb_configuration config = {
- .bind = cdc_do_config,
- .bConfigurationValue = MULTI_CDC_CONFIG_NUM,


- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- };
-

- config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
- config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
-
- return usb_add_config(cdev, &config);
-}
-
-#else
-
-static int cdc_config_register(struct usb_composite_dev *cdev)
-{
- return 0;
-}
+static struct usb_configuration second_config_driver = {
+ .label = "Second Configuration",


+ .bind = second_do_config,
+ .bConfigurationValue = 2,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+};

#endif

@@ -331,13 +309,15 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
strings_dev[MULTI_STRING_PRODUCT_IDX].id;

/* register configurations */
- status = rndis_config_register(cdev);
+ status = usb_add_config(cdev, &first_config_driver);


if (unlikely(status < 0))
goto fail2;

- status = cdc_config_register(cdev);


+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

+ status = usb_add_config(cdev, &second_config_driver);


if (unlikely(status < 0))
goto fail2;

+#endif



/* we're done */
dev_info(&gadget->dev, DRIVER_DESC "\n");

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:03 AM6/7/10
to
The Multifunction Compasite Gadget have been cleaned up
and refactored so hopefully it looks prettier and works
at least as good as before changes.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/Kconfig | 1 +
drivers/usb/gadget/multi.c | 262 +++++++++++++++++++++++++-------------------
2 files changed, 148 insertions(+), 115 deletions(-)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 591ae9f..027f61b 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -863,6 +863,7 @@ config USB_G_NOKIA


config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"

depends on BLOCK && NET

+ select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
help

The Multifunction Composite Gadget provides Ethernet (RNDIS

and/or CDC Ethernet), mass storage and ACM serial link

diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index d3d3140..c7a5b58 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -24,6 +24,7 @@

#include <linux/kernel.h>
#include <linux/utsname.h>

+ MULTI_NUM_CONFIGS = __MULTI_NUM_CONFIGS_HELPER - 1
+};
+



static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,

@@ -82,80 +97,81 @@ static struct usb_device_descriptor device_desc = {

.bcdUSB = cpu_to_le16(0x0200),

- /* .bDeviceClass = USB_CLASS_COMM, */
- /* .bDeviceSubClass = 0, */
- /* .bDeviceProtocol = 0, */
- .bDeviceClass = 0xEF,
+ .bDeviceClass = USB_CLASS_MISC /* 0xEF */,
.bDeviceSubClass = 2,
.bDeviceProtocol = 1,
- /* .bMaxPacketSize0 = f(hardware) */

/* Vendor and product id can be overridden by module parameters. */
.idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
.idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),

- /* .bcdDevice = f(hardware) */
- /* .iManufacturer = DYNAMIC */
- /* .iProduct = DYNAMIC */
- /* NO SERIAL NUMBER */
- .bNumConfigurations = 1,
+ .bNumConfigurations = MULTI_NUM_CONFIGS,
};

-static struct usb_otg_descriptor otg_descriptor = {
- .bLength = sizeof otg_descriptor,
- .bDescriptorType = USB_DT_OTG,
-
- /* REVISIT SRP-only hardware is possible, although
- * it would not be called "OTG" ...
- */
- .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
-};

static const struct usb_descriptor_header *otg_desc[] = {

- (struct usb_descriptor_header *) &otg_descriptor,
+ (struct usb_descriptor_header *) &(struct usb_otg_descriptor){
+ .bLength = sizeof(struct usb_otg_descriptor),
+ .bDescriptorType = USB_DT_OTG,
+
+ /* REVISIT SRP-only hardware is possible, although
+ * it would not be called "OTG" ... */
+ .bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
+ },
NULL,
};


-/* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX 0
-#define STRING_PRODUCT_IDX 1
+enum {
+ MULTI_STRING_MANUFACTURER_IDX,
+ MULTI_STRING_PRODUCT_IDX,
+#ifdef CONFIG_USB_G_MULTI_RNDIS
+ MULTI_STRING_RNDIS_CONFIG_IDX,
+#endif
+#ifdef CONFIG_USB_G_MULTI_CDC
+ MULTI_STRING_CDC_CONFIG_IDX,
+#endif
+};

static char manufacturer[50];

static struct usb_string strings_dev[] = {

- [STRING_MANUFACTURER_IDX].s = manufacturer,
- [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+ [MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
+ [MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC,
+#ifdef CONFIG_USB_G_MULTI_RNDIS

+ [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
+#endif
+#ifdef CONFIG_USB_G_MULTI_CDC
+ [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM",
+#endif


{ } /* end of list */
};

-static struct usb_gadget_strings stringtab_dev = {

- .language = 0x0409, /* en-us */
- .strings = strings_dev,

-};
-


static struct usb_gadget_strings *dev_strings[] = {

- &stringtab_dev,


+ &(struct usb_gadget_strings){
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+ },

NULL,
};

-static u8 hostaddr[ETH_ALEN];



/****************************** Configurations ******************************/


-static struct fsg_module_parameters mod_data = {
- .stall = 1
-};
-FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);

+static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
+FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
+
+static struct fsg_common fsg_common;

+
+static u8 hostaddr[ETH_ALEN];

-static struct fsg_common *fsg_common;

+/********** RNDIS **********/

#ifdef USB_ETH_RNDIS

-static int __init rndis_do_config(struct usb_configuration *c)
+static __ref int rndis_do_config(struct usb_configuration *c)
{
int ret;

@@ -172,26 +188,42 @@ static int __init rndis_do_config(struct usb_configuration *c)
if (ret < 0)
return ret;

- ret = fsg_bind_config(c->cdev, c, fsg_common);
+ ret = fsg_bind_config(c->cdev, c, &fsg_common);


if (ret < 0)
return ret;

return 0;
}


-static struct usb_configuration rndis_config_driver = {
- .label = "Multifunction Composite (RNDIS + MS + ACM)",

- .bind = rndis_do_config,


- .bConfigurationValue = 2,
- /* .iConfiguration = DYNAMIC */

- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};

+static int rndis_config_register(struct usb_composite_dev *cdev)
+{
+ static struct usb_configuration config = {
+ .bind = rndis_do_config,
+ .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,

+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
+ config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
+
+ return usb_add_config(cdev, &config);

+}
+
+#else
+
+static int rndis_config_register(struct usb_composite_dev *cdev)


+{
+ return 0;
+}

#endif

+
+/********** CDC ECM **********/
+
#ifdef CONFIG_USB_G_MULTI_CDC

-static int __init cdc_do_config(struct usb_configuration *c)
+static __ref int cdc_do_config(struct usb_configuration *c)
{
int ret;

@@ -208,20 +240,33 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (ret < 0)
return ret;

- ret = fsg_bind_config(c->cdev, c, fsg_common);
+ ret = fsg_bind_config(c->cdev, c, &fsg_common);


if (ret < 0)
return ret;

return 0;
}


-static struct usb_configuration cdc_config_driver = {
- .label = "Multifunction Composite (CDC + MS + ACM)",

- .bind = cdc_do_config,


- .bConfigurationValue = 1,
- /* .iConfiguration = DYNAMIC */

- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};

+static int cdc_config_register(struct usb_composite_dev *cdev)
+{
+ static struct usb_configuration config = {
+ .bind = cdc_do_config,
+ .bConfigurationValue = MULTI_CDC_CONFIG_NUM,

+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
+ config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;


+
+ return usb_add_config(cdev, &config);

+}
+
+#else
+
+static int cdc_config_register(struct usb_composite_dev *cdev)


+{
+ return 0;
+}

#endif

@@ -230,7 +275,7 @@ static struct usb_configuration cdc_config_driver = {
/****************************** Gadget Bind ******************************/


-static int __init multi_bind(struct usb_composite_dev *cdev)

+static int __ref multi_bind(struct usb_composite_dev *cdev)
{


struct usb_gadget *gadget = cdev->gadget;

int status, gcnum;
@@ -252,67 +297,57 @@ static int __init multi_bind(struct usb_composite_dev *cdev)
goto fail0;

/* set up mass storage function */

- fsg_common = fsg_common_from_params(0, cdev, &mod_data);
- if (IS_ERR(fsg_common)) {
- status = PTR_ERR(fsg_common);
- goto fail1;
+ {
+ void *retp;
+ retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
+ if (IS_ERR(retp)) {
+ status = PTR_ERR(retp);
+ goto fail1;
+ }
}

-
+ /* set bcdDevice */

gcnum = usb_gadget_controller_number(gadget);
- if (gcnum >= 0)

+ if (gcnum >= 0) {

device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
- else {

- /* We assume that can_support_ecm() tells the truth;
- * but if the controller isn't recognized at all then
- * that assumption is a bit more likely to be wrong.
- */

- WARNING(cdev, "controller '%s' not recognized\n",

- gadget->name);
+ } else {

+ WARNING(cdev, "controller '%s' not recognized\n", gadget->name);
device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
}


+ /* allocate string descriptor numbers */

- /* Allocate string descriptor numbers ... note that string
- * contents can be overridden by the composite_dev glue.
- */
-
- /* device descriptor strings: manufacturer, product */

snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",

init_utsname()->sysname, init_utsname()->release,
gadget->name);
- status = usb_string_id(cdev);

- if (status < 0)


- goto fail2;
- strings_dev[STRING_MANUFACTURER_IDX].id = status;
- device_desc.iManufacturer = status;

- status = usb_string_id(cdev);
- if (status < 0)
+ status = usb_string_ids_tab(cdev, strings_dev);

+ if (unlikely(status < 0))
goto fail2;


- strings_dev[STRING_PRODUCT_IDX].id = status;
- device_desc.iProduct = status;

-#ifdef USB_ETH_RNDIS
- /* register our first configuration */
- status = usb_add_config(cdev, &rndis_config_driver);
- if (status < 0)
+ device_desc.iManufacturer =
+ strings_dev[MULTI_STRING_MANUFACTURER_IDX].id;
+ device_desc.iProduct =
+ strings_dev[MULTI_STRING_PRODUCT_IDX].id;
+

+ /* register configurations */

+ status = rndis_config_register(cdev);
+ if (unlikely(status < 0))
goto fail2;


-#endif

-#ifdef CONFIG_USB_G_MULTI_CDC
- /* register our second configuration */
- status = usb_add_config(cdev, &cdc_config_driver);
- if (status < 0)
+ status = cdc_config_register(cdev);

+ if (unlikely(status < 0))
goto fail2;


-#endif

- dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
- fsg_common_put(fsg_common);

+ /* we're done */
+ dev_info(&gadget->dev, DRIVER_DESC "\n");
+ fsg_common_put(&fsg_common);
return 0;

+


+ /* error recovery */
fail2:
- fsg_common_put(fsg_common);
+ fsg_common_put(&fsg_common);
fail1:
gserial_cleanup();
fail0:
@@ -339,18 +374,15 @@ static struct usb_composite_driver multi_driver = {
.unbind = __exit_p(multi_unbind),
};

-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Michal Nazarewicz");
-MODULE_LICENSE("GPL");

-static int __init g_multi_init(void)
+static int __init multi_init(void)
{
return usb_composite_register(&multi_driver);
}
-module_init(g_multi_init);
+module_init(multi_init);

-static void __exit g_multi_cleanup(void)
+static void __exit multi_exit(void)
{
usb_composite_unregister(&multi_driver);
}
-module_exit(g_multi_cleanup);
+module_exit(multi_exit);

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:04 AM6/7/10
to
Updated the INF file for g_serial gadget. It should work with

most recent Windows systems now.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Documentation/usb/gadget_serial.txt | 87 +++-------------------------
Documentation/usb/linux-cdc-acm.inf | 106 +++++++++++++++++++++++++++++++++++
2 files changed, 116 insertions(+), 77 deletions(-)
create mode 100644 Documentation/usb/linux-cdc-acm.inf

diff --git a/Documentation/usb/gadget_serial.txt b/Documentation/usb/gadget_serial.txt
index eac7df9..61e67f6 100644
--- a/Documentation/usb/gadget_serial.txt
+++ b/Documentation/usb/gadget_serial.txt
@@ -151,88 +151,23 @@ instructions below to install the host side driver.

Installing the Windows Host ACM Driver
--------------------------------------
-To use the Windows ACM driver you must have the files "gserial.inf"
-and "usbser.sys" together in a folder on the Windows machine.
-
-The "gserial.inf" file is given here.
-
--------------------- CUT HERE --------------------
-[Version]
-Signature="$Windows NT$"
-Class=Ports
-ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
-Provider=%LINUX%
-DriverVer=08/17/2004,0.0.2.0
-; Copyright (C) 2004 Al Borchers (albor...@steinerpoint.com)
-
-[Manufacturer]
-%LINUX%=GSerialDeviceList
-
-[GSerialDeviceList]
-%GSERIAL%=GSerialInstall, USB\VID_0525&PID_A4A7
-
-[DestinationDirs]
-DefaultDestDir=10,System32\Drivers
-
-[GSerialInstall]
-CopyFiles=GSerialCopyFiles
-AddReg=GSerialAddReg
-
-[GSerialCopyFiles]
-usbser.sys
-
-[GSerialAddReg]
-HKR,,DevLoader,,*ntkern
-HKR,,NTMPDriver,,usbser.sys
-HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
-
-[GSerialInstall.Services]
-AddService = usbser,0x0002,GSerialService
-
-[GSerialService]
-DisplayName = %GSERIAL_DISPLAY_NAME%
-ServiceType = 1 ; SERVICE_KERNEL_DRIVER
-StartType = 3 ; SERVICE_DEMAND_START
-ErrorControl = 1 ; SERVICE_ERROR_NORMAL
-ServiceBinary = %10%\System32\Drivers\usbser.sys
-LoadOrderGroup = Base
-
-[Strings]
-LINUX = "Linux"
-GSERIAL = "Gadget Serial"
-GSERIAL_DISPLAY_NAME = "USB Gadget Serial Driver"
--------------------- CUT HERE --------------------
-
-The "usbser.sys" file comes with various versions of Windows.
-For example, it can be found on Windows XP typically in
-
- C:\WINDOWS\Driver Cache\i386\driver.cab
-
-Or it can be found on the Windows 98SE CD in the "win98" folder
-in the "DRIVER11.CAB" through "DRIVER20.CAB" cab files. You will
-need the DOS "expand" program, the Cygwin "cabextract" program, or
-a similar program to unpack these cab files and extract "usbser.sys".
-
-For example, to extract "usbser.sys" into the current directory
-on Windows XP, open a DOS window and run a command like
-
- expand C:\WINDOWS\Driver~1\i386\driver.cab -F:usbser.sys .
-
-(Thanks to Nishant Kamat for pointing out this DOS command.)
+To use the Windows ACM driver you must have the "linux-cdc-acm.inf"
+file (provided along this document) which supports all recent versions
+of Windows.

When the gadget serial driver is loaded and the USB device connected
to the Windows host with a USB cable, Windows should recognize the
gadget serial device and ask for a driver. Tell Windows to find the
-driver in the folder that contains "gserial.inf" and "usbser.sys".
+driver in the folder that contains the "linux-cdc-acm.inf" file.

For example, on Windows XP, when the gadget serial device is first
plugged in, the "Found New Hardware Wizard" starts up. Select
-"Install from a list or specific location (Advanced)", then on
-the next screen select "Include this location in the search" and
-enter the path or browse to the folder containing "gserial.inf" and
-"usbser.sys". Windows will complain that the Gadget Serial driver
-has not passed Windows Logo testing, but select "Continue anyway"
-and finish the driver installation.
+"Install from a list or specific location (Advanced)", then on the
+next screen select "Include this location in the search" and enter the
+path or browse to the folder containing the "linux-cdc-acm.inf" file.
+Windows will complain that the Gadget Serial driver has not passed
+Windows Logo testing, but select "Continue anyway" and finish the
+driver installation.

On Windows XP, in the "Device Manager" (under "Control Panel",
"System", "Hardware") expand the "Ports (COM & LPT)" entry and you
@@ -345,5 +280,3 @@ you should be able to send data back and forth between the gadget
side and host side systems. Anything you type on the terminal
window on the gadget side should appear in the terminal window on
the host side and vice versa.
-
-
diff --git a/Documentation/usb/linux-cdc-acm.inf b/Documentation/usb/linux-cdc-acm.inf
new file mode 100644
index 0000000..0e338e5
--- /dev/null
+++ b/Documentation/usb/linux-cdc-acm.inf
@@ -0,0 +1,106 @@
+; Windows USB CDC ACM Setup File
+; Copyright (c) 2000 Microsoft Corporation
+; Copyright (C) 2007 Microchip Technology Inc.


+
+; Hacked for Linux by Michal Nazarewicz <min...@mina86.com>

+; No, I do not understand this file, don't blame me if it does not
+; work... Thanks to Xiaofan Chen for pointing to this file.
+


+[Version]
+Signature="$Windows NT$"
+Class=Ports
+ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}

+Provider=%Linux%
+DriverVer=11/15/2007,5.1.2600.0
+
+[Manufacturer]
+%Linux%=DeviceList, NTamd64
+
+[DestinationDirs]
+DefaultDestDir=12
+
+
+;------------------------------------------------------------------------------
+; Windows 2000/XP/Vista-32bit Sections
+;------------------------------------------------------------------------------
+
+[DriverInstall.nt]
+include=mdmcpq.inf
+CopyFiles=DriverCopyFiles.nt
+AddReg=DriverInstall.nt.AddReg
+
+[DriverCopyFiles.nt]
+usbser.sys,,,0x20
+
+[DriverInstall.nt.AddReg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,USBSER.sys
+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
+
+[DriverInstall.nt.Services]
+AddService=usbser, 0x00000002, DriverService.nt
+
+[DriverService.nt]
+DisplayName=%SERVICE%
+ServiceType=1
+StartType=3
+ErrorControl=1
+ServiceBinary=%12%\USBSER.sys
+
+;------------------------------------------------------------------------------
+; Vista-64bit Sections
+;------------------------------------------------------------------------------
+
+[DriverInstall.NTamd64]
+include=mdmcpq.inf
+CopyFiles=DriverCopyFiles.NTamd64
+AddReg=DriverInstall.NTamd64.AddReg
+
+[DriverCopyFiles.NTamd64]
+USBSER.sys,,,0x20
+
+[DriverInstall.NTamd64.AddReg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,USBSER.sys
+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
+
+[DriverInstall.NTamd64.Services]
+AddService=usbser, 0x00000002, DriverService.NTamd64
+
+[DriverService.NTamd64]
+DisplayName=%SERVICE%
+ServiceType=1
+StartType=3
+ErrorControl=1
+ServiceBinary=%12%\USBSER.sys
+
+
+;------------------------------------------------------------------------------
+; Vendor and Product ID Definitions
+;------------------------------------------------------------------------------
+; When developing your USB device, the VID and PID used in the PC side
+; application program and the firmware on the microcontroller must match.
+; Modify the below line to use your VID and PID. Use the format as shown below.
+; Note: One INF file can be used for multiple devices with different
+VID and PIDs.
+; For each supported device, append ",USB\VID_xxxx&PID_yyyy" to the
+end of the line.
+;------------------------------------------------------------------------------
+[SourceDisksFiles]
+[SourceDisksNames]
+[DeviceList]
+%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7
+
+[DeviceList.NTamd64]
+%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7
+
+
+;------------------------------------------------------------------------------
+; String Definitions
+;------------------------------------------------------------------------------
+;Modify these strings to customize your device
+;------------------------------------------------------------------------------


+[Strings]
+Linux = "Linux Developer Community"

+DESCRIPTION = "Gadget Serial"
+SERVICE = "USB RS-232 Emulation Driver"

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:03 AM6/7/10
to
Added a disconnect() callback to compasite devices which
is called by composite glue when its disconnect callback
is called by gadget.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

drivers/usb/gadget/composite.c | 2 ++
include/linux/usb/composite.h | 2 ++

2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 125167e..e483f80 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c


@@ -956,6 +956,8 @@ static void composite_disconnect(struct usb_gadget *gadget)
spin_lock_irqsave(&cdev->lock, flags);
if (cdev->config)
reset_config(cdev);
+ if (composite->disconnect)
+ composite->disconnect(cdev);
spin_unlock_irqrestore(&cdev->lock, flags);
}

diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index f378075..890bc14 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h


@@ -276,6 +276,8 @@ struct usb_composite_driver {
int (*bind)(struct usb_composite_dev *);
int (*unbind)(struct usb_composite_dev *);

+ void (*disconnect)(struct usb_composite_dev *);
+
/* global suspend hooks */
void (*suspend)(struct usb_composite_dev *);
void (*resume)(struct usb_composite_dev *);

Michal Nazarewicz

unread,
Jun 7, 2010, 8:50:04 AM6/7/10
to
Added an Install Mode to the Multifunction Composite Gadget. This
mode makes the gadget appear as a mass storage device with first
logical unit simulating CD-ROM until an eject on that logical unit
is requested because then gadget switches to the "full flagged"
gadget.

The intend is that in Install Mode the gadget will provide only
a CD-ROM with drivers for host platform. After the drivers are
intstalled the gadget will switch to the proper gadget and the
newly installed drivers will handle it.

When the device is disconnected form the host machine (or host
reboots or whatever that couses suspend or disconnect) the gadget
will switch to Install Mode again.

Because disconnect is a normal situation on re-enumeration gadget
"ignores" all disconnects and suspends during the first 10 seconds
after an eject.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Documentation/usb/gadget_multi.txt | 65 ++++-
drivers/usb/gadget/Kconfig | 22 ++
drivers/usb/gadget/multi.c | 597 +++++++++++++++++++++++++++++-------
3 files changed, 570 insertions(+), 114 deletions(-)

diff --git a/Documentation/usb/gadget_multi.txt b/Documentation/usb/gadget_multi.txt
index ac3c547..ca10f79 100644
--- a/Documentation/usb/gadget_multi.txt
+++ b/Documentation/usb/gadget_multi.txt
@@ -18,6 +18,11 @@ RNDIS and another with CDC ECM[3].


Please not that if you use non-standard configuration you may need to

change vendor and/or product ID.

+The driver provides also an "install mode" which you may also call
+NoCD ore ZereCD (expect the later is a trademark) which lets one
+develop an image with drivers which install automatically on systems
+like Windows.
+
* Host drivers

To make use of the gadget one needs to make it work on host side --

@@ -35,6 +40,10 @@ This is also true for two configuration set-up with RNDIS


configuration being the first one. Linux host will use the second

configuration with CDC ECM which should work better under Linux.

+The only exception is when install mode is enabled in which case the
+gadget will appear as a plain mass storage device unless it is
+ejected. Read appropriate section of this document to find out more.
+
** Windows host drivers

For the gadget two work under Windown two conditions have to be met:

@@ -116,13 +125,61 @@ For more exotic systems I have even less to say...



Any testing and drivers *are* *welcome*!

+** Interoperability with host
+


+As said, the idea behind install mode is that hosts that require
+drivers will be able to get them without the need for additional
+CD-ROM or another medium provided with the device.
+
+CD-ROM image should provide an "autorun" functionality witch will
+install drivers and eject the emulated CD-ROM to switch gadget into
+the other mode which will be handled by newly installed drivers. If
+drivers are installed already, they should "catch" the install mode
+device by product and vendor IDs and issue an eject.
+
+This mode is not very Linux-friendly though since Linux and Linux
+based systems have no notion of autorun (which from security point of
+view is a good thing) and there's no way of adding some file on the
+image which will make gadget eject the device.
+

+Fortunately, there's USB_ModeSwitch[9] and/or udev[10] which


+should handle it just fine. A single rule need to be added and
+everything should work fine.
+
* Authors

This document has been written by Michal Nazarewicz

([[mailto:min...@mina86.com]]) and INF files have been hacked with

support of Marek Szyprowski ([[mailto:m.szyp...@samsung.com]]) and

Xiaofan Chen ([[mailto:xiao...@gmail.com]]) basing on the MS RNDIS

-template[9] and Microchip's CDC ACM INF file.
+template[11] and Microchip's CDC ACM INF file.

* Footnotes

@@ -147,4 +204,8 @@ useful.

[8] http://www.nirsoft.net/utils/usb_devices_view.html

-[9] [[http://msdn.microsoft.com/en-us/library/ff570620.aspx]]
+[9] [[http://www.draisberghof.de/usb_modeswitch/]]
+
+[10] [[http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html]]
+
+[11] [[http://msdn.microsoft.com/en-us/library/ff570620.aspx]]
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 6bf6c5c..5b1cce6 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -921,6 +921,28 @@ config USB_G_MULTI_MSF



If unsure, say "y".

+config USB_G_MULTI_INSTALL
+ bool "Install Mode"

+ depends on USB_G_MULTI && BLOCK

+ default n
+ help


+ This option enables an "Install Mode" configuration. You may
+ also refer to in as NoCD or ZeroCD (although the later is
+ a trademark).
+
+ This mode makes gadget appear as an USB Mass Storage device
+ emulating a CD-ROM the first time it is connected. The intend
+ is that you can put drivers for your gadget on the disk image.
+
+ When eject request is sent to the logical translation unit
+ gadget switches its mode to the full flagged gadget with all the
+ other functions.
+
+ When device is disconnected, gadget once again switches to the
+ Install Mode configuration.

+


+ If unsure, say "n".
+
config USB_G_HID
tristate "HID Gadget"
help

diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 6f6fd3e..1946584 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -25,6 +25,8 @@
#include <linux/kernel.h>
#include <linux/utsname.h>


#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>


#if defined USB_ETH_RNDIS

@@ -57,18 +59,27 @@ MODULE_LICENSE("GPL");
#include "config.c"
#include "epautoconf.c"


-/* Mass storage */
-#ifdef CONFIG_USB_G_MULTI_MSF
+/* Mass storage & Install Mode */
+#if defined CONFIG_USB_G_MULTI_MSF || defined CONFIG_USB_G_MULTI_INSTALL
# include "f_mass_storage.c"
-

static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };

FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
-
static struct fsg_common fsg_common;
#else

-# define fsg_common_from_params(common, cdev, data) NULL


# define fsg_bind_config(cdev, conf, common) ((int)0)

-# define fsg_common_put(common) do { } while (0)
+#endif

+static int multi_eject(struct fsg_common *common,


+ struct fsg_lun *lun, int num);

+static void multi_disconnect(struct usb_composite_dev *cdev);
+#else
+# define multi_disconnect NULL
+#endif
+
+
+
/***************************** Device Descriptor ****************************/

+/* Main device */

#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */

#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */

static const struct usb_descriptor_header *otg_desc[] = {

(struct usb_descriptor_header *) &(struct usb_otg_descriptor){

.bLength = sizeof(struct usb_otg_descriptor),
@@ -150,9 +200,17 @@ static const struct usb_descriptor_header *otg_desc[] = {
};


+/* Strings */
enum {
MULTI_STRING_MANUFACTURER_IDX,
MULTI_STRING_PRODUCT_IDX,
+ MULTI_STRING_FIRST_CFG_IDX,

+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

+ MULTI_STRING_SECOND_CFG_IDX,
+#endif
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ MULTI_STRING_INSTALL_MODE_IDX,
+#endif
};

static char manufacturer[50];
@@ -160,24 +218,42 @@ static char manufacturer[50];


static struct usb_string strings_dev[] = {
[MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
[MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC,

+ [MULTI_STRING_FIRST_CFG_IDX].s = "First Configuration",

+#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

+ [MULTI_STRING_SECOND_CFG_IDX].s = "Second Configuration",
+#endif
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ [MULTI_STRING_INSTALL_MODE_IDX].s = "Install Mode [NoCD]",
+#endif

{ } /* end of list */
};

-static struct usb_gadget_strings *dev_strings[] = {
- &(struct usb_gadget_strings){


- .language = 0x0409, /* en-us */
- .strings = strings_dev,

+/* The driver */
+static struct usb_composite_driver multi_driver = {
+ .name = "g_multi",
+ .dev = &multi_device_desc,
+ .strings = (struct usb_gadget_strings *[]) {

+ &(struct usb_gadget_strings) {
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+ },

+ NULL,
},
- NULL,
+ .bind = multi_bind,
+ .disconnect = multi_disconnect,
+ .suspend = multi_disconnect,
};

-
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+# define device_desc (*(struct usb_device_descriptor *)multi_driver.dev)
+#else
+# define device_desc multi_device_desc
+#endif


/****************************** Configurations ******************************/

-

-static __ref int first_do_config(struct usb_configuration *c)
+static int first_do_config(struct usb_configuration *c)
{
int ret;


@@ -186,36 +262,51 @@ static __ref int first_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}

+ /* First configuration can have either RNDIS or ECM. This
+ * depends on wthether RNDIS is turned on. If it is then
+ * first config is always RNDIS because even if ECM is on as
+ * well it is the second config. */

#ifdef CONFIG_USB_G_MULTI_RNDIS
ret = rndis_bind_config(c, hostaddr);

#else
ret = ecm_bind_config(c, hostaddr);
#endif
- if (ret < 0)

+ if (unlikely(ret < 0))
return ret;


ret = acm_bind_config(c, 0);
- if (ret < 0)
+ if (unlikely(ret < 0))

return ret;


- ret = fsg_bind_config(c->cdev, c, &fsg_common);
- if (ret < 0)
- return ret;
+ if (have_fsg) {
+ /* We need to check if we want mass storage since it
+ * may have been forced on by the install mode even
+ * though user does not want it in the proper USB
+ * configurations. */

+ ret = fsg_bind_config(c->cdev, c, &fsg_common);

+ if (unlikely(ret < 0))
+ return ret;
+ }

return 0;
}


-static struct usb_configuration first_config_driver = {
- .label = "First Configuration",
- .bind = first_do_config,
- .bConfigurationValue = 1,

- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};
-

+static int add_first_config(struct usb_composite_dev *cdev)
+{
+ static struct usb_configuration driver = {


+ .bind = first_do_config,
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ driver.iConfiguration = strings_dev[MULTI_STRING_FIRST_CFG_IDX].id;
+ driver.label = strings_dev[MULTI_STRING_FIRST_CFG_IDX].s;
+ return usb_add_config(cdev, &driver);
+}

#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM

-static __ref int second_do_config(struct usb_configuration *c)
+static int second_do_config(struct usb_configuration *c)
{
int ret;

@@ -225,144 +316,426 @@ static __ref int second_do_config(struct usb_configuration *c)


}

ret = ecm_bind_config(c, hostaddr);
- if (ret < 0)

+ if (unlikely(ret < 0))
return ret;


ret = acm_bind_config(c, 0);
- if (ret < 0)
+ if (unlikely(ret < 0))

return ret;


- ret = fsg_bind_config(c->cdev, c, &fsg_common);
- if (ret < 0)
- return ret;
+ if (have_fsg) {
+ /* We need to check if we want mass storage since it
+ * may have been forced on by the install mode even
+ * though user does not want it in the proper USB
+ * configurations. */

+ ret = fsg_bind_config(c->cdev, c, &fsg_common);

+ if (unlikely(ret < 0))
+ return ret;
+ }

return 0;
}


-static struct usb_configuration second_config_driver = {
- .label = "Second Configuration",
- .bind = second_do_config,
- .bConfigurationValue = 2,

- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};

+static int add_second_config(struct usb_composite_dev *cdev)
+{
+ static struct usb_configuration driver = {


+ .bind = second_do_config,
+ .bConfigurationValue = 2,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ driver.iConfiguration = strings_dev[MULTI_STRING_FIRST_CFG_IDX].id;
+ driver.label = strings_dev[MULTI_STRING_FIRST_CFG_IDX].s;
+ return usb_add_config(cdev, &driver);

+}
+
+#else
+
+static int add_second_config(struct usb_composite_dev *cdev)
+{


+ return 0;
+}
+

+# define multi_worker_exit() do { } while (0)
+#endif
+


+
+/****************************** Install Mode *****************************/
+
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+
+static int install_mode_do_config(struct usb_configuration *c)
+{
+ if (gadget_is_otg(c->cdev->gadget)) {
+ c->descriptors = otg_desc;
+ c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
+ return fsg_bind_config(c->cdev, c, &fsg_common);
+}
+

+static int add_install_mode_config(struct usb_composite_dev *cdev)
+{


+ static struct usb_configuration driver = {
+ .bind = install_mode_do_config,

+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };

+
+ driver.iConfiguration = strings_dev[MULTI_STRING_INSTALL_MODE_IDX].id;
+ driver.label = strings_dev[MULTI_STRING_INSTALL_MODE_IDX].s;
+ return usb_add_config(cdev, &driver);
+}
+
+
+/* Jiffies of the last eject request on LUN 0. */
+static unsigned long multi_eject_jiffies;
+

+static int multi_eject(struct fsg_common *common,


+ struct fsg_lun *lun, int num)

+{
+ if (num)
+ return 0;
+


+ multi_eject_jiffies = jiffies;
+ next_install_mode = 0;
+ multi_worker_schedule();
+
+ return 1; /* Prevent realy unmounting the device */
+}
+
+static void multi_disconnect(struct usb_composite_dev *cdev)
+{
+ printk(KERN_INFO "multi_disconnect()\n");
+
+ /* Change back to install mode only if there was an eject
+ * (this is checked by looking if multi_eject_jiffies is
+ * non-zero), we are not switching to install mode already (no
+ * point in doing anything if next_install_mode is aleady one)
+ * and at least 10 seconds passed since last eject. */
+ /* Funky stuff may happen when jiffies wrap but we do not
+ * care. */
+ if (multi_eject_jiffies && !next_install_mode &&
+ jiffies >= multi_eject_jiffies + 10 * HZ) {
+ next_install_mode = 1;
+ multi_worker_schedule();
+ }

+}
+
+#else
+
+static int add_install_mode_config(struct usb_composite_dev *cdev)
+{


+ return 0;
+}
+

+#endif


/****************************** Gadget Bind ******************************/

+#if defined CONFIG_USB_G_MULTI_MSF || defined CONFIG_USB_G_MULTI_INSTALL

-static int __ref multi_bind(struct usb_composite_dev *cdev)
+static int __dyn_init multi_fsg_setup(struct usb_composite_dev *cdev)
{
- struct usb_gadget *gadget = cdev->gadget;
- int status, gcnum;
+ struct fsg_config cfg;
+ void *ret;
+
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ /* In install mode, make the first logical unit a read
+ * only removable CD-ROM. In addition if mass storage
+ * is used only for install mode, sot number of
+ * logical units to 1. */
+ if (!have_fsg)
+ fsg_mod_data.luns = 1;
+ fsg_mod_data.ro[0] = 1;
+ fsg_mod_data.removable[0] = 1;
+ fsg_mod_data.cdrom[0] = 1;

+ fsg_mod_data.ro_count = max(fsg_mod_data.ro_count, 1u);
+ fsg_mod_data.removable_count = max(fsg_mod_data.removable_count, 1u);
+ fsg_mod_data.cdrom_count = max(fsg_mod_data.cdrom_count, 1u);


+#endif

- if (!can_support_ecm(cdev->gadget)) {

- dev_err(&gadget->dev, "controller '%s' not usable\n",
- gadget->name);


- return -EINVAL;
+ fsg_config_from_params(&cfg, &fsg_mod_data);
+
+#ifdef CONFIG_USB_G_MULTI_INSTALL
+ {
+ static const struct fsg_operations ops = {
+ .pre_eject = multi_eject,
+ };
+ cfg.ops = &ops;
}
+#endif
+
+ ret = fsg_common_init(&fsg_common, cdev, &cfg);
+ return unlikely(IS_ERR(ret)) ? PTR_ERR(ret) : 0;
+}
+
+#endif
+

+static int __dyn_init multi_setup(struct usb_composite_dev *cdev)
+{
+ int ret;
+
+#if defined CONFIG_USB_G_MULTI_RNDIS || defined CONFIG_USB_G_MULTI_ECM
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);

- if (status < 0)


- return status;
+ if (!test_and_set_bit(1, &multi_initialised)) {
+ ret = gether_setup(cdev->gadget, hostaddr);
+ if (unlikely(ret < 0)) {
+ clear_bit(1, &multi_initialised);
+ goto fail;
+ }
+ }
+#endif

+#if defined CONFIG_USB_G_MULTI_ACM
/* set up serial link layer */
- status = gserial_setup(cdev->gadget, 1);

- if (status < 0)

- gcnum = usb_gadget_controller_number(gadget);
- if (gcnum >= 0) {
- device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
- } else {

+ /* allocate string descriptor numbers */

+ if (!*manufacturer)
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);

status = usb_string_ids_tab(cdev, strings_dev);
if (unlikely(status < 0))
- goto fail2;
+ goto fail;
+
+ printk(KERN_INFO "install_mode = %d\n", install_mode);

+ /* register configurations */

+ if (install_mode) {
+ status = add_install_mode_config(cdev);
+ } else {
+ status = add_first_config(cdev);
+ if (unlikely(status < 0))
+ goto fail;
+
+ status = add_second_config(cdev);
+ if (unlikely(status < 0))
+ goto fail;
+ }
+

+ /* Fill the rest of the device descriptor */
device_desc.iManufacturer =


strings_dev[MULTI_STRING_MANUFACTURER_IDX].id;
device_desc.iProduct =
strings_dev[MULTI_STRING_PRODUCT_IDX].id;

- /* register configurations */
- status = usb_add_config(cdev, &first_config_driver);
- if (unlikely(status < 0))
- goto fail2;
-
-#if defined CONFIG_USB_G_MULTI_RNDIS && defined CONFIG_USB_G_MULTI_ECM
- status = usb_add_config(cdev, &second_config_driver);
- if (unlikely(status < 0))
- goto fail2;
-#endif
+ status = usb_gadget_controller_number(cdev->gadget);
+ device_desc.bcdDevice =
+ cpu_to_le16(0x300 | (status < 0 ? 0x99 : status));

/* we're done */
dev_info(&gadget->dev, DRIVER_DESC "\n");

David Brownell

unread,
Jun 8, 2010, 9:00:01 AM6/8/10
to

--- On Mon, 6/7/10, Michal Nazarewicz <m.naza...@samsung.com> wrote:


> +; Copyright (c) Microsoft Corporation


Erm, do we have the right to redistribute
these changes, then?


In principle, supporting more versions
of MS-Windows is a good thing, but we need
appropriate rights to do so, and it's not
clear to me that we have those rights ..

Xiaofan Chen

unread,
Jun 8, 2010, 9:20:01 AM6/8/10
to
On Tue, Jun 8, 2010 at 8:57 PM, David Brownell <dav...@pacbell.net> wrote:
> --- On Mon, 6/7/10, Michal Nazarewicz <m.naza...@samsung.com> wrote:
>> +; Copyright (c) Microsoft Corporation
>
> Erm, do we have the right to redistribute
> these changes, then?
>
>
> In principle, supporting more versions
> of MS-Windows is a good thing, but we need
> appropriate rights to do so, and it's not
> clear to me that we have those rights ..

http://msdn.microsoft.com/en-us/library/ff570620.aspx

I will think you can redistribute the file. After all, the template
is provided by Microsoft to an IHV (independent hardware vendor)
to use the Remote NDIS driver.

--
Xiaofan http://mcuee.blogspot.com

David Brownell

unread,
Jun 8, 2010, 9:20:02 AM6/8/10
to
> +; Copyright (c) 2000 Microsoft Corporation

Same comment as with the INF file for g_ether:

If you're giving Microsoft credit for this,
you should make sure we have the right to
redistribute the changes ...

To the extent that your patches reduce our
ability to redistribute these INF files and
thus use these drivers with MS-Windows ... NAK.

It's my understanding that pulling fragments
from INF files comes under "fair use" and
thus copyright does not need to be assigned.
Microsoft publishes these things with the
expectation they'll be copied/pasted all over...

Xiaofan Chen

unread,
Jun 8, 2010, 9:30:01 AM6/8/10
to
On Tue, Jun 8, 2010 at 9:13 PM, David Brownell <dav...@pacbell.net> wrote:
>
> It's my understanding that pulling fragments
> from INF files comes under "fair use" and
> thus copyright does not need to be assigned.
> Microsoft publishes these things with the
> expectation they'll be copied/pasted all over...
>
>

I agree with you here.


--
Xiaofan http://mcuee.blogspot.com

David Brownell

unread,
Jun 8, 2010, 9:40:02 AM6/8/10
to

--- On Mon, 6/7/10, Michal Nazarewicz <m.naza...@samsung.com> wrote:

> Date: Monday, June 7, 2010, 5:39 AM


> Added Kconfig options for each
> function used by g_multi so that
> one can customize the gadget to a greater extend.

For what it's worth ... I still NAK all
these complications to what's been intended
to be a simple driver.

If you want to create some complex monstrosity,
that should have been a different driver.

Unfortunately I see that some such patches
have merged despite my previous NAK. Sigh.

David Brownell

unread,
Jun 8, 2010, 10:10:01 AM6/8/10
to

--- On Mon, 6/7/10, Michal Nazarewicz <m.naza...@samsung.com> wrote:

> From: Michal Nazarewicz <m.naza...@samsung.com>
> Subject: [PATCHv4 11/13] USB: gadget: composite: addad disconnect callback
> To: linu...@vger.kernel.org, linu...@vger.kernel.org
> Cc: "David Brownell" <dbro...@users.sourceforge.net>, "Kyungmin Park" <kyungm...@samsung.com>, "Marek Szyprowski" <m.szyp...@samsung.com>, linux-...@vger.kernel.org
> Date: Monday, June 7, 2010, 5:39 AM

> Added a disconnect() callback to
> compasite devices which
> is called by composite glue when its disconnect callback
> is called by gadget.

Acked-by: David Brownell <dbro...@users.sourceforge.net>


... though I don't recall why I didn't add
this originally; I certainly thought about it.

>
> Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
> Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
> ---
> drivers/usb/gadget/composite.c |    2 ++
> include/linux/usb/composite.h  |    2 ++
> 2 files changed, 4 insertions(+), 0 deletions(-)
>

Michał Nazarewicz

unread,
Jun 9, 2010, 5:00:01 AM6/9/10
to
On Tue, 08 Jun 2010 15:13:30 +0200, David Brownell <dav...@pacbell.net> wrote:
>> +; Copyright (c) 2000 Microsoft Corporation
>
> Same comment as with the INF file for g_ether:
>
> If you're giving Microsoft credit for this,
> you should make sure we have the right to
> redistribute the changes ...
>
> To the extent that your patches reduce our
> ability to redistribute these INF files and
> thus use these drivers with MS-Windows ... NAK.
>
> It's my understanding that pulling fragments
> from INF files comes under "fair use" and
> thus copyright does not need to be assigned.
> Microsoft publishes these things with the
> expectation they'll be copied/pasted all over...

So you're saying that removing the copyright will be the way to go?
I kept it since it was not really pulling fragments the INF is the
whole template provided by Microsoft with some minor changes.

As for RNDIS INF file, my understanding is that since Microsoft provides
the template in a publicly available documentation we can assume that we
have the right to redistribute code based on it.

As for CDC ACM INF file, my understanding is similar except the template
is provided by Microchip rather then Microsoft itself.

I thought it's safer to leave the copyright notice and assume we have the
right to modify and redistribute rather then remove it and then be accused
of claiming other's copyright.

All lawyers in the room please rise hands? ;)

--
Best regards, _ _

| Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o
| Computer Science, Michał "mina86" Nazarewicz (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--

Xiaofan Chen

unread,
Jun 9, 2010, 5:30:02 AM6/9/10
to
2010/6/9 Michał Nazarewicz <m.naza...@samsung.com>:

> As for CDC ACM INF file, my understanding is similar except the template
> is provided by Microchip rather then Microsoft itself.
>

Actually Microchip is also copying from Microsoft's template.
I could not find the CDC-ACM inf template from Microsoft
website now but I clearly remember I saw it somewhere.

Other companies does not really put Copyrights on the inf file
for usbser.sys, for example, look at the following file from ST.
http://www.st.com/stonline/books/pdf/docs/12571.pdf (page 5).

Another example (old format).
http://www.lvr.com/files/usbcomport.txt

So it is probably okay to drop the copyright line. On the
other hand, even if there is the copyright line from Microsoft,
I think you can still redistribute it. But I am not a lawyer but
a hardware engineer. ;-)


--
Xiaofan http://mcuee.blogspot.com

Michał Nazarewicz

unread,
Jun 9, 2010, 6:10:02 AM6/9/10
to
> 2010/6/9 Michał Nazarewicz <m.naza...@samsung.com>:
>> As for CDC ACM INF file, my understanding is similar except the template
>> is provided by Microchip rather then Microsoft itself.

On Wed, 09 Jun 2010 11:29:22 +0200, Xiaofan Chen <xiao...@gmail.com> wrote:
> So it is probably okay to drop the copyright line. On the
> other hand, even if there is the copyright line from Microsoft,
> I think you can still redistribute it.

> But I am not a lawyer but a hardware engineer. ;-)

I think we all have the same problem here. ;)

I dunno, obviously I want to make everything according to law to avoid
any problems. Maybe we should contact someone at The Software Freedom
Law Center or some similar entity?

--
Best regards, _ _
| Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o
| Computer Science, Michał "mina86" Nazarewicz (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--

Michał Nazarewicz

unread,
Jun 9, 2010, 6:20:02 AM6/9/10
to
> On Mon, 6/7/10, Michal Nazarewicz <m.naza...@samsung.com> wrote:
>> Added Kconfig options for each function used by g_multi so that
>> one can customize the gadget to a greater extend.

On Tue, 08 Jun 2010 15:37:24 +0200, David Brownell <dav...@pacbell.net> wrote:
> For what it's worth ... I still NAK all
> these complications to what's been intended
> to be a simple driver.

First of, let me assure you that I didn't want to “go behind your back” or
anything.

After your initial NAK I wouldn't bother resending this patch but I wanted
to show the install mode feature and stimulate some, I don't know, discussion
on how you see things go from here. Sorry if I haven't been clear about
my intend.

Also note, that in my opinion all the previous patches in the patchset
should be considered all right in this regard since they don't add
complexity to the g_multi.

> If you want to create some complex monstrosity,
> that should have been a different driver.

So, what would you like to see happen?

As I'm working on various features for USB gadgets at the moment I wanted
to release them as quickly as possible. Also, new ideas arise long after
the original gadget had been created.

Would you prefer I forked g_multi to a g_monstrosity gadget where new
features could be developed and tested?

Or do you think that such an experimental, dynamically changed gadget
has no place in kernel at all? I don't like that idea as I'd like to
share the install mode and maybe other new features with the rest of
the word rather then keeping it on my hard drive.

Also, I think that having a configurable gadget may help others test their
platform and came up with a gadget they'd like to use by simply changing
Kconfig options and testing rather then hacking the file by themselves.

I wanted to reuse g_multi as to not create too many gadgets hence adding
features to g_multi in backward compatible fashion.

I'd like to hear you elaborate an that a little so I'd know what's the
best course of action here and what I should do from here.

--
Best regards, _ _
| Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o
| Computer Science, Michał "mina86" Nazarewicz (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--

Greg KH

unread,
Jun 9, 2010, 11:10:01 AM6/9/10
to
On Wed, Jun 09, 2010 at 12:01:32PM +0200, Michał Nazarewicz wrote:
> > 2010/6/9 Michał Nazarewicz <m.naza...@samsung.com>:
> >> As for CDC ACM INF file, my understanding is similar except the template
> >> is provided by Microchip rather then Microsoft itself.
>
> On Wed, 09 Jun 2010 11:29:22 +0200, Xiaofan Chen <xiao...@gmail.com> wrote:
> > So it is probably okay to drop the copyright line. On the
> > other hand, even if there is the copyright line from Microsoft,
> > I think you can still redistribute it.
>
> > But I am not a lawyer but a hardware engineer. ;-)
>
> I think we all have the same problem here. ;)
>
> I dunno, obviously I want to make everything according to law to avoid
> any problems. Maybe we should contact someone at The Software Freedom
> Law Center or some similar entity?

Ick, no, that's not needed here.

Take the copyright off if this is something that _you_ wrote. If you
copied it from somewhere and modified it, say where you copied it from,
and show the rights that allowed you to copy it.

Where exactly did you get it from originally?

thanks,

greg k-h

Michał Nazarewicz

unread,
Jun 9, 2010, 11:30:02 AM6/9/10
to
>> I dunno, obviously I want to make everything according to law to avoid
>> any problems. Maybe we should contact someone at The Software Freedom
>> Law Center or some similar entity?

On Wed, 09 Jun 2010 16:59:46 +0200, Greg KH <gr...@kroah.com> wrote:
> Ick, no, that's not needed here.

Still I had a chat on IRC with a person who knows copyright law rather
well[1] which pointed me to a few things. ;)


> Take the copyright off if this is something that _you_ wrote. If you
> copied it from somewhere and modified it, say where you copied it from,
> and show the rights that allowed you to copy it.
>
> Where exactly did you get it from originally?

The RNDIS template was taken from:
http://msdn.microsoft.com/en-us/library/ff570620.aspx

The CDC ACM was sent by Xiaofan Chen who said that it is probably
taken indirectly form MSDN as well.


The MSDN TOS reads:
> If Microsoft makes any code marked as “sample” available on this
> Web Site without a License Agreement, then that code is licensed
> to you under the terms of the Microsoft Limited Public License.

Where the MLPL can be found at:
<http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>. It seems like
a perfectly legal free software license except point 3(F):

> (F) Platform Limitation- The licenses granted in sections 2(A) & 2(B)
> extend only to the software or derivative works that you create that
> run on a Microsoft Windows operating system product.

Also, 3(D) requires that the whole license is included:
> (D) If you distribute any portion of the software in source code form,
> you may do so only under this license by including a complete copy of
> this license with your distribution. If you distribute any portion of
> the software in compiled or object code form, you may only do so under
> a license that complies with this license.

Therefore, shall we include the license along with the INFs and ignore
the fact it's not fully free software?

_______________________________________________________________________
[1] I'm deliberately not using the word "lawyer" here not I give the
person's name as to not make an impression that it was a legal
advice or to make him in any way liable. This was *not* a legal
advice.

--
Best regards, _ _
| Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o
| Computer Science, Michał "mina86" Nazarewicz (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--

Greg KH

unread,
Jun 9, 2010, 11:40:03 AM6/9/10
to
On Wed, Jun 09, 2010 at 05:22:58PM +0200, Michał Nazarewicz wrote:
> >>I dunno, obviously I want to make everything according to law to avoid
> >>any problems. Maybe we should contact someone at The Software Freedom
> >>Law Center or some similar entity?
>
> On Wed, 09 Jun 2010 16:59:46 +0200, Greg KH <gr...@kroah.com> wrote:
> >Ick, no, that's not needed here.
>
> Still I had a chat on IRC with a person who knows copyright law rather
> well[1] which pointed me to a few things. ;)
>
>
> >Take the copyright off if this is something that _you_ wrote. If you
> >copied it from somewhere and modified it, say where you copied it from,
> >and show the rights that allowed you to copy it.
> >
> >Where exactly did you get it from originally?
>
> The RNDIS template was taken from:
> http://msdn.microsoft.com/en-us/library/ff570620.aspx
>
> The CDC ACM was sent by Xiaofan Chen who said that it is probably
> taken indirectly form MSDN as well.

Ok, and not from the Windows DDK, right? That has a different license
than MSDN.

> The MSDN TOS reads:
> >If Microsoft makes any code marked as “sample” available on this
> >Web Site without a License Agreement, then that code is licensed
> >to you under the terms of the Microsoft Limited Public License.
>
> Where the MLPL can be found at:
> <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>. It seems like
> a perfectly legal free software license except point 3(F):
>
> >(F) Platform Limitation- The licenses granted in sections 2(A) & 2(B)
> >extend only to the software or derivative works that you create that
> >run on a Microsoft Windows operating system product.
>
> Also, 3(D) requires that the whole license is included:
> >(D) If you distribute any portion of the software in source code form,
> >you may do so only under this license by including a complete copy of
> >this license with your distribution. If you distribute any portion of
> >the software in compiled or object code form, you may only do so under
> >a license that complies with this license.
>
> Therefore, shall we include the license along with the INFs and ignore
> the fact it's not fully free software?

No, it's not "software" here, and it is abiding by the license of the
MLPL as you don't run that file on any non-Windows machine.

How about putting the following on the file:
; based on a example .inf file that was:
; Copyright (c) Microsoft Corporation
; and released under the MLPL as found at
; http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL
; For use only on Windows operating systems.
;

Interesting that they don't put a date on the copyright.

With that wording, I'd be glad to take it.

thanks,

greg k-h

Michał Nazarewicz

unread,
Jun 9, 2010, 12:00:03 PM6/9/10
to
On Wed, 09 Jun 2010 17:33:51 +0200, Greg KH <gr...@kroah.com> wrote:
>> The RNDIS template was taken from:
>> http://msdn.microsoft.com/en-us/library/ff570620.aspx
>>
>> The CDC ACM was sent by Xiaofan Chen who said that it is probably
>> taken indirectly form MSDN as well.
>
> Ok, and not from the Windows DDK, right? That has a different license
> than MSDN.

RNDIS is from MSDN for sure. As of serial, I couldn't find it there.

>> The MSDN TOS reads:
>> >If Microsoft makes any code marked as “sample” available on this
>> >Web Site without a License Agreement, then that code is licensed
>> >to you under the terms of the Microsoft Limited Public License.
>>
>> Where the MLPL can be found at:
>> <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>. It seems like
>> a perfectly legal free software license except point 3(F):
>>
>> >(F) Platform Limitation- The licenses granted in sections 2(A) & 2(B)
>> >extend only to the software or derivative works that you create that
>> >run on a Microsoft Windows operating system product.
>>
>> Also, 3(D) requires that the whole license is included:
>> >(D) If you distribute any portion of the software in source code form,
>> >you may do so only under this license by including a complete copy of
>> >this license with your distribution. If you distribute any portion of
>> >the software in compiled or object code form, you may only do so under
>> >a license that complies with this license.
>>
>> Therefore, shall we include the license along with the INFs and ignore
>> the fact it's not fully free software?

> No, it's not "software" here, and it is abiding by the license of the
> MLPL as you don't run that file on any non-Windows machine.

Well... According to the license (if we assume the license apply to the
INF template) it is "software":
> This license governs use of code marked as “sample” available on this
> Web Site without a License Agreement , as provided under the Section
> above titled “NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE”.
> If you use such code (the “software”), you accept this license.

On Wed, 09 Jun 2010 17:33:51 +0200, Greg KH <gr...@kroah.com> wrote:
> How about putting the following on the file:
> ; based on a example .inf file that was:
> ; Copyright (c) Microsoft Corporation
> ; and released under the MLPL as found at
> ; http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL
> ; For use only on Windows operating systems.
> ;
>
> Interesting that they don't put a date on the copyright.
>
> With that wording, I'd be glad to take it.

If no one sees any legal issues here I can change the patch accordingly.
I'm more and more confused by the whole issue. ;)

--
Best regards, _ _
| Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o
| Computer Science, Michał "mina86" Nazarewicz (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--

Michal Nazarewicz

unread,
Jun 14, 2010, 4:50:01 AM6/14/10
to
This commit cleans the g_fs gadget hopefully making it more
readable. This is achieved by usage of the usb_string_ids_tab()
function for bulk string IDs registration as well as
generalising provided configuration so that a single routine is
used to add each configuration and bind interfaces. As an
effect, the code is shorter and has fewer #ifdefs.

Also, a bug has been fixed where bConfigurationValue were
not affected by what configuration user chose to compile in via
Kconfig option. As an effect, RDNIS and ECM were always number
1 and the "pure" configuration was always number 2.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Requires "USB: gadget: composite: usb_string_ids_*() functions added"
patch to work.

drivers/usb/gadget/Kconfig | 23 +++---
drivers/usb/gadget/g_ffs.c | 174 ++++++++++++--------------------------------
2 files changed, 60 insertions(+), 137 deletions(-)

diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index d5b65d3..d3d0e2d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -750,6 +750,7 @@ config USB_GADGETFS
config USB_FUNCTIONFS
tristate "Function Filesystem (EXPERIMENTAL)"
depends on EXPERIMENTAL
+ select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
help
The Function Filesystem (FunctioFS) lets one create USB
composite functions in user space in the same way as GadgetFS
@@ -758,31 +759,31 @@ config USB_FUNCTIONFS
implemented in kernel space (for instance Ethernet, serial or
mass storage) and other are implemented in user space.

+ If you say "y" or "m" here you will be able what kind of
+ configurations the gadget will provide.
+


Say "y" to link the driver statically, or "m" to build

a dynamically linked module called "g_ffs".

config USB_FUNCTIONFS_ETH
- bool "Include CDC ECM (Ethernet) function"
+ bool "Include configuration with CDC ECM (Ethernet)"
depends on USB_FUNCTIONFS && NET
help
- Include an CDC ECM (Ethernet) funcion in the CDC ECM (Funcion)
- Filesystem. If you also say "y" to the RNDIS query below the
- gadget will have two configurations.
+ Include a configuration with CDC ECM funcion (Ethernet) and the
+ Funcion Filesystem.

config USB_FUNCTIONFS_RNDIS
- bool "Include RNDIS (Ethernet) function"
+ bool "Include configuration with RNDIS (Ethernet)"
depends on USB_FUNCTIONFS && NET
help
- Include an RNDIS (Ethernet) funcion in the Funcion Filesystem.
- If you also say "y" to the CDC ECM query above the gadget will
- have two configurations.
+ Include a configuration with RNDIS funcion (Ethernet) and the Filesystem.

config USB_FUNCTIONFS_GENERIC
bool "Include 'pure' configuration"
- depends on USB_FUNCTIONFS && (USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
+ depends on USB_FUNCTIONFS
help
- Include a configuration with FunctionFS and no Ethernet
- configuration.
+ Include a configuration with the Function Filesystem alone with
+ no Ethernet interface.

config USB_FILE_STORAGE
tristate "File-backed Storage Gadget"
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index da3a9e4..a9474f8 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -32,12 +32,13 @@
# include "u_ether.c"

static u8 gfs_hostaddr[ETH_ALEN];
-#else
-# if !defined CONFIG_USB_FUNCTIONFS_GENERIC
-# define CONFIG_USB_FUNCTIONFS_GENERIC
+# ifdef CONFIG_USB_FUNCTIONFS_ETH
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
# endif
+#else


# define gether_cleanup() do { } while (0)

# define gether_setup(gadget, hostaddr) ((int)0)
+# define gfs_hostaddr NULL
#endif

#include "f_fs.c"
@@ -107,15 +108,7 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = {
enum {
GFS_STRING_MANUFACTURER_IDX,
GFS_STRING_PRODUCT_IDX,
-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
- GFS_STRING_RNDIS_CONFIG_IDX,
-#endif
-#ifdef CONFIG_USB_FUNCTIONFS_ETH
- GFS_STRING_ECM_CONFIG_IDX,
-#endif
-#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
- GFS_STRING_GENERIC_CONFIG_IDX,
-#endif
+ GFS_STRING_FIRST_CONFIG_IDX,
};

static char gfs_manufacturer[50];
@@ -126,13 +119,13 @@ static struct usb_string gfs_strings[] = {
[GFS_STRING_MANUFACTURER_IDX].s = gfs_manufacturer,
[GFS_STRING_PRODUCT_IDX].s = gfs_driver_desc,
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
- [GFS_STRING_RNDIS_CONFIG_IDX].s = "FunctionFS + RNDIS",
+ { .s = "FunctionFS + RNDIS" },
#endif
#ifdef CONFIG_USB_FUNCTIONFS_ETH
- [GFS_STRING_ECM_CONFIG_IDX].s = "FunctionFS + ECM",
+ { .s = "FunctionFS + ECM" },
#endif
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
- [GFS_STRING_GENERIC_CONFIG_IDX].s = "FunctionFS",
+ { .s = "FunctionFS" },


#endif
{ } /* end of list */
};

@@ -146,59 +139,33 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
};


+
+struct gfs_configuration {
+ struct usb_configuration c;
+ int (*eth)(struct usb_configuration *c, u8 *ethaddr);
+} gfs_configurations[] = {
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-static int gfs_do_rndis_config(struct usb_configuration *c);
-
-static struct usb_configuration gfs_rndis_config_driver = {
- .label = "FunctionFS + RNDIS",
- .bind = gfs_do_rndis_config,
- .bConfigurationValue = 1,


- /* .iConfiguration = DYNAMIC */

- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};

-# define gfs_add_rndis_config(cdev) \
- usb_add_config(cdev, &gfs_rndis_config_driver)
-#else
-# define gfs_add_rndis_config(cdev) 0
+ {
+ .eth = rndis_bind_config,
+ },
#endif

-
#ifdef CONFIG_USB_FUNCTIONFS_ETH
-static int gfs_do_ecm_config(struct usb_configuration *c);
-
-static struct usb_configuration gfs_ecm_config_driver = {
- .label = "FunctionFS + ECM",
- .bind = gfs_do_ecm_config,
- .bConfigurationValue = 1,


- /* .iConfiguration = DYNAMIC */

- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};

-# define gfs_add_ecm_config(cdev) \
- usb_add_config(cdev, &gfs_ecm_config_driver)
-#else
-# define gfs_add_ecm_config(cdev) 0
+ {
+ .eth = eth_bind_config,
+ },
#endif

-
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
-static int gfs_do_generic_config(struct usb_configuration *c);
-
-static struct usb_configuration gfs_generic_config_driver = {
- .label = "FunctionFS",
- .bind = gfs_do_generic_config,
- .bConfigurationValue = 2,


- /* .iConfiguration = DYNAMIC */

- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-};

-# define gfs_add_generic_config(cdev) \
- usb_add_config(cdev, &gfs_generic_config_driver)
-#else
-# define gfs_add_generic_config(cdev) 0
+ {
+ },
#endif
+};


static int gfs_bind(struct usb_composite_dev *cdev);
static int gfs_unbind(struct usb_composite_dev *cdev);
+static int gfs_do_config(struct usb_configuration *c);

static struct usb_composite_driver gfs_driver = {
.name = gfs_short_name,
@@ -267,7 +234,7 @@ static int functionfs_check_dev_callback(const char *dev_name)

static int gfs_bind(struct usb_composite_dev *cdev)
{
- int ret;
+ int ret, i;

ENTER();

@@ -284,57 +251,32 @@ static int gfs_bind(struct usb_composite_dev *cdev)
snprintf(gfs_manufacturer, sizeof gfs_manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
cdev->gadget->name);
- ret = usb_string_id(cdev);
- if (unlikely(ret < 0))
- goto error;
- gfs_strings[GFS_STRING_MANUFACTURER_IDX].id = ret;
- gfs_dev_desc.iManufacturer = ret;
-
- ret = usb_string_id(cdev);
- if (unlikely(ret < 0))
- goto error;
- gfs_strings[GFS_STRING_PRODUCT_IDX].id = ret;
- gfs_dev_desc.iProduct = ret;
-
-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
- ret = usb_string_id(cdev);
- if (unlikely(ret < 0))
- goto error;
- gfs_strings[GFS_STRING_RNDIS_CONFIG_IDX].id = ret;
- gfs_rndis_config_driver.iConfiguration = ret;
-#endif

-#ifdef CONFIG_USB_FUNCTIONFS_ETH
- ret = usb_string_id(cdev);
+ ret = usb_string_ids_tab(cdev, gfs_strings);
if (unlikely(ret < 0))
goto error;
- gfs_strings[GFS_STRING_ECM_CONFIG_IDX].id = ret;
- gfs_ecm_config_driver.iConfiguration = ret;
-#endif

-#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
- ret = usb_string_id(cdev);
- if (unlikely(ret < 0))
- goto error;
- gfs_strings[GFS_STRING_GENERIC_CONFIG_IDX].id = ret;
- gfs_generic_config_driver.iConfiguration = ret;
-#endif
+ gfs_dev_desc.iManufacturer = gfs_strings[GFS_STRING_MANUFACTURER_IDX].id;
+ gfs_dev_desc.iProduct = gfs_strings[GFS_STRING_PRODUCT_IDX].id;

ret = functionfs_bind(gfs_ffs_data, cdev);
if (unlikely(ret < 0))
goto error;

- ret = gfs_add_rndis_config(cdev);
- if (unlikely(ret < 0))
- goto error_unbind;
+ for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
+ struct gfs_configuration *c = gfs_configurations + i;

- ret = gfs_add_ecm_config(cdev);
- if (unlikely(ret < 0))
- goto error_unbind;
+ ret = GFS_STRING_FIRST_CONFIG_IDX + i;
+ c->c.label = gfs_strings[ret].s;
+ c->c.iConfiguration = gfs_strings[ret].id;
+ c->c.bind = gfs_do_config;
+ c->c.bConfigurationValue = 1 + i;
+ c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER;

- ret = gfs_add_generic_config(cdev);
- if (unlikely(ret < 0))
- goto error_unbind;
+ ret = usb_add_config(cdev, &c->c);
+ if (unlikely(ret < 0))
+ goto error_unbind;
+ }

return 0;

@@ -368,10 +310,10 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
}


-static int __gfs_do_config(struct usb_configuration *c,
- int (*eth)(struct usb_configuration *c, u8 *ethaddr),
- u8 *ethaddr)
+static int gfs_do_config(struct usb_configuration *c)
{
+ struct gfs_configuration *gc =
+ container_of(c, struct gfs_configuration, c);
int ret;

if (WARN_ON(!gfs_ffs_data))
@@ -382,8 +324,8 @@ static int __gfs_do_config(struct usb_configuration *c,
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}

- if (eth) {
- ret = eth(c, ethaddr);
+ if (gc->eth) {
+ ret = gc->eth(c, gfs_hostaddr);


if (unlikely(ret < 0))
return ret;
}

@@ -406,32 +348,12 @@ static int __gfs_do_config(struct usb_configuration *c,
return 0;
}

-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-static int gfs_do_rndis_config(struct usb_configuration *c)
-{
- ENTER();
-
- return __gfs_do_config(c, rndis_bind_config, gfs_hostaddr);
-}
-#endif

#ifdef CONFIG_USB_FUNCTIONFS_ETH
-static int gfs_do_ecm_config(struct usb_configuration *c)
-{
- ENTER();
-
- return __gfs_do_config(c,
- can_support_ecm(c->cdev->gadget)
- ? ecm_bind_config : geth_bind_config,
- gfs_hostaddr);
-}
-#endif
-
-#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
-static int gfs_do_generic_config(struct usb_configuration *c)
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
{
- ENTER();
-
- return __gfs_do_config(c, NULL, NULL);
+ return can_support_ecm(c->cdev->gadget)
+ ? ecm_bind_config(c, ethaddr)
+ : geth_bind_config(c, ethaddr);
}
#endif

Michal Nazarewicz

unread,
Jun 14, 2010, 4:50:02 AM6/14/10
to
Added pre_eject() and post_eject() callbacks which are
called befor and after removable logical unit is ejected.
The first can prevent logical unit from being ejected.

This commit also changes the way callbacks are passed to
the function from gadget. A fsg_operations structure has
been created which lists all callbacks -- this is passed
to the fsg_config.

This is important because it changes the way thread_exits()
callback is passed.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

Compared to previous patch version fixed the fsg_operations object
having automatic instead of static storage.

drivers/usb/gadget/f_mass_storage.c | 109 ++++++++++++++++++++++------------
drivers/usb/gadget/mass_storage.c | 5 +-
2 files changed, 74 insertions(+), 40 deletions(-)

index 2b11e20..306098f 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -143,6 +143,9 @@ static int msg_thread_exits(struct fsg_common *common)



static int __init msg_do_config(struct usb_configuration *c)

{
+ static const struct fsg_operations ops = {

+ .thread_exits = msg_thread_exits,
+ };

static struct fsg_common common;

struct fsg_common *retp;
@@ -155,7 +158,7 @@ static int __init msg_do_config(struct usb_configuration *c)


}

fsg_config_from_params(&config, &mod_data);
- config.thread_exits = msg_thread_exits;

+ config.ops = &ops;

Michal Nazarewicz

unread,
Jun 14, 2010, 4:50:03 AM6/14/10
to
Updated the INF file for the g_ether gadegt. It should work with most
recent Windows systems now. The file hase been also renamed to
linux-rndis.inf rather then linux.inf.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

On Wed, 09 Jun 2010 17:33:51 +0200, Greg KH <gr...@kroah.com> wrote:
> How about putting the following on the file:
> ; based on a example .inf file that was:
> ; Copyright (c) Microsoft Corporation
> ; and released under the MLPL as found at
> ; http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL
> ; For use only on Windows operating systems.
> ;

As requested only with a little bit different wording.

Still, I am not sure what to do with the serial INF.
I cannot even find the original file Xiaofan posted
not mentioning any associated license. I mean, I would
leave it as is without changes but dunno...

Documentation/usb/linux-rndis.inf | 72 +++++++++++++
Documentation/usb/linux.inf | 200 -------------------------------------
2 files changed, 72 insertions(+), 200 deletions(-)
create mode 100644 Documentation/usb/linux-rndis.inf
delete mode 100644 Documentation/usb/linux.inf

diff --git a/Documentation/usb/linux-rndis.inf b/Documentation/usb/linux-rndis.inf
new file mode 100644
index 0000000..31e58fa
--- /dev/null
+++ b/Documentation/usb/linux-rndis.inf
@@ -0,0 +1,72 @@
+
+; Hacked together by Michal Nazarewicz <min...@mina86.com>
+; with Xiaofan Chen's <xiao...@gmail.com> help.
+
+; Based on template INF file found at
+; <http://msdn.microsoft.com/en-us/library/ff570620.aspx>
+; which was


+; Copyright (c) Microsoft Corporation

+; and released under the MLPL as found at:
+; <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>.
+; For use only on Windows operating systems.
+
+[Version]
+Signature = "$Windows NT$"
+Class = Net
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %Linux%
+DriverVer = 06/21/2006,6.0.6000.16384
+;CatalogFile = device.cat
+
+[Manufacturer]
+%Linux% = RndisDevices,NTx86,NTamd64,NTia64
+
+; Decoration for x86 architecture
+[RndisDevices.NTx86]
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
+
+; Decoration for x64 architecture
+[RndisDevices.NTamd64]
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
+
+; Decoration for ia64 architecture
+[RndisDevices.NTia64]
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
+
+;@@@ This is the common setting for setup
+[ControlFlags]
+ExcludeFromSelect=*
+
+; DDInstall section
+; References the in-build Netrndis.inf
+[RNDIS.NT.5.1]
+Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
+BusType = 15
+; NEVER REMOVE THE FOLLOWING REFERENCE FOR NETRNDIS.INF
+include = netrndis.inf
+needs = Usb_Rndis.ndi
+AddReg = Rndis_AddReg_Vista
+
+; DDInstal.Services section
+[RNDIS.NT.5.1.Services]
+include = netrndis.inf
+needs = Usb_Rndis.ndi.Services
+
+; Optional registry settings. You can modify as needed.
+[RNDIS_AddReg_Vista]
+HKR, NDI\params\VistaProperty, ParamDesc, 0, %Vista_Property%
+HKR, NDI\params\VistaProperty, type, 0, "edit"
+HKR, NDI\params\VistaProperty, LimitText, 0, "12"
+HKR, NDI\params\VistaProperty, UpperCase, 0, "1"
+HKR, NDI\params\VistaProperty, default, 0, " "
+HKR, NDI\params\VistaProperty, optional, 0, "1"
+
+; No sys copyfiles - the sys files are already in-build
+; (part of the operating system).
+; We do not support XP SP1-, 2003 SP1-, ME, 9x.
+
+; Modify these strings for your device as needed.


+[Strings]
+Linux = "Linux Developer Community"

+RndisDevice = "Ethernet/RNDIS Gadget"
+Vista_Property = "Optional Vista Property"
diff --git a/Documentation/usb/linux.inf b/Documentation/usb/linux.inf
deleted file mode 100644
index 2f7217d..0000000
--- a/Documentation/usb/linux.inf
+++ /dev/null
@@ -1,200 +0,0 @@
-; MS-Windows driver config matching some basic modes of the
-; Linux-USB Ethernet/RNDIS gadget firmware:
-;
-; - RNDIS plus CDC Ethernet ... this may be familiar as a DOCSIS
-; cable modem profile, and supports most non-Microsoft USB hosts
-;
-; - RNDIS plus CDC Subset ... used by hardware that incapable of
-; full CDC Ethernet support.
-;
-; Microsoft only directly supports RNDIS drivers, and bundled them into XP.
-; The Microsoft "Remote NDIS USB Driver Kit" is currently found at:
-; http://www.microsoft.com/whdc/hwdev/resources/HWservices/rndis.mspx
-
-
-[Version]
-Signature = "$CHICAGO$"
-Class = Net
-ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
-Provider = %Linux%
-Compatible = 1
-MillenniumPreferred = .ME
-DriverVer = 03/30/2004,0.0.0.0
-; catalog file would be used by WHQL
-;CatalogFile = Linux.cat
-
-[Manufacturer]
-%Linux% = LinuxDevices,NT.5.1
-
-[LinuxDevices]
-; NetChip IDs, used by both firmware modes
-%LinuxDevice% = RNDIS, USB\VID_0525&PID_a4a2
-
-[LinuxDevices.NT.5.1]
-%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
-
-[ControlFlags]
-ExcludeFromSelect=*
-
-; Windows 98, Windows 98 Second Edition specific sections --------
-
-[RNDIS]
-DeviceID = usb8023
-MaxInstance = 512
-DriverVer = 03/30/2004,0.0.0.0
-AddReg = RNDIS_AddReg_98, RNDIS_AddReg_Common
-
-[RNDIS_AddReg_98]
-HKR, , DevLoader, 0, *ndis
-HKR, , DeviceVxDs, 0, usb8023.sys
-HKR, NDIS, LogDriverName, 0, "usb8023"
-HKR, NDIS, MajorNdisVersion, 1, 5
-HKR, NDIS, MinorNdisVersion, 1, 0
-HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5"
-HKR, Ndi\Interfaces, DefLower, 0, "ethernet"
-HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5"
-HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
-HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_98"
-HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_98"
-HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_98"
-HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4a2"
-
-[RNDIS_Install_98]
-CopyFiles=RNDIS_CopyFiles_98
-
-[RNDIS_CopyFiles_98]
-usb8023.sys, usb8023w.sys, , 0
-rndismp.sys, rndismpw.sys, , 0
-
-; Windows Millennium Edition specific sections --------------------
-
-[RNDIS.ME]
-DeviceID = usb8023
-MaxInstance = 512
-DriverVer = 03/30/2004,0.0.0.0
-AddReg = RNDIS_AddReg_ME, RNDIS_AddReg_Common
-Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
-BusType = 15
-
-[RNDIS_AddReg_ME]
-HKR, , DevLoader, 0, *ndis
-HKR, , DeviceVxDs, 0, usb8023.sys
-HKR, NDIS, LogDriverName, 0, "usb8023"
-HKR, NDIS, MajorNdisVersion, 1, 5
-HKR, NDIS, MinorNdisVersion, 1, 0
-HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5"
-HKR, Ndi\Interfaces, DefLower, 0, "ethernet"
-HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5"
-HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
-HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_ME"
-HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_ME"
-HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_ME"
-HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4a2"
-
-[RNDIS_Install_ME]
-CopyFiles=RNDIS_CopyFiles_ME
-
-[RNDIS_CopyFiles_ME]
-usb8023.sys, usb8023m.sys, , 0
-rndismp.sys, rndismpm.sys, , 0
-
-; Windows 2000 specific sections ---------------------------------
-
-[RNDIS.NT]
-Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
-BusType = 15
-DriverVer = 03/30/2004,0.0.0.0
-AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common
-CopyFiles = RNDIS_CopyFiles_NT
-
-[RNDIS.NT.Services]
-AddService = USB_RNDIS, 2, RNDIS_ServiceInst_NT, RNDIS_EventLog
-
-[RNDIS_CopyFiles_NT]
-; no rename of files on Windows 2000, use the 'k' names as is
-usb8023k.sys, , , 0
-rndismpk.sys, , , 0
-
-[RNDIS_ServiceInst_NT]
-DisplayName = %ServiceDisplayName%
-ServiceType = 1
-StartType = 3
-ErrorControl = 1
-ServiceBinary = %12%\usb8023k.sys
-LoadOrderGroup = NDIS
-AddReg = RNDIS_WMI_AddReg_NT
-
-[RNDIS_WMI_AddReg_NT]
-HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismpk.sys"
-
-; Windows XP specific sections -----------------------------------
-
-[RNDIS.NT.5.1]
-Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
-BusType = 15
-DriverVer = 03/30/2004,0.0.0.0
-AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common
-; no copyfiles - the files are already in place
-
-[RNDIS.NT.5.1.Services]
-AddService = USB_RNDIS, 2, RNDIS_ServiceInst_51, RNDIS_EventLog
-
-[RNDIS_ServiceInst_51]
-DisplayName = %ServiceDisplayName%
-ServiceType = 1
-StartType = 3
-ErrorControl = 1
-ServiceBinary = %12%\usb8023.sys
-LoadOrderGroup = NDIS
-AddReg = RNDIS_WMI_AddReg_51
-
-[RNDIS_WMI_AddReg_51]
-HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismp.sys"
-
-; Windows 2000 and Windows XP common sections --------------------
-
-[RNDIS_AddReg_NT]
-HKR, Ndi, Service, 0, "USB_RNDIS"
-HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
-HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
-
-[RNDIS_EventLog]
-AddReg = RNDIS_EventLog_AddReg
-
-[RNDIS_EventLog_AddReg]
-HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll"
-HKR, , TypesSupported, 0x00010001, 7
-
-; Common Sections -------------------------------------------------
-
-[RNDIS_AddReg_Common]
-HKR, NDI\params\NetworkAddress, ParamDesc, 0, %NetworkAddress%
-HKR, NDI\params\NetworkAddress, type, 0, "edit"
-HKR, NDI\params\NetworkAddress, LimitText, 0, "12"
-HKR, NDI\params\NetworkAddress, UpperCase, 0, "1"
-HKR, NDI\params\NetworkAddress, default, 0, " "
-HKR, NDI\params\NetworkAddress, optional, 0, "1"
-
-[SourceDisksNames]
-1=%SourceDisk%,,1
-
-[SourceDisksFiles]
-usb8023m.sys=1
-rndismpm.sys=1
-usb8023w.sys=1
-rndismpw.sys=1
-usb8023k.sys=1
-rndismpk.sys=1
-
-[DestinationDirs]
-RNDIS_CopyFiles_98 = 10, system32/drivers
-RNDIS_CopyFiles_ME = 10, system32/drivers
-RNDIS_CopyFiles_NT = 12
-
-[Strings]
-ServiceDisplayName = "USB Remote NDIS Network Device Driver"
-NetworkAddress = "Network Address"
-Linux = "Linux Developer Community"
-LinuxDevice = "Linux USB Ethernet/RNDIS Gadget"
-SourceDisk = "Ethernet/RNDIS Gadget Driver Install Disk"
-

Xiaofan Chen

unread,
Jun 14, 2010, 7:40:02 AM6/14/10
to
On Mon, Jun 14, 2010 at 4:43 PM, Michal Nazarewicz
<m.naza...@samsung.com> wrote:
> Updated the INF file for the g_ether gadget.  It should work with most
> recent Windows systems now.  The file has been also renamed to

> linux-rndis.inf rather then linux.inf.
>
> Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>
> Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
> ---
> On Wed, 09 Jun 2010 17:33:51 +0200, Greg KH <gr...@kroah.com> wrote:
>> How about putting the following on the file:
>>       ; based on a example .inf file that was:
>>       ;       Copyright (c) Microsoft Corporation
>>       ; and released under the MLPL as found at
>>       ; http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL
>>       ; For use only on Windows operating systems.
>>       ;
>
> As requested only with a little bit different wording.
>
> Still, I am not sure what to do with the serial INF.
> I cannot even find the original file Xiaofan posted
> not mentioning any associated license.  I mean, I would
> leave it as is without changes but dunno...

I think all the INF file templates ultimately comes
from DDK/WDK.

For example, the RNDIS template is from here. And the title
says WDK.
http://msdn.microsoft.com/en-us/library/ff570620%28VS.85%29.aspx

For the CDC-ACM INF, the original template may well be from an ancient
DDK. Anyway, here are some places to infer the CDC-ACM
INF file.
http://support.microsoft.com/kb/837637/en-us (important for Vista/Win7)
http://msdn.microsoft.com/en-us/library/ff542605%28VS.85%29.aspx
(same as above).
http://msdn.microsoft.com/en-us/library/ff543241.aspx (for 2000/XP)
http://msdn.microsoft.com/en-us/library/ff542491%28v=VS.85%29.aspx
http://msdn.microsoft.com/en-us/library/ff542559.aspx

Worse come worse, you might contact Microsoft about the license.
The Microsoft Driver News group has a lot of experts including
Microsoft employees who are very helpful.
microsoft.public.development.device.drivers


--
Xiaofan http://mcuee.blogspot.com

David Brownell

unread,
Jun 14, 2010, 3:50:03 PM6/14/10
to
The updated copyright note
Looks OK to me ... (Though it seems wrong to
reference so many folk yet omit the original
author (me)

However, I don't see a version
of the patch with the cleaner copyright notice.

Also, please don't rename the file without
updating all the references to the original
name. Since thoses refs are in docs all over
the web ... I think it's best to just
not rename it.

Michał Nazarewicz

unread,
Jun 14, 2010, 4:10:02 PM6/14/10
to
On Mon, 14 Jun 2010 21:42:46 +0200, David Brownell <dav...@pacbell.net> wrote:

> The updated copyright note
> Looks OK to me ... (Though it seems wrong to
> reference so many folk yet omit the original
> author (me)

Uh... I basically took what Xiaofan provided and changed IDs and that's why.
But true enough, as I think about it now, I took some parts from the original
linux.inf file so there's probably *at* *least* as much your work as mine in
there.

I'll add you in the next version. Or should I remove the notices all
together? Personally I feel they serve two purposes: give credit and let
others know who might be a good person to ask question. I'm fine either
way...

> However, I don't see a version
> of the patch with the cleaner copyright notice.
>
> Also, please don't rename the file without
> updating all the references to the original
> name. Since thoses refs are in docs all over
> the web ... I think it's best to just
> not rename it.

Ah, haven't thought about that. I grepped Documentation/ but forgot
about grepping my personal copy of the Internet I keep in my basement. ;)

I intended a consistent naming and that's why the rename. In any way,
I'll get the old name in the next version of the patch.

--
Best regards, _ _
| Humble Liege of Serenely Enlightened Majesty of o' \,=./ `o
| Computer Science, Michał "mina86" Nazarewicz (o o)
+----[mina86*mina86.com]---[mina86*jabber.org]----ooO--(_)--Ooo--

Michal Nazarewicz

unread,
Jun 16, 2010, 10:50:01 AM6/16/10
to
Updated the INF file for the g_ether gadegt. It should work with most
recent Windows systems now.

Signed-off-by: Michal Nazarewicz <m.naza...@samsung.com>


Signed-off-by: Kyungmin Park <kyungm...@samsung.com>
---

On Wed, 16 Jun 2010 16:12:38 +0200, David Brownell <dav...@pacbell.net> wrote:
> NAK ... still waiting for a version of the
> patch with all requested changes. In
> particular, without the rename (which
> invalidates most documentation, though
> it would otherwise be a reasonable cleanup).

Argh... Sorry about that. The patch was updated per your suggestion.
I only forgot about the commit message...

As such, this is identical to the previous expect the last sentence of
the commit is removed.

Documentation/usb/linux.inf | 236 ++++++++++---------------------------------
1 files changed, 52 insertions(+), 184 deletions(-)

diff --git a/Documentation/usb/linux.inf b/Documentation/usb/linux.inf
index 2f7217d..3bed2e9 100644
--- a/Documentation/usb/linux.inf
+++ b/Documentation/usb/linux.inf
@@ -1,200 +1,68 @@


-; MS-Windows driver config matching some basic modes of the
-; Linux-USB Ethernet/RNDIS gadget firmware:
-;
-; - RNDIS plus CDC Ethernet ... this may be familiar as a DOCSIS
-; cable modem profile, and supports most non-Microsoft USB hosts
-;
-; - RNDIS plus CDC Subset ... used by hardware that incapable of
-; full CDC Ethernet support.
-;
-; Microsoft only directly supports RNDIS drivers, and bundled them into XP.
-; The Microsoft "Remote NDIS USB Driver Kit" is currently found at:
-; http://www.microsoft.com/whdc/hwdev/resources/HWservices/rndis.mspx
-

+; Based on template INF file found at
+; <http://msdn.microsoft.com/en-us/library/ff570620.aspx>
+; which was:
+; Copyright (c) Microsoft Corporation
+; and released under the MLPL as found at:
+; <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>.

+; For use only on Windows operating systems.

[Version]
-Signature = "$CHICAGO$"
+Signature = "$Windows NT$"
Class = Net
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}


Provider = %Linux%
-Compatible = 1
-MillenniumPreferred = .ME
-DriverVer = 03/30/2004,0.0.0.0
-; catalog file would be used by WHQL
-;CatalogFile = Linux.cat

+DriverVer = 06/21/2006,6.0.6000.16384
+;CatalogFile = device.cat

[Manufacturer]
-%Linux% = LinuxDevices,NT.5.1


+%Linux% = RndisDevices,NTx86,NTamd64,NTia64
+
+; Decoration for x86 architecture
+[RndisDevices.NTx86]
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2

-[LinuxDevices]
-; NetChip IDs, used by both firmware modes
-%LinuxDevice% = RNDIS, USB\VID_0525&PID_a4a2

+; Decoration for x64 architecture
+[RndisDevices.NTamd64]
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2

-[LinuxDevices.NT.5.1]
-%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2

+; Decoration for ia64 architecture
+[RndisDevices.NTia64]
+%RndisDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2

+;@@@ This is the common setting for setup

[ControlFlags]
ExcludeFromSelect=*

+; DDInstall section
+; References the in-build Netrndis.inf

[RNDIS.NT.5.1]
-Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
-BusType = 15
-DriverVer = 03/30/2004,0.0.0.0
-AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common
-; no copyfiles - the files are already in place
-

+Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
+BusType = 15
+; NEVER REMOVE THE FOLLOWING REFERENCE FOR NETRNDIS.INF
+include = netrndis.inf
+needs = Usb_Rndis.ndi
+AddReg = Rndis_AddReg_Vista
+
+; DDInstal.Services section

+include = netrndis.inf
+needs = Usb_Rndis.ndi.Services
+
+; Optional registry settings. You can modify as needed.
+[RNDIS_AddReg_Vista]
+HKR, NDI\params\VistaProperty, ParamDesc, 0, %Vista_Property%
+HKR, NDI\params\VistaProperty, type, 0, "edit"
+HKR, NDI\params\VistaProperty, LimitText, 0, "12"
+HKR, NDI\params\VistaProperty, UpperCase, 0, "1"
+HKR, NDI\params\VistaProperty, default, 0, " "
+HKR, NDI\params\VistaProperty, optional, 0, "1"
+
+; No sys copyfiles - the sys files are already in-build
+; (part of the operating system).
+; We do not support XP SP1-, 2003 SP1-, ME, 9x.
+
+; Modify these strings for your device as needed.

[Strings]
-ServiceDisplayName = "USB Remote NDIS Network Device Driver"
-NetworkAddress = "Network Address"
-Linux = "Linux Developer Community"
-LinuxDevice = "Linux USB Ethernet/RNDIS Gadget"
-SourceDisk = "Ethernet/RNDIS Gadget Driver Install Disk"
-

+Linux = "Linux Developer Community"
+RndisDevice = "Ethernet/RNDIS Gadget"
+Vista_Property = "Optional Vista Property"

--
1.7.1

0 new messages