1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2015 Hans Petter Selasky 5 * Copyright (c) 2018 The FreeBSD Foundation 6 * All rights reserved. 7 * 8 * Portions of this software were developed by Edward Tomasz Napierala 9 * under sponsorship from the FreeBSD Foundation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * This file contains the USB template for an USB MIDI Device. 35 */ 36 37 #ifdef USB_GLOBAL_INCLUDE_FILE 38 #include USB_GLOBAL_INCLUDE_FILE 39 #else 40 #include <sys/stdint.h> 41 #include <sys/stddef.h> 42 #include <sys/param.h> 43 #include <sys/queue.h> 44 #include <sys/types.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/bus.h> 48 #include <sys/module.h> 49 #include <sys/lock.h> 50 #include <sys/mutex.h> 51 #include <sys/condvar.h> 52 #include <sys/sysctl.h> 53 #include <sys/sx.h> 54 #include <sys/unistd.h> 55 #include <sys/callout.h> 56 #include <sys/malloc.h> 57 #include <sys/priv.h> 58 59 #include <dev/usb/usb.h> 60 #include <dev/usb/usbdi.h> 61 #include <dev/usb/usb_core.h> 62 #include <dev/usb/usb_ioctl.h> 63 #include <dev/usb/usb_util.h> 64 65 #include <dev/usb/template/usb_template.h> 66 #endif /* USB_GLOBAL_INCLUDE_FILE */ 67 68 enum { 69 MIDI_LANG_INDEX, 70 MIDI_INTERFACE_INDEX, 71 MIDI_MANUFACTURER_INDEX, 72 MIDI_PRODUCT_INDEX, 73 MIDI_SERIAL_NUMBER_INDEX, 74 MIDI_MAX_INDEX, 75 }; 76 77 #define MIDI_DEFAULT_VENDOR_ID USB_TEMPLATE_VENDOR 78 #define MIDI_DEFAULT_PRODUCT_ID 0x27de 79 #define MIDI_DEFAULT_INTERFACE "MIDI interface" 80 #define MIDI_DEFAULT_MANUFACTURER USB_TEMPLATE_MANUFACTURER 81 #define MIDI_DEFAULT_PRODUCT "MIDI Test Device" 82 #define MIDI_DEFAULT_SERIAL_NUMBER "March 2008" 83 84 static struct usb_string_descriptor midi_interface; 85 static struct usb_string_descriptor midi_manufacturer; 86 static struct usb_string_descriptor midi_product; 87 static struct usb_string_descriptor midi_serial_number; 88 89 static struct sysctl_ctx_list midi_ctx_list; 90 91 /* prototypes */ 92 93 static const uint8_t midi_desc_raw_0[9] = { 94 0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01 95 }; 96 97 static const void *midi_descs_0[] = { 98 &midi_desc_raw_0, 99 NULL 100 }; 101 102 static const struct usb_temp_interface_desc midi_iface_0 = { 103 .ppEndpoints = NULL, /* no endpoints */ 104 .ppRawDesc = midi_descs_0, 105 .bInterfaceClass = UICLASS_AUDIO, 106 .bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL, 107 .bInterfaceProtocol = 0, 108 .iInterface = MIDI_INTERFACE_INDEX, 109 }; 110 111 static const struct usb_temp_packet_size midi_mps = { 112 .mps[USB_SPEED_LOW] = 8, 113 .mps[USB_SPEED_FULL] = 64, 114 .mps[USB_SPEED_HIGH] = 512, 115 }; 116 117 static const uint8_t midi_desc_raw_7[5] = { 118 0x05, 0x25, 0x01, 0x01, 0x01 119 }; 120 121 static const void *midi_descs_2[] = { 122 &midi_desc_raw_7, 123 NULL 124 }; 125 126 static const struct usb_temp_endpoint_desc midi_bulk_out_ep = { 127 .ppRawDesc = midi_descs_2, 128 .pPacketSize = &midi_mps, 129 .bEndpointAddress = UE_DIR_OUT, 130 .bmAttributes = UE_BULK, 131 }; 132 133 static const uint8_t midi_desc_raw_6[5] = { 134 0x05, 0x25, 0x01, 0x01, 0x03, 135 }; 136 137 static const void *midi_descs_3[] = { 138 &midi_desc_raw_6, 139 NULL 140 }; 141 142 static const struct usb_temp_endpoint_desc midi_bulk_in_ep = { 143 .ppRawDesc = midi_descs_3, 144 .pPacketSize = &midi_mps, 145 .bEndpointAddress = UE_DIR_IN, 146 .bmAttributes = UE_BULK, 147 }; 148 149 static const struct usb_temp_endpoint_desc *midi_iface_1_ep[] = { 150 &midi_bulk_out_ep, 151 &midi_bulk_in_ep, 152 NULL, 153 }; 154 155 static const uint8_t midi_desc_raw_1[7] = { 156 0x07, 0x24, 0x01, 0x00, 0x01, /* wTotalLength: */ 0x41, 0x00 157 }; 158 159 static const uint8_t midi_desc_raw_2[6] = { 160 0x06, 0x24, 0x02, 0x01, 0x01, 0x00 161 }; 162 163 static const uint8_t midi_desc_raw_3[6] = { 164 0x06, 0x24, 0x02, 0x02, 0x02, 0x00 165 }; 166 167 static const uint8_t midi_desc_raw_4[9] = { 168 0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00 169 }; 170 171 static const uint8_t midi_desc_raw_5[9] = { 172 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00 173 }; 174 175 static const void *midi_descs_1[] = { 176 &midi_desc_raw_1, 177 &midi_desc_raw_2, 178 &midi_desc_raw_3, 179 &midi_desc_raw_4, 180 &midi_desc_raw_5, 181 NULL 182 }; 183 184 static const struct usb_temp_interface_desc midi_iface_1 = { 185 .ppRawDesc = midi_descs_1, 186 .ppEndpoints = midi_iface_1_ep, 187 .bInterfaceClass = UICLASS_AUDIO, 188 .bInterfaceSubClass = UISUBCLASS_MIDISTREAM, 189 .bInterfaceProtocol = 0, 190 .iInterface = MIDI_INTERFACE_INDEX, 191 }; 192 193 static const struct usb_temp_interface_desc *midi_interfaces[] = { 194 &midi_iface_0, 195 &midi_iface_1, 196 NULL, 197 }; 198 199 static const struct usb_temp_config_desc midi_config_desc = { 200 .ppIfaceDesc = midi_interfaces, 201 .bmAttributes = 0, 202 .bMaxPower = 0, 203 .iConfiguration = MIDI_PRODUCT_INDEX, 204 }; 205 206 static const struct usb_temp_config_desc *midi_configs[] = { 207 &midi_config_desc, 208 NULL, 209 }; 210 211 static usb_temp_get_string_desc_t midi_get_string_desc; 212 213 struct usb_temp_device_desc usb_template_midi = { 214 .getStringDesc = &midi_get_string_desc, 215 .ppConfigDesc = midi_configs, 216 .idVendor = MIDI_DEFAULT_VENDOR_ID, 217 .idProduct = MIDI_DEFAULT_PRODUCT_ID, 218 .bcdDevice = 0x0100, 219 .bDeviceClass = 0, 220 .bDeviceSubClass = 0, 221 .bDeviceProtocol = 0, 222 .iManufacturer = MIDI_MANUFACTURER_INDEX, 223 .iProduct = MIDI_PRODUCT_INDEX, 224 .iSerialNumber = MIDI_SERIAL_NUMBER_INDEX, 225 }; 226 227 /*------------------------------------------------------------------------* 228 * midi_get_string_desc 229 * 230 * Return values: 231 * NULL: Failure. No such string. 232 * Else: Success. Pointer to string descriptor is returned. 233 *------------------------------------------------------------------------*/ 234 static const void * 235 midi_get_string_desc(uint16_t lang_id, uint8_t string_index) 236 { 237 static const void *ptr[MIDI_MAX_INDEX] = { 238 [MIDI_LANG_INDEX] = &usb_string_lang_en, 239 [MIDI_INTERFACE_INDEX] = &midi_interface, 240 [MIDI_MANUFACTURER_INDEX] = &midi_manufacturer, 241 [MIDI_PRODUCT_INDEX] = &midi_product, 242 [MIDI_SERIAL_NUMBER_INDEX] = &midi_serial_number, 243 }; 244 245 if (string_index == 0) { 246 return (&usb_string_lang_en); 247 } 248 if (lang_id != 0x0409) { 249 return (NULL); 250 } 251 if (string_index < MIDI_MAX_INDEX) { 252 return (ptr[string_index]); 253 } 254 return (NULL); 255 } 256 257 static void 258 midi_init(void *arg __unused) 259 { 260 struct sysctl_oid *parent; 261 char parent_name[3]; 262 263 usb_make_str_desc(&midi_interface, sizeof(midi_interface), 264 MIDI_DEFAULT_INTERFACE); 265 usb_make_str_desc(&midi_manufacturer, sizeof(midi_manufacturer), 266 MIDI_DEFAULT_MANUFACTURER); 267 usb_make_str_desc(&midi_product, sizeof(midi_product), 268 MIDI_DEFAULT_PRODUCT); 269 usb_make_str_desc(&midi_serial_number, sizeof(midi_serial_number), 270 MIDI_DEFAULT_SERIAL_NUMBER); 271 272 snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MIDI); 273 sysctl_ctx_init(&midi_ctx_list); 274 275 parent = SYSCTL_ADD_NODE(&midi_ctx_list, 276 SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO, 277 parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE, 278 0, "USB MIDI device side template"); 279 SYSCTL_ADD_U16(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 280 "vendor_id", CTLFLAG_RWTUN, 281 &usb_template_midi.idVendor, 1, "Vendor identifier"); 282 SYSCTL_ADD_U16(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 283 "product_id", CTLFLAG_RWTUN, 284 &usb_template_midi.idProduct, 1, "Product identifier"); 285 #if 0 286 SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 287 "interface", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 288 &midi_interface, sizeof(midi_interface), usb_temp_sysctl, 289 "A", "Interface string"); 290 #endif 291 SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 292 "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 293 &midi_manufacturer, sizeof(midi_manufacturer), usb_temp_sysctl, 294 "A", "Manufacturer string"); 295 SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 296 "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 297 &midi_product, sizeof(midi_product), usb_temp_sysctl, 298 "A", "Product string"); 299 SYSCTL_ADD_PROC(&midi_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO, 300 "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 301 &midi_serial_number, sizeof(midi_serial_number), usb_temp_sysctl, 302 "A", "Serial number string"); 303 } 304 305 static void 306 midi_uninit(void *arg __unused) 307 { 308 309 sysctl_ctx_free(&midi_ctx_list); 310 } 311 312 SYSINIT(midi_init, SI_SUB_LOCK, SI_ORDER_FIRST, midi_init, NULL); 313 SYSUNINIT(midi_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, midi_uninit, NULL); 314