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