xref: /freebsd/sys/dev/usb/template/usb_template_midi.c (revision dd41de95a84d979615a2ef11df6850622bf6184e)
1 /* $FreeBSD$ */
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4  *
5  * Copyright (c) 2015 Hans Petter Selasky
6  * Copyright (c) 2018 The FreeBSD Foundation
7  * All rights reserved.
8  *
9  * Portions of this software were developed by Edward Tomasz Napierala
10  * under sponsorship from the FreeBSD Foundation.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*
35  * This file contains the USB template for an USB MIDI Device.
36  */
37 
38 #ifdef USB_GLOBAL_INCLUDE_FILE
39 #include USB_GLOBAL_INCLUDE_FILE
40 #else
41 #include <sys/stdint.h>
42 #include <sys/stddef.h>
43 #include <sys/param.h>
44 #include <sys/queue.h>
45 #include <sys/types.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/bus.h>
49 #include <sys/module.h>
50 #include <sys/lock.h>
51 #include <sys/mutex.h>
52 #include <sys/condvar.h>
53 #include <sys/sysctl.h>
54 #include <sys/sx.h>
55 #include <sys/unistd.h>
56 #include <sys/callout.h>
57 #include <sys/malloc.h>
58 #include <sys/priv.h>
59 
60 #include <dev/usb/usb.h>
61 #include <dev/usb/usbdi.h>
62 #include <dev/usb/usb_core.h>
63 #include <dev/usb/usb_ioctl.h>
64 #include <dev/usb/usb_util.h>
65 
66 #include <dev/usb/template/usb_template.h>
67 #endif					/* USB_GLOBAL_INCLUDE_FILE */
68 
69 enum {
70 	MIDI_LANG_INDEX,
71 	MIDI_INTERFACE_INDEX,
72 	MIDI_MANUFACTURER_INDEX,
73 	MIDI_PRODUCT_INDEX,
74 	MIDI_SERIAL_NUMBER_INDEX,
75 	MIDI_MAX_INDEX,
76 };
77 
78 #define	MIDI_DEFAULT_VENDOR_ID		USB_TEMPLATE_VENDOR
79 #define	MIDI_DEFAULT_PRODUCT_ID		0x27de
80 #define	MIDI_DEFAULT_INTERFACE		"MIDI interface"
81 #define	MIDI_DEFAULT_MANUFACTURER	USB_TEMPLATE_MANUFACTURER
82 #define	MIDI_DEFAULT_PRODUCT		"MIDI Test Device"
83 #define	MIDI_DEFAULT_SERIAL_NUMBER	"March 2008"
84 
85 static struct usb_string_descriptor	midi_interface;
86 static struct usb_string_descriptor	midi_manufacturer;
87 static struct usb_string_descriptor	midi_product;
88 static struct usb_string_descriptor	midi_serial_number;
89 
90 static struct sysctl_ctx_list		midi_ctx_list;
91 
92 /* prototypes */
93 
94 static const uint8_t midi_desc_raw_0[9] = {
95 	0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01
96 };
97 
98 static const void *midi_descs_0[] = {
99 	&midi_desc_raw_0,
100 	NULL
101 };
102 
103 static const struct usb_temp_interface_desc midi_iface_0 = {
104 	.ppEndpoints = NULL,		/* no endpoints */
105 	.ppRawDesc = midi_descs_0,
106 	.bInterfaceClass = UICLASS_AUDIO,
107 	.bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
108 	.bInterfaceProtocol = 0,
109 	.iInterface = MIDI_INTERFACE_INDEX,
110 };
111 
112 static const struct usb_temp_packet_size midi_mps = {
113 	.mps[USB_SPEED_LOW] = 8,
114 	.mps[USB_SPEED_FULL] = 64,
115 	.mps[USB_SPEED_HIGH] = 512,
116 };
117 
118 static const uint8_t midi_desc_raw_7[5] = {
119 	0x05, 0x25, 0x01, 0x01, 0x01
120 };
121 
122 static const void *midi_descs_2[] = {
123 	&midi_desc_raw_7,
124 	NULL
125 };
126 
127 static const struct usb_temp_endpoint_desc midi_bulk_out_ep = {
128 	.ppRawDesc = midi_descs_2,
129 	.pPacketSize = &midi_mps,
130 	.bEndpointAddress = UE_DIR_OUT,
131 	.bmAttributes = UE_BULK,
132 };
133 
134 static const uint8_t midi_desc_raw_6[5] = {
135 	0x05, 0x25, 0x01, 0x01, 0x03,
136 };
137 
138 static const void *midi_descs_3[] = {
139 	&midi_desc_raw_6,
140 	NULL
141 };
142 
143 static const struct usb_temp_endpoint_desc midi_bulk_in_ep = {
144 	.ppRawDesc = midi_descs_3,
145 	.pPacketSize = &midi_mps,
146 	.bEndpointAddress = UE_DIR_IN,
147 	.bmAttributes = UE_BULK,
148 };
149 
150 static const struct usb_temp_endpoint_desc *midi_iface_1_ep[] = {
151 	&midi_bulk_out_ep,
152 	&midi_bulk_in_ep,
153 	NULL,
154 };
155 
156 static const uint8_t midi_desc_raw_1[7] = {
157 	0x07, 0x24, 0x01, 0x00, 0x01, /* wTotalLength: */ 0x41, 0x00
158 };
159 
160 static const uint8_t midi_desc_raw_2[6] = {
161 	0x06, 0x24, 0x02, 0x01, 0x01, 0x00
162 };
163 
164 static const uint8_t midi_desc_raw_3[6] = {
165 	0x06, 0x24, 0x02, 0x02, 0x02, 0x00
166 };
167 
168 static const uint8_t midi_desc_raw_4[9] = {
169 	0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00
170 };
171 
172 static const uint8_t midi_desc_raw_5[9] = {
173 	0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00
174 };
175 
176 static const void *midi_descs_1[] = {
177 	&midi_desc_raw_1,
178 	&midi_desc_raw_2,
179 	&midi_desc_raw_3,
180 	&midi_desc_raw_4,
181 	&midi_desc_raw_5,
182 	NULL
183 };
184 
185 static const struct usb_temp_interface_desc midi_iface_1 = {
186 	.ppRawDesc = midi_descs_1,
187 	.ppEndpoints = midi_iface_1_ep,
188 	.bInterfaceClass = UICLASS_AUDIO,
189 	.bInterfaceSubClass = UISUBCLASS_MIDISTREAM,
190 	.bInterfaceProtocol = 0,
191 	.iInterface = MIDI_INTERFACE_INDEX,
192 };
193 
194 static const struct usb_temp_interface_desc *midi_interfaces[] = {
195 	&midi_iface_0,
196 	&midi_iface_1,
197 	NULL,
198 };
199 
200 static const struct usb_temp_config_desc midi_config_desc = {
201 	.ppIfaceDesc = midi_interfaces,
202 	.bmAttributes = 0,
203 	.bMaxPower = 0,
204 	.iConfiguration = MIDI_PRODUCT_INDEX,
205 };
206 
207 static const struct usb_temp_config_desc *midi_configs[] = {
208 	&midi_config_desc,
209 	NULL,
210 };
211 
212 static usb_temp_get_string_desc_t midi_get_string_desc;
213 
214 struct usb_temp_device_desc usb_template_midi = {
215 	.getStringDesc = &midi_get_string_desc,
216 	.ppConfigDesc = midi_configs,
217 	.idVendor = MIDI_DEFAULT_VENDOR_ID,
218 	.idProduct = MIDI_DEFAULT_PRODUCT_ID,
219 	.bcdDevice = 0x0100,
220 	.bDeviceClass = 0,
221 	.bDeviceSubClass = 0,
222 	.bDeviceProtocol = 0,
223 	.iManufacturer = MIDI_MANUFACTURER_INDEX,
224 	.iProduct = MIDI_PRODUCT_INDEX,
225 	.iSerialNumber = MIDI_SERIAL_NUMBER_INDEX,
226 };
227 
228 /*------------------------------------------------------------------------*
229  *	midi_get_string_desc
230  *
231  * Return values:
232  * NULL: Failure. No such string.
233  * Else: Success. Pointer to string descriptor is returned.
234  *------------------------------------------------------------------------*/
235 static const void *
236 midi_get_string_desc(uint16_t lang_id, uint8_t string_index)
237 {
238 	static const void *ptr[MIDI_MAX_INDEX] = {
239 		[MIDI_LANG_INDEX] = &usb_string_lang_en,
240 		[MIDI_INTERFACE_INDEX] = &midi_interface,
241 		[MIDI_MANUFACTURER_INDEX] = &midi_manufacturer,
242 		[MIDI_PRODUCT_INDEX] = &midi_product,
243 		[MIDI_SERIAL_NUMBER_INDEX] = &midi_serial_number,
244 	};
245 
246 	if (string_index == 0) {
247 		return (&usb_string_lang_en);
248 	}
249 	if (lang_id != 0x0409) {
250 		return (NULL);
251 	}
252 	if (string_index < MIDI_MAX_INDEX) {
253 		return (ptr[string_index]);
254 	}
255 	return (NULL);
256 }
257 
258 static void
259 midi_init(void *arg __unused)
260 {
261 	struct sysctl_oid *parent;
262 	char parent_name[3];
263 
264 	usb_make_str_desc(&midi_interface, sizeof(midi_interface),
265 	    MIDI_DEFAULT_INTERFACE);
266 	usb_make_str_desc(&midi_manufacturer, sizeof(midi_manufacturer),
267 	    MIDI_DEFAULT_MANUFACTURER);
268 	usb_make_str_desc(&midi_product, sizeof(midi_product),
269 	    MIDI_DEFAULT_PRODUCT);
270 	usb_make_str_desc(&midi_serial_number, sizeof(midi_serial_number),
271 	    MIDI_DEFAULT_SERIAL_NUMBER);
272 
273 	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MIDI);
274 	sysctl_ctx_init(&midi_ctx_list);
275 
276 	parent = SYSCTL_ADD_NODE(&midi_ctx_list,
277 	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
278 	    parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE,
279 	    0, "USB MIDI device side template");
280 	SYSCTL_ADD_U16(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
281 	    "vendor_id", CTLFLAG_RWTUN,
282 	    &usb_template_midi.idVendor, 1, "Vendor identifier");
283 	SYSCTL_ADD_U16(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
284 	    "product_id", CTLFLAG_RWTUN,
285 	    &usb_template_midi.idProduct, 1, "Product identifier");
286 #if 0
287 	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
288 	    "interface", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
289 	    &midi_interface, sizeof(midi_interface), usb_temp_sysctl,
290 	    "A", "Interface string");
291 #endif
292 	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
293 	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
294 	    &midi_manufacturer, sizeof(midi_manufacturer), usb_temp_sysctl,
295 	    "A", "Manufacturer string");
296 	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
297 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
298 	    &midi_product, sizeof(midi_product), usb_temp_sysctl,
299 	    "A", "Product string");
300 	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
301 	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
302 	    &midi_serial_number, sizeof(midi_serial_number), usb_temp_sysctl,
303 	    "A", "Serial number string");
304 }
305 
306 static void
307 midi_uninit(void *arg __unused)
308 {
309 
310 	sysctl_ctx_free(&midi_ctx_list);
311 }
312 
313 SYSINIT(midi_init, SI_SUB_LOCK, SI_ORDER_FIRST, midi_init, NULL);
314 SYSUNINIT(midi_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, midi_uninit, NULL);
315