diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
commit | 2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch) | |
tree | 848558de17fb3008cdf4d861b01ac7781903ce39 /drivers/usb/gadget/legacy/mass_storage.c | |
parent | Initial commit. (diff) | |
download | linux-upstream.tar.xz linux-upstream.zip |
Adding upstream version 6.1.76.upstream/6.1.76upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/usb/gadget/legacy/mass_storage.c')
-rw-r--r-- | drivers/usb/gadget/legacy/mass_storage.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c new file mode 100644 index 000000000..ac1741126 --- /dev/null +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * mass_storage.c -- Mass Storage USB Gadget + * + * Copyright (C) 2003-2008 Alan Stern + * Copyright (C) 2009 Samsung Electronics + * Author: Michal Nazarewicz <mina86@mina86.com> + * All rights reserved. + */ + + +/* + * The Mass Storage Gadget acts as a USB Mass Storage device, + * appearing to the host as a disk drive or as a CD-ROM drive. In + * addition to providing an example of a genuinely useful gadget + * driver for a USB device, it also illustrates a technique of + * double-buffering for increased throughput. Last but not least, it + * gives an easy way to probe the behavior of the Mass Storage drivers + * in a USB host. + * + * Since this file serves only administrative purposes and all the + * business logic is implemented in f_mass_storage.* file. Read + * comments in this file for more detailed description. + */ + + +#include <linux/kernel.h> +#include <linux/usb/ch9.h> +#include <linux/module.h> + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_DESC "Mass Storage Gadget" +#define DRIVER_VERSION "2009/09/11" + +/* + * Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ +#define FSG_VENDOR_ID 0x0525 /* NetChip */ +#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ + +#include "f_mass_storage.h" + +/*-------------------------------------------------------------------------*/ +USB_GADGET_COMPOSITE_OPTIONS(); + +static struct usb_device_descriptor msg_device_desc = { + .bLength = sizeof msg_device_desc, + .bDescriptorType = USB_DT_DEVICE, + + /* .bcdUSB = DYNAMIC */ + .bDeviceClass = USB_CLASS_PER_INTERFACE, + + /* Vendor and product id can be overridden by module parameters. */ + .idVendor = cpu_to_le16(FSG_VENDOR_ID), + .idProduct = cpu_to_le16(FSG_PRODUCT_ID), + .bNumConfigurations = 1, +}; + +static const struct usb_descriptor_header *otg_desc[2]; + +static struct usb_string strings_dev[] = { + [USB_GADGET_MANUFACTURER_IDX].s = "", + [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s = "", + { } /* 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, + NULL, +}; + +static struct usb_function_instance *fi_msg; +static struct usb_function *f_msg; + +/****************************** Configurations ******************************/ + +static struct fsg_module_parameters mod_data = { + .stall = 1 +}; +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ + +FSG_MODULE_PARAMETERS(/* no prefix */, mod_data); + +static int msg_do_config(struct usb_configuration *c) +{ + int ret; + + if (gadget_is_otg(c->cdev->gadget)) { + c->descriptors = otg_desc; + c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + + f_msg = usb_get_function(fi_msg); + if (IS_ERR(f_msg)) + return PTR_ERR(f_msg); + + ret = usb_add_function(c, f_msg); + if (ret) + goto put_func; + + return 0; + +put_func: + usb_put_function(f_msg); + return ret; +} + +static struct usb_configuration msg_config_driver = { + .label = "Linux File-Backed Storage", + .bConfigurationValue = 1, + .bmAttributes = USB_CONFIG_ATT_SELFPOWER, +}; + + +/****************************** Gadget Bind ******************************/ + +static int msg_bind(struct usb_composite_dev *cdev) +{ + struct fsg_opts *opts; + struct fsg_config config; + int status; + + fi_msg = usb_get_function_instance("mass_storage"); + if (IS_ERR(fi_msg)) + return PTR_ERR(fi_msg); + + fsg_config_from_params(&config, &mod_data, fsg_num_buffers); + opts = fsg_opts_from_func_inst(fi_msg); + + opts->no_configfs = true; + status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers); + if (status) + goto fail; + + status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); + if (status) + goto fail_set_cdev; + + fsg_common_set_sysfs(opts->common, true); + status = fsg_common_create_luns(opts->common, &config); + if (status) + goto fail_set_cdev; + + fsg_common_set_inquiry_string(opts->common, config.vendor_name, + config.product_name); + + status = usb_string_ids_tab(cdev, strings_dev); + if (status < 0) + goto fail_string_ids; + msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + + if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) { + status = -ENOMEM; + goto fail_string_ids; + } + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + + status = usb_add_config(cdev, &msg_config_driver, msg_do_config); + if (status < 0) + goto fail_otg_desc; + + usb_composite_overwrite_options(cdev, &coverwrite); + dev_info(&cdev->gadget->dev, + DRIVER_DESC ", version: " DRIVER_VERSION "\n"); + return 0; + +fail_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; +fail_string_ids: + fsg_common_remove_luns(opts->common); +fail_set_cdev: + fsg_common_free_buffers(opts->common); +fail: + usb_put_function_instance(fi_msg); + return status; +} + +static int msg_unbind(struct usb_composite_dev *cdev) +{ + if (!IS_ERR(f_msg)) + usb_put_function(f_msg); + + if (!IS_ERR(fi_msg)) + usb_put_function_instance(fi_msg); + + kfree(otg_desc[0]); + otg_desc[0] = NULL; + + return 0; +} + +/****************************** Some noise ******************************/ + +static struct usb_composite_driver msg_driver = { + .name = "g_mass_storage", + .dev = &msg_device_desc, + .max_speed = USB_SPEED_SUPER_PLUS, + .needs_serial = 1, + .strings = dev_strings, + .bind = msg_bind, + .unbind = msg_unbind, +}; + +module_usb_composite_driver(msg_driver); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Michal Nazarewicz"); +MODULE_LICENSE("GPL"); |