1fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf/*
2fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * acm_ms.c -- Composite driver, with ACM and mass storage support
3fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf *
4fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * Copyright (C) 2008 David Brownell
5fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * Copyright (C) 2008 Nokia Corporation
6fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * Author: David Brownell
7fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * Modified: Klaus Schwarzkopf <schwarzkopf@sensortherm.de>
8fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf *
9fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * Heavily based on multi.c and cdc2.c
10fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf *
11fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * This program is free software; you can redistribute it and/or modify
12fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * it under the terms of the GNU General Public License as published by
13fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * the Free Software Foundation; either version 2 of the License, or
14fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * (at your option) any later version.
15fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf */
16fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
17fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf#include <linux/kernel.h>
18721e2e91945bc2520d57d795dfe1b502ecec567cSebastian Andrzej Siewior#include <linux/module.h>
19fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
20fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf#include "u_serial.h"
21fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
22fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf#define DRIVER_DESC		"Composite Gadget (ACM + MS)"
23fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf#define DRIVER_VERSION		"2011/10/10"
24fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
25fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf/*-------------------------------------------------------------------------*/
26fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
27fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf/*
28fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
29fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * Instead:  allocate your own, using normal USB-IF procedures.
30fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf */
31fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf#define ACM_MS_VENDOR_NUM	0x1d6b	/* Linux Foundation */
32fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf#define ACM_MS_PRODUCT_NUM	0x0106	/* Composite Gadget: ACM + MS*/
33fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
34e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz#include "f_mass_storage.h"
35fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
36fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf/*-------------------------------------------------------------------------*/
377d16e8d3eb704f5f6eb5a271d5758b495634e8e6Sebastian Andrzej SiewiorUSB_GADGET_COMPOSITE_OPTIONS();
38fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
39fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic struct usb_device_descriptor device_desc = {
40fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bLength =		sizeof device_desc,
41fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bDescriptorType =	USB_DT_DEVICE,
42fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
43fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bcdUSB =		cpu_to_le16(0x0200),
44fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
45fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bDeviceClass =		USB_CLASS_MISC /* 0xEF */,
46fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bDeviceSubClass =	2,
47fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bDeviceProtocol =	1,
48fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
49fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/* .bMaxPacketSize0 = f(hardware) */
50fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
51fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/* Vendor and product id can be overridden by module parameters.  */
52fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.idVendor =		cpu_to_le16(ACM_MS_VENDOR_NUM),
53fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.idProduct =		cpu_to_le16(ACM_MS_PRODUCT_NUM),
54fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/* .bcdDevice = f(hardware) */
55fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/* .iManufacturer = DYNAMIC */
56fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/* .iProduct = DYNAMIC */
57fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/* NO SERIAL NUMBER */
58fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/*.bNumConfigurations =	DYNAMIC*/
59fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf};
60fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
61fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic struct usb_otg_descriptor otg_descriptor = {
62fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bLength =		sizeof otg_descriptor,
63fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bDescriptorType =	USB_DT_OTG,
64fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
65fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/*
66fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	 * REVISIT SRP-only hardware is possible, although
67fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	 * it would not be called "OTG" ...
68fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	 */
69fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
70fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf};
71fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
72fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic const struct usb_descriptor_header *otg_desc[] = {
73fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	(struct usb_descriptor_header *) &otg_descriptor,
74fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	NULL,
75fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf};
76fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
77fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf/* string IDs are assigned dynamically */
78fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic struct usb_string strings_dev[] = {
79cc2683c318a5bf192b75cd5c343b51009db0cf6cSebastian Andrzej Siewior	[USB_GADGET_MANUFACTURER_IDX].s = "",
80276e2e4f1f3e07a0ad891bf757dbcfd655ff5f91Sebastian Andrzej Siewior	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
81276e2e4f1f3e07a0ad891bf757dbcfd655ff5f91Sebastian Andrzej Siewior	[USB_GADGET_SERIAL_IDX].s = "",
82fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	{  } /* end of list */
83fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf};
84fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
85fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic struct usb_gadget_strings stringtab_dev = {
86fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.language	= 0x0409,	/* en-us */
87fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.strings	= strings_dev,
88fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf};
89fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
90fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic struct usb_gadget_strings *dev_strings[] = {
91fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	&stringtab_dev,
92fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	NULL,
93fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf};
94fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
95fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf/****************************** Configurations ******************************/
96fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
97fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
986fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz#ifdef CONFIG_USB_GADGET_DEBUG_FILES
996fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz
1006fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewiczstatic unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
1016fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz
1026fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz#else
1036fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz
1046fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz/*
1056fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz * Number of buffers we will use.
1066fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz * 2 is usually enough for good buffering pipeline
1076fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz */
1086fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
1096fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz
1100c8b1992b4a180704a887b3c9128aa103b5ef60fGreg Kroah-Hartman#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
1116fdc5dd25e0cd5afc114fe65427150c65f0eb67bAndrzej Pietrasiewicz
112fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus SchwarzkopfFSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
113fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
114fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf/*-------------------------------------------------------------------------*/
1155f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewiorstatic struct usb_function *f_acm;
1165f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewiorstatic struct usb_function_instance *f_acm_inst;
117e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
118e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczstatic struct usb_function_instance *fi_msg;
119e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczstatic struct usb_function *f_msg;
120e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
121fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf/*
122fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf * We _always_ have both ACM and mass storage functions.
123fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf */
124fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic int __init acm_ms_do_config(struct usb_configuration *c)
125fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf{
126e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	struct fsg_opts *opts;
127fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	int	status;
128fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
129fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	if (gadget_is_otg(c->cdev->gadget)) {
130fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf		c->descriptors = otg_desc;
131fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
132fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	}
133fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
134e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	opts = fsg_opts_from_func_inst(fi_msg);
1355f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewior
1365f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewior	f_acm = usb_get_function(f_acm_inst);
137e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (IS_ERR(f_acm))
138e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		return PTR_ERR(f_acm);
139e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
140e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	f_msg = usb_get_function(fi_msg);
141e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (IS_ERR(f_msg)) {
142e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		status = PTR_ERR(f_msg);
143e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto put_acm;
1445f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewior	}
145fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
1465f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewior	status = usb_add_function(c, f_acm);
147fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	if (status < 0)
148e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto put_msg;
149fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
150e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	status = fsg_common_run_thread(opts->common);
151e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (status)
152e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto remove_acm;
153e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
154e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	status = usb_add_function(c, f_msg);
155e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (status)
156e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto remove_acm;
157fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
158fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	return 0;
159e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczremove_acm:
1605f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewior	usb_remove_function(c, f_acm);
161e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczput_msg:
162e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	usb_put_function(f_msg);
163e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczput_acm:
1645f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewior	usb_put_function(f_acm);
1655f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewior	return status;
166fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf}
167fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
168fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic struct usb_configuration acm_ms_config_driver = {
169fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.label			= DRIVER_DESC,
170fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bConfigurationValue	= 1,
171fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/* .iConfiguration = DYNAMIC */
172fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
173fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf};
174fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
175fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf/*-------------------------------------------------------------------------*/
176fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
177fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic int __init acm_ms_bind(struct usb_composite_dev *cdev)
178fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf{
179fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	struct usb_gadget	*gadget = cdev->gadget;
180e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	struct fsg_opts		*opts;
181e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	struct fsg_config	config;
182fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	int			status;
183fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
184e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	f_acm_inst = usb_get_function_instance("acm");
185e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (IS_ERR(f_acm_inst))
186e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		return PTR_ERR(f_acm_inst);
187e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
188e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	fi_msg = usb_get_function_instance("mass_storage");
189e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (IS_ERR(fi_msg)) {
190e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		status = PTR_ERR(fi_msg);
191e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto fail_get_msg;
192fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	}
193fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
194e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	/* set up mass storage function */
195e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers);
196e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	opts = fsg_opts_from_func_inst(fi_msg);
197e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
198e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	opts->no_configfs = true;
199e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers);
200e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (status)
201e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto fail;
202e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
203e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	status = fsg_common_set_nluns(opts->common, config.nluns);
204e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (status)
205e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto fail_set_nluns;
206e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
207e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
208e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (status)
209e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto fail_set_cdev;
210e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
211e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	fsg_common_set_sysfs(opts->common, true);
212e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	status = fsg_common_create_luns(opts->common, &config);
213e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	if (status)
214e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto fail_set_cdev;
215e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz
216e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	fsg_common_set_inquiry_string(opts->common, config.vendor_name,
217e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz				      config.product_name);
218fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/*
219fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	 * Allocate string descriptor numbers ... note that string
220fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	 * contents can be overridden by the composite_dev glue.
221fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	 */
222e1f15ccbae40b55a4e2591373ea5f1808cf29855Sebastian Andrzej Siewior	status = usb_string_ids_tab(cdev, strings_dev);
223fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	if (status < 0)
224e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto fail_string_ids;
225276e2e4f1f3e07a0ad891bf757dbcfd655ff5f91Sebastian Andrzej Siewior	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
226276e2e4f1f3e07a0ad891bf757dbcfd655ff5f91Sebastian Andrzej Siewior	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
227fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
228fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/* register our configuration */
229fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
230fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	if (status < 0)
231e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz		goto fail_string_ids;
232fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
2337d16e8d3eb704f5f6eb5a271d5758b495634e8e6Sebastian Andrzej Siewior	usb_composite_overwrite_options(cdev, &coverwrite);
234fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
235fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf			DRIVER_DESC);
236fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	return 0;
237fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
238fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	/* error recovery */
239e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczfail_string_ids:
240e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	fsg_common_remove_luns(opts->common);
241e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczfail_set_cdev:
242e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	fsg_common_free_luns(opts->common);
243e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczfail_set_nluns:
244e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	fsg_common_free_buffers(opts->common);
245e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczfail:
246e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	usb_put_function_instance(fi_msg);
247e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewiczfail_get_msg:
248e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	usb_put_function_instance(f_acm_inst);
249fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	return status;
250fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf}
251fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
252fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopfstatic int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
253fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf{
254e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	usb_put_function(f_msg);
255e6c661ef18177f2f1ce32210140f8497851d9388Andrzej Pietrasiewicz	usb_put_function_instance(fi_msg);
2565f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewior	usb_put_function(f_acm);
2575f72bbfd9f427565c85e71a63d47b3448e79a466Sebastian Andrzej Siewior	usb_put_function_instance(f_acm_inst);
258fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	return 0;
259fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf}
260fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
261c2ec75c25112c9e0d9053f55ba8cf0a358d4a354Sebastian Andrzej Siewiorstatic __refdata struct usb_composite_driver acm_ms_driver = {
262fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.name		= "g_acm_ms",
263fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.dev		= &device_desc,
2646f47209b271661ecd5929397cbe646ff247f01b6Steve Bennett	.max_speed	= USB_SPEED_SUPER,
265fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.strings	= dev_strings,
26603e42bd5937c4c24e411690ab165627e93c258b5Sebastian Andrzej Siewior	.bind		= acm_ms_bind,
267fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf	.unbind		= __exit_p(acm_ms_unbind),
268fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf};
269fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus Schwarzkopf
270909346a819c5b81420d861bd53abd1140b26104eTobias Klausermodule_usb_composite_driver(acm_ms_driver);
271909346a819c5b81420d861bd53abd1140b26104eTobias Klauser
272fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus SchwarzkopfMODULE_DESCRIPTION(DRIVER_DESC);
273fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus SchwarzkopfMODULE_AUTHOR("Klaus Schwarzkopf <schwarzkopf@sensortherm.de>");
274fa3ae0c158c70e6cf227b3a194659ee7fed8c588Klaus SchwarzkopfMODULE_LICENSE("GPL v2");
275