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