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