1283879Shselasky/* $FreeBSD: stable/11/sys/dev/usb/template/usb_template_midi.c 357434 2020-02-03 10:57:37Z hselasky $ */
2283879Shselasky/*-
3332576Strasz * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4332576Strasz *
5332575Strasz * Copyright (c) 2015 Hans Petter Selasky
6332575Strasz * Copyright (c) 2018 The FreeBSD Foundation
7332575Strasz * All rights reserved.
8283879Shselasky *
9332575Strasz * Portions of this software were developed by Edward Tomasz Napierala
10332575Strasz * under sponsorship from the FreeBSD Foundation.
11332575Strasz *
12283879Shselasky * Redistribution and use in source and binary forms, with or without
13283879Shselasky * modification, are permitted provided that the following conditions
14283879Shselasky * are met:
15283879Shselasky * 1. Redistributions of source code must retain the above copyright
16283879Shselasky *    notice, this list of conditions and the following disclaimer.
17283879Shselasky * 2. Redistributions in binary form must reproduce the above copyright
18283879Shselasky *    notice, this list of conditions and the following disclaimer in the
19283879Shselasky *    documentation and/or other materials provided with the distribution.
20283879Shselasky *
21283879Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22283879Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23283879Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24283879Shselasky * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25283879Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26283879Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27283879Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28283879Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29283879Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30283879Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31283879Shselasky * SUCH DAMAGE.
32283879Shselasky */
33283879Shselasky
34283879Shselasky/*
35283879Shselasky * This file contains the USB template for an USB MIDI Device.
36283879Shselasky */
37283879Shselasky
38283879Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE
39283879Shselasky#include USB_GLOBAL_INCLUDE_FILE
40283879Shselasky#else
41283879Shselasky#include <sys/stdint.h>
42283879Shselasky#include <sys/stddef.h>
43283879Shselasky#include <sys/param.h>
44283879Shselasky#include <sys/queue.h>
45283879Shselasky#include <sys/types.h>
46283879Shselasky#include <sys/systm.h>
47283879Shselasky#include <sys/kernel.h>
48283879Shselasky#include <sys/bus.h>
49283879Shselasky#include <sys/module.h>
50283879Shselasky#include <sys/lock.h>
51283879Shselasky#include <sys/mutex.h>
52283879Shselasky#include <sys/condvar.h>
53283879Shselasky#include <sys/sysctl.h>
54283879Shselasky#include <sys/sx.h>
55283879Shselasky#include <sys/unistd.h>
56283879Shselasky#include <sys/callout.h>
57283879Shselasky#include <sys/malloc.h>
58283879Shselasky#include <sys/priv.h>
59283879Shselasky
60283879Shselasky#include <dev/usb/usb.h>
61283879Shselasky#include <dev/usb/usbdi.h>
62283879Shselasky#include <dev/usb/usb_core.h>
63332575Strasz#include <dev/usb/usb_ioctl.h>
64332575Strasz#include <dev/usb/usb_util.h>
65283879Shselasky
66283879Shselasky#include <dev/usb/template/usb_template.h>
67283879Shselasky#endif					/* USB_GLOBAL_INCLUDE_FILE */
68283879Shselasky
69283879Shselaskyenum {
70332575Strasz	MIDI_LANG_INDEX,
71332575Strasz	MIDI_INTERFACE_INDEX,
72332578Strasz	MIDI_MANUFACTURER_INDEX,
73332575Strasz	MIDI_PRODUCT_INDEX,
74332578Strasz	MIDI_SERIAL_NUMBER_INDEX,
75332575Strasz	MIDI_MAX_INDEX,
76283879Shselasky};
77283879Shselasky
78332575Strasz#define	MIDI_DEFAULT_INTERFACE		"MIDI interface"
79332578Strasz#define	MIDI_DEFAULT_MANUFACTURER	"FreeBSD foundation"
80332575Strasz#define	MIDI_DEFAULT_PRODUCT		"MIDI Test Device"
81332578Strasz#define	MIDI_DEFAULT_SERIAL_NUMBER	"March 2008"
82283879Shselasky
83332575Straszstatic struct usb_string_descriptor	midi_interface;
84332578Straszstatic struct usb_string_descriptor	midi_manufacturer;
85332575Straszstatic struct usb_string_descriptor	midi_product;
86332578Straszstatic struct usb_string_descriptor	midi_serial_number;
87283879Shselasky
88332575Straszstatic struct sysctl_ctx_list		midi_ctx_list;
89283879Shselasky
90283879Shselasky/* prototypes */
91283879Shselasky
92283879Shselaskystatic const uint8_t midi_desc_raw_0[9] = {
93283879Shselasky	0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01
94283879Shselasky};
95283879Shselasky
96283879Shselaskystatic const void *midi_descs_0[] = {
97283879Shselasky	&midi_desc_raw_0,
98283879Shselasky	NULL
99283879Shselasky};
100283879Shselasky
101283879Shselaskystatic const struct usb_temp_interface_desc midi_iface_0 = {
102283879Shselasky	.ppEndpoints = NULL,		/* no endpoints */
103283879Shselasky	.ppRawDesc = midi_descs_0,
104332574Strasz	.bInterfaceClass = UICLASS_AUDIO,
105332574Strasz	.bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
106283879Shselasky	.bInterfaceProtocol = 0,
107332575Strasz	.iInterface = MIDI_INTERFACE_INDEX,
108283879Shselasky};
109283879Shselasky
110283879Shselaskystatic const struct usb_temp_packet_size midi_mps = {
111283879Shselasky	.mps[USB_SPEED_LOW] = 8,
112283879Shselasky	.mps[USB_SPEED_FULL] = 64,
113283879Shselasky	.mps[USB_SPEED_HIGH] = 512,
114283879Shselasky};
115283879Shselasky
116283879Shselaskystatic const uint8_t midi_desc_raw_7[5] = {
117283879Shselasky	0x05, 0x25, 0x01, 0x01, 0x01
118283879Shselasky};
119283879Shselasky
120283879Shselaskystatic const void *midi_descs_2[] = {
121283879Shselasky	&midi_desc_raw_7,
122283879Shselasky	NULL
123283879Shselasky};
124283879Shselasky
125283879Shselaskystatic const struct usb_temp_endpoint_desc midi_bulk_out_ep = {
126283879Shselasky	.ppRawDesc = midi_descs_2,
127283879Shselasky	.pPacketSize = &midi_mps,
128283879Shselasky	.bEndpointAddress = UE_DIR_OUT,
129283879Shselasky	.bmAttributes = UE_BULK,
130283879Shselasky};
131283879Shselasky
132283879Shselaskystatic const uint8_t midi_desc_raw_6[5] = {
133283879Shselasky	0x05, 0x25, 0x01, 0x01, 0x03,
134283879Shselasky};
135283879Shselasky
136283879Shselaskystatic const void *midi_descs_3[] = {
137283879Shselasky	&midi_desc_raw_6,
138283879Shselasky	NULL
139283879Shselasky};
140283879Shselasky
141283879Shselaskystatic const struct usb_temp_endpoint_desc midi_bulk_in_ep = {
142283879Shselasky	.ppRawDesc = midi_descs_3,
143283879Shselasky	.pPacketSize = &midi_mps,
144283879Shselasky	.bEndpointAddress = UE_DIR_IN,
145283879Shselasky	.bmAttributes = UE_BULK,
146283879Shselasky};
147283879Shselasky
148283879Shselaskystatic const struct usb_temp_endpoint_desc *midi_iface_1_ep[] = {
149283879Shselasky	&midi_bulk_out_ep,
150283879Shselasky	&midi_bulk_in_ep,
151283879Shselasky	NULL,
152283879Shselasky};
153283879Shselasky
154283879Shselaskystatic const uint8_t midi_desc_raw_1[7] = {
155283879Shselasky	0x07, 0x24, 0x01, 0x00, 0x01, /* wTotalLength: */ 0x41, 0x00
156283879Shselasky};
157283879Shselasky
158283879Shselaskystatic const uint8_t midi_desc_raw_2[6] = {
159283879Shselasky	0x06, 0x24, 0x02, 0x01, 0x01, 0x00
160283879Shselasky};
161283879Shselasky
162283879Shselaskystatic const uint8_t midi_desc_raw_3[6] = {
163283879Shselasky	0x06, 0x24, 0x02, 0x02, 0x02, 0x00
164283879Shselasky};
165283879Shselasky
166283879Shselaskystatic const uint8_t midi_desc_raw_4[9] = {
167283879Shselasky	0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00
168283879Shselasky};
169283879Shselasky
170283879Shselaskystatic const uint8_t midi_desc_raw_5[9] = {
171283879Shselasky	0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00
172283879Shselasky};
173283879Shselasky
174283879Shselaskystatic const void *midi_descs_1[] = {
175283879Shselasky	&midi_desc_raw_1,
176283879Shselasky	&midi_desc_raw_2,
177283879Shselasky	&midi_desc_raw_3,
178283879Shselasky	&midi_desc_raw_4,
179283879Shselasky	&midi_desc_raw_5,
180283879Shselasky	NULL
181283879Shselasky};
182283879Shselasky
183283879Shselaskystatic const struct usb_temp_interface_desc midi_iface_1 = {
184283879Shselasky	.ppRawDesc = midi_descs_1,
185283879Shselasky	.ppEndpoints = midi_iface_1_ep,
186332574Strasz	.bInterfaceClass = UICLASS_AUDIO,
187332574Strasz	.bInterfaceSubClass = UISUBCLASS_MIDISTREAM,
188283879Shselasky	.bInterfaceProtocol = 0,
189332575Strasz	.iInterface = MIDI_INTERFACE_INDEX,
190283879Shselasky};
191283879Shselasky
192283879Shselaskystatic const struct usb_temp_interface_desc *midi_interfaces[] = {
193283879Shselasky	&midi_iface_0,
194283879Shselasky	&midi_iface_1,
195283879Shselasky	NULL,
196283879Shselasky};
197283879Shselasky
198283879Shselaskystatic const struct usb_temp_config_desc midi_config_desc = {
199283879Shselasky	.ppIfaceDesc = midi_interfaces,
200283879Shselasky	.bmAttributes = UC_BUS_POWERED,
201283879Shselasky	.bMaxPower = 25,		/* 50 mA */
202332575Strasz	.iConfiguration = MIDI_PRODUCT_INDEX,
203283879Shselasky};
204283879Shselasky
205283879Shselaskystatic const struct usb_temp_config_desc *midi_configs[] = {
206283879Shselasky	&midi_config_desc,
207283879Shselasky	NULL,
208283879Shselasky};
209283879Shselasky
210283879Shselaskystatic usb_temp_get_string_desc_t midi_get_string_desc;
211283879Shselasky
212332575Straszstruct usb_temp_device_desc usb_template_midi = {
213283879Shselasky	.getStringDesc = &midi_get_string_desc,
214283879Shselasky	.ppConfigDesc = midi_configs,
215283879Shselasky	.idVendor = USB_TEMPLATE_VENDOR,
216283879Shselasky	.idProduct = 0x00BB,
217283879Shselasky	.bcdDevice = 0x0100,
218283879Shselasky	.bDeviceClass = 0,
219283879Shselasky	.bDeviceSubClass = 0,
220283879Shselasky	.bDeviceProtocol = 0,
221332578Strasz	.iManufacturer = MIDI_MANUFACTURER_INDEX,
222332575Strasz	.iProduct = MIDI_PRODUCT_INDEX,
223332578Strasz	.iSerialNumber = MIDI_SERIAL_NUMBER_INDEX,
224283879Shselasky};
225283879Shselasky
226283879Shselasky/*------------------------------------------------------------------------*
227283879Shselasky *	midi_get_string_desc
228283879Shselasky *
229283879Shselasky * Return values:
230283879Shselasky * NULL: Failure. No such string.
231283879Shselasky * Else: Success. Pointer to string descriptor is returned.
232283879Shselasky *------------------------------------------------------------------------*/
233283879Shselaskystatic const void *
234283879Shselaskymidi_get_string_desc(uint16_t lang_id, uint8_t string_index)
235283879Shselasky{
236332575Strasz	static const void *ptr[MIDI_MAX_INDEX] = {
237332575Strasz		[MIDI_LANG_INDEX] = &usb_string_lang_en,
238332575Strasz		[MIDI_INTERFACE_INDEX] = &midi_interface,
239332578Strasz		[MIDI_MANUFACTURER_INDEX] = &midi_manufacturer,
240332575Strasz		[MIDI_PRODUCT_INDEX] = &midi_product,
241332578Strasz		[MIDI_SERIAL_NUMBER_INDEX] = &midi_serial_number,
242283879Shselasky	};
243283879Shselasky
244283879Shselasky	if (string_index == 0) {
245283879Shselasky		return (&usb_string_lang_en);
246283879Shselasky	}
247283879Shselasky	if (lang_id != 0x0409) {
248283879Shselasky		return (NULL);
249283879Shselasky	}
250332575Strasz	if (string_index < MIDI_MAX_INDEX) {
251283879Shselasky		return (ptr[string_index]);
252283879Shselasky	}
253283879Shselasky	return (NULL);
254283879Shselasky}
255332575Strasz
256332575Straszstatic void
257332575Straszmidi_init(void *arg __unused)
258332575Strasz{
259332575Strasz	struct sysctl_oid *parent;
260332575Strasz	char parent_name[3];
261332575Strasz
262332575Strasz	usb_make_str_desc(&midi_interface, sizeof(midi_interface),
263332575Strasz	    MIDI_DEFAULT_INTERFACE);
264332578Strasz	usb_make_str_desc(&midi_manufacturer, sizeof(midi_manufacturer),
265332578Strasz	    MIDI_DEFAULT_MANUFACTURER);
266332575Strasz	usb_make_str_desc(&midi_product, sizeof(midi_product),
267332575Strasz	    MIDI_DEFAULT_PRODUCT);
268332578Strasz	usb_make_str_desc(&midi_serial_number, sizeof(midi_serial_number),
269332578Strasz	    MIDI_DEFAULT_SERIAL_NUMBER);
270332575Strasz
271332575Strasz	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MIDI);
272332575Strasz	sysctl_ctx_init(&midi_ctx_list);
273332575Strasz
274332575Strasz	parent = SYSCTL_ADD_NODE(&midi_ctx_list,
275332575Strasz	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
276332575Strasz	    parent_name, CTLFLAG_RW,
277332575Strasz	    0, "USB MIDI device side template");
278332575Strasz	SYSCTL_ADD_U16(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
279332575Strasz	    "vendor_id", CTLFLAG_RWTUN,
280332575Strasz	    &usb_template_midi.idVendor, 1, "Vendor identifier");
281332575Strasz	SYSCTL_ADD_U16(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
282332575Strasz	    "product_id", CTLFLAG_RWTUN,
283332575Strasz	    &usb_template_midi.idProduct, 1, "Product identifier");
284332575Strasz#if 0
285332575Strasz	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
286332575Strasz	    "interface", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
287332575Strasz	    &midi_interface, sizeof(midi_interface), usb_temp_sysctl,
288332575Strasz	    "A", "Interface string");
289332575Strasz#endif
290332575Strasz	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
291332578Strasz	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
292332578Strasz	    &midi_manufacturer, sizeof(midi_manufacturer), usb_temp_sysctl,
293332578Strasz	    "A", "Manufacturer string");
294332578Strasz	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
295332575Strasz	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
296332575Strasz	    &midi_product, sizeof(midi_product), usb_temp_sysctl,
297332575Strasz	    "A", "Product string");
298332578Strasz	SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
299332578Strasz	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
300332578Strasz	    &midi_serial_number, sizeof(midi_serial_number), usb_temp_sysctl,
301332578Strasz	    "A", "Serial number string");
302332575Strasz}
303332575Strasz
304332575Straszstatic void
305332575Straszmidi_uninit(void *arg __unused)
306332575Strasz{
307332575Strasz
308332575Strasz	sysctl_ctx_free(&midi_ctx_list);
309332575Strasz}
310332575Strasz
311332575StraszSYSINIT(midi_init, SI_SUB_LOCK, SI_ORDER_FIRST, midi_init, NULL);
312357434ShselaskySYSUNINIT(midi_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, midi_uninit, NULL);
313