Commit | Line | Data |
---|---|---|
c52661d6 SAS |
1 | /* Target based USB-Gadget |
2 | * | |
3 | * UAS protocol handling, target callbacks, configfs handling, | |
4 | * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling. | |
5 | * | |
6 | * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de> | |
7 | * License: GPLv2 as published by FSF. | |
8 | */ | |
9 | #include <linux/kernel.h> | |
10 | #include <linux/module.h> | |
11 | #include <linux/types.h> | |
12 | #include <linux/string.h> | |
13 | #include <linux/configfs.h> | |
14 | #include <linux/ctype.h> | |
15 | #include <linux/usb/ch9.h> | |
16 | #include <linux/usb/composite.h> | |
17 | #include <linux/usb/gadget.h> | |
18 | #include <linux/usb/storage.h> | |
c52661d6 SAS |
19 | #include <scsi/scsi_tcq.h> |
20 | #include <target/target_core_base.h> | |
21 | #include <target/target_core_fabric.h> | |
c52661d6 SAS |
22 | #include <asm/unaligned.h> |
23 | ||
00240714 | 24 | #include "u_tcm.h" |
c52661d6 | 25 | |
7d16e8d3 SAS |
26 | USB_GADGET_COMPOSITE_OPTIONS(); |
27 | ||
c52661d6 SAS |
28 | #define UAS_VENDOR_ID 0x0525 /* NetChip */ |
29 | #define UAS_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ | |
30 | ||
31 | static struct usb_device_descriptor usbg_device_desc = { | |
32 | .bLength = sizeof(usbg_device_desc), | |
33 | .bDescriptorType = USB_DT_DEVICE, | |
0aecfc1b | 34 | /* .bcdUSB = DYNAMIC */ |
c52661d6 SAS |
35 | .bDeviceClass = USB_CLASS_PER_INTERFACE, |
36 | .idVendor = cpu_to_le16(UAS_VENDOR_ID), | |
37 | .idProduct = cpu_to_le16(UAS_PRODUCT_ID), | |
c52661d6 SAS |
38 | .bNumConfigurations = 1, |
39 | }; | |
40 | ||
c3978ed3 AP |
41 | #define USB_G_STR_CONFIG USB_GADGET_FIRST_AVAIL_IDX |
42 | ||
c52661d6 | 43 | static struct usb_string usbg_us_strings[] = { |
276e2e4f SAS |
44 | [USB_GADGET_MANUFACTURER_IDX].s = "Target Manufactor", |
45 | [USB_GADGET_PRODUCT_IDX].s = "Target Product", | |
46 | [USB_GADGET_SERIAL_IDX].s = "000000000001", | |
18786da4 | 47 | [USB_G_STR_CONFIG].s = "default config", |
c52661d6 SAS |
48 | { }, |
49 | }; | |
50 | ||
51 | static struct usb_gadget_strings usbg_stringtab = { | |
52 | .language = 0x0409, | |
53 | .strings = usbg_us_strings, | |
54 | }; | |
55 | ||
56 | static struct usb_gadget_strings *usbg_strings[] = { | |
57 | &usbg_stringtab, | |
58 | NULL, | |
59 | }; | |
60 | ||
00240714 AP |
61 | static struct usb_function_instance *fi_tcm; |
62 | static struct usb_function *f_tcm; | |
c52661d6 | 63 | |
c52661d6 | 64 | static int guas_unbind(struct usb_composite_dev *cdev) |
c52661d6 | 65 | { |
00240714 AP |
66 | if (!IS_ERR_OR_NULL(f_tcm)) |
67 | usb_put_function(f_tcm); | |
10287bae | 68 | |
c52661d6 | 69 | return 0; |
c52661d6 SAS |
70 | } |
71 | ||
00240714 | 72 | static int tcm_do_config(struct usb_configuration *c) |
c52661d6 | 73 | { |
00240714 | 74 | int status; |
c52661d6 | 75 | |
00240714 AP |
76 | f_tcm = usb_get_function(fi_tcm); |
77 | if (IS_ERR(f_tcm)) | |
78 | return PTR_ERR(f_tcm); | |
c52661d6 | 79 | |
00240714 AP |
80 | status = usb_add_function(c, f_tcm); |
81 | if (status < 0) { | |
82 | usb_put_function(f_tcm); | |
83 | return status; | |
c52661d6 | 84 | } |
c52661d6 | 85 | |
c52661d6 | 86 | return 0; |
c52661d6 SAS |
87 | } |
88 | ||
c52661d6 SAS |
89 | static struct usb_configuration usbg_config_driver = { |
90 | .label = "Linux Target", | |
91 | .bConfigurationValue = 1, | |
c52661d6 SAS |
92 | .bmAttributes = USB_CONFIG_ATT_SELFPOWER, |
93 | }; | |
c52661d6 | 94 | |
00240714 AP |
95 | static int usbg_attach(struct usb_function_instance *f); |
96 | static void usbg_detach(struct usb_function_instance *f); | |
c52661d6 SAS |
97 | |
98 | static int usb_target_bind(struct usb_composite_dev *cdev) | |
99 | { | |
100 | int ret; | |
101 | ||
18786da4 SAS |
102 | ret = usb_string_ids_tab(cdev, usbg_us_strings); |
103 | if (ret) | |
104 | return ret; | |
105 | ||
106 | usbg_device_desc.iManufacturer = | |
276e2e4f SAS |
107 | usbg_us_strings[USB_GADGET_MANUFACTURER_IDX].id; |
108 | usbg_device_desc.iProduct = usbg_us_strings[USB_GADGET_PRODUCT_IDX].id; | |
109 | usbg_device_desc.iSerialNumber = | |
110 | usbg_us_strings[USB_GADGET_SERIAL_IDX].id; | |
18786da4 SAS |
111 | usbg_config_driver.iConfiguration = |
112 | usbg_us_strings[USB_G_STR_CONFIG].id; | |
113 | ||
00240714 | 114 | ret = usb_add_config(cdev, &usbg_config_driver, tcm_do_config); |
7d16e8d3 SAS |
115 | if (ret) |
116 | return ret; | |
117 | usb_composite_overwrite_options(cdev, &coverwrite); | |
c52661d6 SAS |
118 | return 0; |
119 | } | |
120 | ||
c94e289f | 121 | static struct usb_composite_driver usbg_driver = { |
c52661d6 SAS |
122 | .name = "g_target", |
123 | .dev = &usbg_device_desc, | |
124 | .strings = usbg_strings, | |
125 | .max_speed = USB_SPEED_SUPER, | |
03e42bd5 | 126 | .bind = usb_target_bind, |
c52661d6 SAS |
127 | .unbind = guas_unbind, |
128 | }; | |
129 | ||
00240714 | 130 | static int usbg_attach(struct usb_function_instance *f) |
c52661d6 | 131 | { |
03e42bd5 | 132 | return usb_composite_probe(&usbg_driver); |
c52661d6 SAS |
133 | } |
134 | ||
00240714 | 135 | static void usbg_detach(struct usb_function_instance *f) |
c52661d6 SAS |
136 | { |
137 | usb_composite_unregister(&usbg_driver); | |
138 | } | |
139 | ||
140 | static int __init usb_target_gadget_init(void) | |
141 | { | |
00240714 AP |
142 | struct f_tcm_opts *tcm_opts; |
143 | ||
144 | fi_tcm = usb_get_function_instance("tcm"); | |
145 | if (IS_ERR(fi_tcm)) | |
146 | return PTR_ERR(fi_tcm); | |
147 | ||
148 | tcm_opts = container_of(fi_tcm, struct f_tcm_opts, func_inst); | |
149 | mutex_lock(&tcm_opts->dep_lock); | |
150 | tcm_opts->tcm_register_callback = usbg_attach; | |
151 | tcm_opts->tcm_unregister_callback = usbg_detach; | |
152 | tcm_opts->dependent = THIS_MODULE; | |
153 | tcm_opts->can_attach = true; | |
154 | tcm_opts->has_dep = true; | |
155 | mutex_unlock(&tcm_opts->dep_lock); | |
156 | ||
157 | fi_tcm->set_inst_name(fi_tcm, "tcm-legacy"); | |
158 | ||
159 | return 0; | |
c52661d6 SAS |
160 | } |
161 | module_init(usb_target_gadget_init); | |
162 | ||
163 | static void __exit usb_target_gadget_exit(void) | |
164 | { | |
00240714 AP |
165 | if (!IS_ERR_OR_NULL(fi_tcm)) |
166 | usb_put_function_instance(fi_tcm); | |
167 | ||
c52661d6 SAS |
168 | } |
169 | module_exit(usb_target_gadget_exit); | |
170 | ||
171 | MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>"); | |
172 | MODULE_DESCRIPTION("usb-gadget fabric"); | |
173 | MODULE_LICENSE("GPL v2"); |