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 69enum { 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 85static struct usb_string_descriptor midi_interface; 86static struct usb_string_descriptor midi_manufacturer; 87static struct usb_string_descriptor midi_product; 88static struct usb_string_descriptor midi_serial_number; 89 90static struct sysctl_ctx_list midi_ctx_list; 91 92/* prototypes */ 93 94static const uint8_t midi_desc_raw_0[9] = { 95 0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01 96}; 97 98static const void *midi_descs_0[] = { 99 &midi_desc_raw_0, 100 NULL 101}; 102 103static 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 112static 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 118static const uint8_t midi_desc_raw_7[5] = { 119 0x05, 0x25, 0x01, 0x01, 0x01 120}; 121 122static const void *midi_descs_2[] = { 123 &midi_desc_raw_7, 124 NULL 125}; 126 127static 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 134static const uint8_t midi_desc_raw_6[5] = { 135 0x05, 0x25, 0x01, 0x01, 0x03, 136}; 137 138static const void *midi_descs_3[] = { 139 &midi_desc_raw_6, 140 NULL 141}; 142 143static 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 150static const struct usb_temp_endpoint_desc *midi_iface_1_ep[] = { 151 &midi_bulk_out_ep, 152 &midi_bulk_in_ep, 153 NULL, 154}; 155 156static const uint8_t midi_desc_raw_1[7] = { 157 0x07, 0x24, 0x01, 0x00, 0x01, /* wTotalLength: */ 0x41, 0x00 158}; 159 160static const uint8_t midi_desc_raw_2[6] = { 161 0x06, 0x24, 0x02, 0x01, 0x01, 0x00 162}; 163 164static const uint8_t midi_desc_raw_3[6] = { 165 0x06, 0x24, 0x02, 0x02, 0x02, 0x00 166}; 167 168static const uint8_t midi_desc_raw_4[9] = { 169 0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00 170}; 171 172static const uint8_t midi_desc_raw_5[9] = { 173 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00 174}; 175 176static 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 185static 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 194static const struct usb_temp_interface_desc *midi_interfaces[] = { 195 &midi_iface_0, 196 &midi_iface_1, 197 NULL, 198}; 199 200static 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 207static const struct usb_temp_config_desc *midi_configs[] = { 208 &midi_config_desc, 209 NULL, 210}; 211 212static usb_temp_get_string_desc_t midi_get_string_desc; 213 214struct 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 *------------------------------------------------------------------------*/ 235static const void * 236midi_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 258static void 259midi_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, 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 306static void 307midi_uninit(void *arg __unused) 308{ 309 310 sysctl_ctx_free(&midi_ctx_list); 311} 312 313SYSINIT(midi_init, SI_SUB_LOCK, SI_ORDER_FIRST, midi_init, NULL); 314SYSUNINIT(midi_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, midi_uninit, NULL); 315