xref: /OK3568_Linux_fs/kernel/drivers/usb/gadget/legacy/mass_storage.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * mass_storage.c -- Mass Storage USB Gadget
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2003-2008 Alan Stern
6*4882a593Smuzhiyun  * Copyright (C) 2009 Samsung Electronics
7*4882a593Smuzhiyun  *                    Author: Michal Nazarewicz <mina86@mina86.com>
8*4882a593Smuzhiyun  * All rights reserved.
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun /*
13*4882a593Smuzhiyun  * The Mass Storage Gadget acts as a USB Mass Storage device,
14*4882a593Smuzhiyun  * appearing to the host as a disk drive or as a CD-ROM drive.  In
15*4882a593Smuzhiyun  * addition to providing an example of a genuinely useful gadget
16*4882a593Smuzhiyun  * driver for a USB device, it also illustrates a technique of
17*4882a593Smuzhiyun  * double-buffering for increased throughput.  Last but not least, it
18*4882a593Smuzhiyun  * gives an easy way to probe the behavior of the Mass Storage drivers
19*4882a593Smuzhiyun  * in a USB host.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * Since this file serves only administrative purposes and all the
22*4882a593Smuzhiyun  * business logic is implemented in f_mass_storage.* file.  Read
23*4882a593Smuzhiyun  * comments in this file for more detailed description.
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include <linux/kernel.h>
28*4882a593Smuzhiyun #include <linux/usb/ch9.h>
29*4882a593Smuzhiyun #include <linux/module.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define DRIVER_DESC		"Mass Storage Gadget"
34*4882a593Smuzhiyun #define DRIVER_VERSION		"2009/09/11"
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /*
37*4882a593Smuzhiyun  * Thanks to NetChip Technologies for donating this product ID.
38*4882a593Smuzhiyun  *
39*4882a593Smuzhiyun  * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
40*4882a593Smuzhiyun  * Instead:  allocate your own, using normal USB-IF procedures.
41*4882a593Smuzhiyun  */
42*4882a593Smuzhiyun #define FSG_VENDOR_ID	0x0525	/* NetChip */
43*4882a593Smuzhiyun #define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #include "f_mass_storage.h"
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
48*4882a593Smuzhiyun USB_GADGET_COMPOSITE_OPTIONS();
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun static struct usb_device_descriptor msg_device_desc = {
51*4882a593Smuzhiyun 	.bLength =		sizeof msg_device_desc,
52*4882a593Smuzhiyun 	.bDescriptorType =	USB_DT_DEVICE,
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	/* .bcdUSB = DYNAMIC */
55*4882a593Smuzhiyun 	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	/* Vendor and product id can be overridden by module parameters.  */
58*4882a593Smuzhiyun 	.idVendor =		cpu_to_le16(FSG_VENDOR_ID),
59*4882a593Smuzhiyun 	.idProduct =		cpu_to_le16(FSG_PRODUCT_ID),
60*4882a593Smuzhiyun 	.bNumConfigurations =	1,
61*4882a593Smuzhiyun };
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun static const struct usb_descriptor_header *otg_desc[2];
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun static struct usb_string strings_dev[] = {
66*4882a593Smuzhiyun 	[USB_GADGET_MANUFACTURER_IDX].s = "",
67*4882a593Smuzhiyun 	[USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
68*4882a593Smuzhiyun 	[USB_GADGET_SERIAL_IDX].s = "",
69*4882a593Smuzhiyun 	{  } /* end of list */
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun static struct usb_gadget_strings stringtab_dev = {
73*4882a593Smuzhiyun 	.language       = 0x0409,       /* en-us */
74*4882a593Smuzhiyun 	.strings        = strings_dev,
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun static struct usb_gadget_strings *dev_strings[] = {
78*4882a593Smuzhiyun 	&stringtab_dev,
79*4882a593Smuzhiyun 	NULL,
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun static struct usb_function_instance *fi_msg;
83*4882a593Smuzhiyun static struct usb_function *f_msg;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /****************************** Configurations ******************************/
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun static struct fsg_module_parameters mod_data = {
88*4882a593Smuzhiyun 	.stall = 1
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun #ifdef CONFIG_USB_GADGET_DEBUG_FILES
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun #else
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun /*
97*4882a593Smuzhiyun  * Number of buffers we will use.
98*4882a593Smuzhiyun  * 2 is usually enough for good buffering pipeline
99*4882a593Smuzhiyun  */
100*4882a593Smuzhiyun #define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun #endif /* CONFIG_USB_GADGET_DEBUG_FILES */
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
105*4882a593Smuzhiyun 
msg_do_config(struct usb_configuration * c)106*4882a593Smuzhiyun static int msg_do_config(struct usb_configuration *c)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	int ret;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	if (gadget_is_otg(c->cdev->gadget)) {
111*4882a593Smuzhiyun 		c->descriptors = otg_desc;
112*4882a593Smuzhiyun 		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	f_msg = usb_get_function(fi_msg);
116*4882a593Smuzhiyun 	if (IS_ERR(f_msg))
117*4882a593Smuzhiyun 		return PTR_ERR(f_msg);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	ret = usb_add_function(c, f_msg);
120*4882a593Smuzhiyun 	if (ret)
121*4882a593Smuzhiyun 		goto put_func;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	return 0;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun put_func:
126*4882a593Smuzhiyun 	usb_put_function(f_msg);
127*4882a593Smuzhiyun 	return ret;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun static struct usb_configuration msg_config_driver = {
131*4882a593Smuzhiyun 	.label			= "Linux File-Backed Storage",
132*4882a593Smuzhiyun 	.bConfigurationValue	= 1,
133*4882a593Smuzhiyun 	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
134*4882a593Smuzhiyun };
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun /****************************** Gadget Bind ******************************/
138*4882a593Smuzhiyun 
msg_bind(struct usb_composite_dev * cdev)139*4882a593Smuzhiyun static int msg_bind(struct usb_composite_dev *cdev)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	struct fsg_opts *opts;
142*4882a593Smuzhiyun 	struct fsg_config config;
143*4882a593Smuzhiyun 	int status;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	fi_msg = usb_get_function_instance("mass_storage");
146*4882a593Smuzhiyun 	if (IS_ERR(fi_msg))
147*4882a593Smuzhiyun 		return PTR_ERR(fi_msg);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	fsg_config_from_params(&config, &mod_data, fsg_num_buffers);
150*4882a593Smuzhiyun 	opts = fsg_opts_from_func_inst(fi_msg);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	opts->no_configfs = true;
153*4882a593Smuzhiyun 	status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers);
154*4882a593Smuzhiyun 	if (status)
155*4882a593Smuzhiyun 		goto fail;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
158*4882a593Smuzhiyun 	if (status)
159*4882a593Smuzhiyun 		goto fail_set_cdev;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	fsg_common_set_sysfs(opts->common, true);
162*4882a593Smuzhiyun 	status = fsg_common_create_luns(opts->common, &config);
163*4882a593Smuzhiyun 	if (status)
164*4882a593Smuzhiyun 		goto fail_set_cdev;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	fsg_common_set_inquiry_string(opts->common, config.vendor_name,
167*4882a593Smuzhiyun 				      config.product_name);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	status = usb_string_ids_tab(cdev, strings_dev);
170*4882a593Smuzhiyun 	if (status < 0)
171*4882a593Smuzhiyun 		goto fail_string_ids;
172*4882a593Smuzhiyun 	msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) {
175*4882a593Smuzhiyun 		struct usb_descriptor_header *usb_desc;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 		usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
178*4882a593Smuzhiyun 		if (!usb_desc)
179*4882a593Smuzhiyun 			goto fail_string_ids;
180*4882a593Smuzhiyun 		usb_otg_descriptor_init(cdev->gadget, usb_desc);
181*4882a593Smuzhiyun 		otg_desc[0] = usb_desc;
182*4882a593Smuzhiyun 		otg_desc[1] = NULL;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	status = usb_add_config(cdev, &msg_config_driver, msg_do_config);
186*4882a593Smuzhiyun 	if (status < 0)
187*4882a593Smuzhiyun 		goto fail_otg_desc;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	usb_composite_overwrite_options(cdev, &coverwrite);
190*4882a593Smuzhiyun 	dev_info(&cdev->gadget->dev,
191*4882a593Smuzhiyun 		 DRIVER_DESC ", version: " DRIVER_VERSION "\n");
192*4882a593Smuzhiyun 	return 0;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun fail_otg_desc:
195*4882a593Smuzhiyun 	kfree(otg_desc[0]);
196*4882a593Smuzhiyun 	otg_desc[0] = NULL;
197*4882a593Smuzhiyun fail_string_ids:
198*4882a593Smuzhiyun 	fsg_common_remove_luns(opts->common);
199*4882a593Smuzhiyun fail_set_cdev:
200*4882a593Smuzhiyun 	fsg_common_free_buffers(opts->common);
201*4882a593Smuzhiyun fail:
202*4882a593Smuzhiyun 	usb_put_function_instance(fi_msg);
203*4882a593Smuzhiyun 	return status;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun 
msg_unbind(struct usb_composite_dev * cdev)206*4882a593Smuzhiyun static int msg_unbind(struct usb_composite_dev *cdev)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun 	if (!IS_ERR(f_msg))
209*4882a593Smuzhiyun 		usb_put_function(f_msg);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	if (!IS_ERR(fi_msg))
212*4882a593Smuzhiyun 		usb_put_function_instance(fi_msg);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	kfree(otg_desc[0]);
215*4882a593Smuzhiyun 	otg_desc[0] = NULL;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun /****************************** Some noise ******************************/
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun static struct usb_composite_driver msg_driver = {
223*4882a593Smuzhiyun 	.name		= "g_mass_storage",
224*4882a593Smuzhiyun 	.dev		= &msg_device_desc,
225*4882a593Smuzhiyun 	.max_speed	= USB_SPEED_SUPER_PLUS,
226*4882a593Smuzhiyun 	.needs_serial	= 1,
227*4882a593Smuzhiyun 	.strings	= dev_strings,
228*4882a593Smuzhiyun 	.bind		= msg_bind,
229*4882a593Smuzhiyun 	.unbind		= msg_unbind,
230*4882a593Smuzhiyun };
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun module_usb_composite_driver(msg_driver);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
235*4882a593Smuzhiyun MODULE_AUTHOR("Michal Nazarewicz");
236*4882a593Smuzhiyun MODULE_LICENSE("GPL");
237