usb_template_midi.c revision 332576
1/* $FreeBSD: stable/11/sys/dev/usb/template/usb_template_midi.c 332576 2018-04-16 15:44:03Z trasz $ */
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
69enum {
70	MIDI_LANG_INDEX,
71	MIDI_INTERFACE_INDEX,
72	MIDI_PRODUCT_INDEX,
73	MIDI_MAX_INDEX,
74};
75
76#define	MIDI_DEFAULT_INTERFACE		"MIDI interface"
77#define	MIDI_DEFAULT_PRODUCT		"MIDI Test Device"
78
79static struct usb_string_descriptor	midi_interface;
80static struct usb_string_descriptor	midi_product;
81
82static struct sysctl_ctx_list		midi_ctx_list;
83
84/* prototypes */
85
86static const uint8_t midi_desc_raw_0[9] = {
87	0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01
88};
89
90static const void *midi_descs_0[] = {
91	&midi_desc_raw_0,
92	NULL
93};
94
95static const struct usb_temp_interface_desc midi_iface_0 = {
96	.ppEndpoints = NULL,		/* no endpoints */
97	.ppRawDesc = midi_descs_0,
98	.bInterfaceClass = UICLASS_AUDIO,
99	.bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
100	.bInterfaceProtocol = 0,
101	.iInterface = MIDI_INTERFACE_INDEX,
102};
103
104static const struct usb_temp_packet_size midi_mps = {
105	.mps[USB_SPEED_LOW] = 8,
106	.mps[USB_SPEED_FULL] = 64,
107	.mps[USB_SPEED_HIGH] = 512,
108};
109
110static const uint8_t midi_desc_raw_7[5] = {
111	0x05, 0x25, 0x01, 0x01, 0x01
112};
113
114static const void *midi_descs_2[] = {
115	&midi_desc_raw_7,
116	NULL
117};
118
119static const struct usb_temp_endpoint_desc midi_bulk_out_ep = {
120	.ppRawDesc = midi_descs_2,
121	.pPacketSize = &midi_mps,
122	.bEndpointAddress = UE_DIR_OUT,
123	.bmAttributes = UE_BULK,
124};
125
126static const uint8_t midi_desc_raw_6[5] = {
127	0x05, 0x25, 0x01, 0x01, 0x03,
128};
129
130static const void *midi_descs_3[] = {
131	&midi_desc_raw_6,
132	NULL
133};
134
135static const struct usb_temp_endpoint_desc midi_bulk_in_ep = {
136	.ppRawDesc = midi_descs_3,
137	.pPacketSize = &midi_mps,
138	.bEndpointAddress = UE_DIR_IN,
139	.bmAttributes = UE_BULK,
140};
141
142static const struct usb_temp_endpoint_desc *midi_iface_1_ep[] = {
143	&midi_bulk_out_ep,
144	&midi_bulk_in_ep,
145	NULL,
146};
147
148static const uint8_t midi_desc_raw_1[7] = {
149	0x07, 0x24, 0x01, 0x00, 0x01, /* wTotalLength: */ 0x41, 0x00
150};
151
152static const uint8_t midi_desc_raw_2[6] = {
153	0x06, 0x24, 0x02, 0x01, 0x01, 0x00
154};
155
156static const uint8_t midi_desc_raw_3[6] = {
157	0x06, 0x24, 0x02, 0x02, 0x02, 0x00
158};
159
160static const uint8_t midi_desc_raw_4[9] = {
161	0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00
162};
163
164static const uint8_t midi_desc_raw_5[9] = {
165	0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00
166};
167
168static const void *midi_descs_1[] = {
169	&midi_desc_raw_1,
170	&midi_desc_raw_2,
171	&midi_desc_raw_3,
172	&midi_desc_raw_4,
173	&midi_desc_raw_5,
174	NULL
175};
176
177static const struct usb_temp_interface_desc midi_iface_1 = {
178	.ppRawDesc = midi_descs_1,
179	.ppEndpoints = midi_iface_1_ep,
180	.bInterfaceClass = UICLASS_AUDIO,
181	.bInterfaceSubClass = UISUBCLASS_MIDISTREAM,
182	.bInterfaceProtocol = 0,
183	.iInterface = MIDI_INTERFACE_INDEX,
184};
185
186static const struct usb_temp_interface_desc *midi_interfaces[] = {
187	&midi_iface_0,
188	&midi_iface_1,
189	NULL,
190};
191
192static const struct usb_temp_config_desc midi_config_desc = {
193	.ppIfaceDesc = midi_interfaces,
194	.bmAttributes = UC_BUS_POWERED,
195	.bMaxPower = 25,		/* 50 mA */
196	.iConfiguration = MIDI_PRODUCT_INDEX,
197};
198
199static const struct usb_temp_config_desc *midi_configs[] = {
200	&midi_config_desc,
201	NULL,
202};
203
204static usb_temp_get_string_desc_t midi_get_string_desc;
205
206struct usb_temp_device_desc usb_template_midi = {
207	.getStringDesc = &midi_get_string_desc,
208	.ppConfigDesc = midi_configs,
209	.idVendor = USB_TEMPLATE_VENDOR,
210	.idProduct = 0x00BB,
211	.bcdDevice = 0x0100,
212	.bDeviceClass = 0,
213	.bDeviceSubClass = 0,
214	.bDeviceProtocol = 0,
215	.iManufacturer = 0,
216	.iProduct = MIDI_PRODUCT_INDEX,
217	.iSerialNumber = 0,
218};
219
220/*------------------------------------------------------------------------*
221 *	midi_get_string_desc
222 *
223 * Return values:
224 * NULL: Failure. No such string.
225 * Else: Success. Pointer to string descriptor is returned.
226 *------------------------------------------------------------------------*/
227static const void *
228midi_get_string_desc(uint16_t lang_id, uint8_t string_index)
229{
230	static const void *ptr[MIDI_MAX_INDEX] = {
231		[MIDI_LANG_INDEX] = &usb_string_lang_en,
232		[MIDI_INTERFACE_INDEX] = &midi_interface,
233		[MIDI_PRODUCT_INDEX] = &midi_product,
234	};
235
236	if (string_index == 0) {
237		return (&usb_string_lang_en);
238	}
239	if (lang_id != 0x0409) {
240		return (NULL);
241	}
242	if (string_index < MIDI_MAX_INDEX) {
243		return (ptr[string_index]);
244	}
245	return (NULL);
246}
247
248static void
249midi_init(void *arg __unused)
250{
251	struct sysctl_oid *parent;
252	char parent_name[3];
253
254	usb_make_str_desc(&midi_interface, sizeof(midi_interface),
255	    MIDI_DEFAULT_INTERFACE);
256	usb_make_str_desc(&midi_product, sizeof(midi_product),
257	    MIDI_DEFAULT_PRODUCT);
258
259	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MIDI);
260	sysctl_ctx_init(&midi_ctx_list);
261
262	parent = SYSCTL_ADD_NODE(&midi_ctx_list,
263	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
264	    parent_name, CTLFLAG_RW,
265	    0, "USB MIDI device side template");
266	SYSCTL_ADD_U16(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
267	    "vendor_id", CTLFLAG_RWTUN,
268	    &usb_template_midi.idVendor, 1, "Vendor identifier");
269	SYSCTL_ADD_U16(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
270	    "product_id", CTLFLAG_RWTUN,
271	    &usb_template_midi.idProduct, 1, "Product identifier");
272#if 0
273	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
274	    "interface", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
275	    &midi_interface, sizeof(midi_interface), usb_temp_sysctl,
276	    "A", "Interface string");
277#endif
278	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
279	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
280	    &midi_product, sizeof(midi_product), usb_temp_sysctl,
281	    "A", "Product string");
282}
283
284static void
285midi_uninit(void *arg __unused)
286{
287
288	sysctl_ctx_free(&midi_ctx_list);
289}
290
291SYSINIT(midi_init, SI_SUB_LOCK, SI_ORDER_FIRST, midi_init, NULL);
292SYSUNINIT(midi_init, SI_SUB_LOCK, SI_ORDER_FIRST, midi_uninit, NULL);
293