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