10a76fe7cSHans Petter Selasky /* $FreeBSD$ */ 20a76fe7cSHans Petter Selasky /*- 30a76fe7cSHans Petter Selasky * Copyright (c) 2015 Hans Petter Selasky. All rights reserved. 40a76fe7cSHans Petter Selasky * 50a76fe7cSHans Petter Selasky * Redistribution and use in source and binary forms, with or without 60a76fe7cSHans Petter Selasky * modification, are permitted provided that the following conditions 70a76fe7cSHans Petter Selasky * are met: 80a76fe7cSHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 90a76fe7cSHans Petter Selasky * notice, this list of conditions and the following disclaimer. 100a76fe7cSHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 110a76fe7cSHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 120a76fe7cSHans Petter Selasky * documentation and/or other materials provided with the distribution. 130a76fe7cSHans Petter Selasky * 140a76fe7cSHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 150a76fe7cSHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 160a76fe7cSHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 170a76fe7cSHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 180a76fe7cSHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 190a76fe7cSHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 200a76fe7cSHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 210a76fe7cSHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 220a76fe7cSHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 230a76fe7cSHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 240a76fe7cSHans Petter Selasky * SUCH DAMAGE. 250a76fe7cSHans Petter Selasky */ 260a76fe7cSHans Petter Selasky 270a76fe7cSHans Petter Selasky /* 280a76fe7cSHans Petter Selasky * This file contains the USB template for an USB MIDI Device. 290a76fe7cSHans Petter Selasky */ 300a76fe7cSHans Petter Selasky 310a76fe7cSHans Petter Selasky #ifdef USB_GLOBAL_INCLUDE_FILE 320a76fe7cSHans Petter Selasky #include USB_GLOBAL_INCLUDE_FILE 330a76fe7cSHans Petter Selasky #else 340a76fe7cSHans Petter Selasky #include <sys/stdint.h> 350a76fe7cSHans Petter Selasky #include <sys/stddef.h> 360a76fe7cSHans Petter Selasky #include <sys/param.h> 370a76fe7cSHans Petter Selasky #include <sys/queue.h> 380a76fe7cSHans Petter Selasky #include <sys/types.h> 390a76fe7cSHans Petter Selasky #include <sys/systm.h> 400a76fe7cSHans Petter Selasky #include <sys/kernel.h> 410a76fe7cSHans Petter Selasky #include <sys/bus.h> 420a76fe7cSHans Petter Selasky #include <sys/module.h> 430a76fe7cSHans Petter Selasky #include <sys/lock.h> 440a76fe7cSHans Petter Selasky #include <sys/mutex.h> 450a76fe7cSHans Petter Selasky #include <sys/condvar.h> 460a76fe7cSHans Petter Selasky #include <sys/sysctl.h> 470a76fe7cSHans Petter Selasky #include <sys/sx.h> 480a76fe7cSHans Petter Selasky #include <sys/unistd.h> 490a76fe7cSHans Petter Selasky #include <sys/callout.h> 500a76fe7cSHans Petter Selasky #include <sys/malloc.h> 510a76fe7cSHans Petter Selasky #include <sys/priv.h> 520a76fe7cSHans Petter Selasky 530a76fe7cSHans Petter Selasky #include <dev/usb/usb.h> 540a76fe7cSHans Petter Selasky #include <dev/usb/usbdi.h> 550a76fe7cSHans Petter Selasky #include <dev/usb/usb_core.h> 560a76fe7cSHans Petter Selasky 570a76fe7cSHans Petter Selasky #include <dev/usb/template/usb_template.h> 580a76fe7cSHans Petter Selasky #endif /* USB_GLOBAL_INCLUDE_FILE */ 590a76fe7cSHans Petter Selasky 600a76fe7cSHans Petter Selasky enum { 610a76fe7cSHans Petter Selasky INDEX_MIDI_LANG, 620a76fe7cSHans Petter Selasky INDEX_MIDI_IF, 630a76fe7cSHans Petter Selasky INDEX_MIDI_PRODUCT, 640a76fe7cSHans Petter Selasky INDEX_MIDI_MAX, 650a76fe7cSHans Petter Selasky }; 660a76fe7cSHans Petter Selasky 670a76fe7cSHans Petter Selasky #define STRING_MIDI_PRODUCT \ 680a76fe7cSHans Petter Selasky "M\0I\0D\0I\0 \0T\0e\0s\0t\0 \0D\0e\0v\0i\0c\0e" 690a76fe7cSHans Petter Selasky 700a76fe7cSHans Petter Selasky #define STRING_MIDI_IF \ 710a76fe7cSHans Petter Selasky "M\0I\0D\0I\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e" 720a76fe7cSHans Petter Selasky 730a76fe7cSHans Petter Selasky /* make the real string descriptors */ 740a76fe7cSHans Petter Selasky 750a76fe7cSHans Petter Selasky USB_MAKE_STRING_DESC(STRING_MIDI_IF, string_midi_if); 760a76fe7cSHans Petter Selasky USB_MAKE_STRING_DESC(STRING_MIDI_PRODUCT, string_midi_product); 770a76fe7cSHans Petter Selasky 780a76fe7cSHans Petter Selasky /* prototypes */ 790a76fe7cSHans Petter Selasky 800a76fe7cSHans Petter Selasky static const uint8_t midi_desc_raw_0[9] = { 810a76fe7cSHans Petter Selasky 0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01 820a76fe7cSHans Petter Selasky }; 830a76fe7cSHans Petter Selasky 840a76fe7cSHans Petter Selasky static const void *midi_descs_0[] = { 850a76fe7cSHans Petter Selasky &midi_desc_raw_0, 860a76fe7cSHans Petter Selasky NULL 870a76fe7cSHans Petter Selasky }; 880a76fe7cSHans Petter Selasky 890a76fe7cSHans Petter Selasky static const struct usb_temp_interface_desc midi_iface_0 = { 900a76fe7cSHans Petter Selasky .ppEndpoints = NULL, /* no endpoints */ 910a76fe7cSHans Petter Selasky .ppRawDesc = midi_descs_0, 92*4ffeccf1SEdward Tomasz Napierala .bInterfaceClass = UICLASS_AUDIO, 93*4ffeccf1SEdward Tomasz Napierala .bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL, 940a76fe7cSHans Petter Selasky .bInterfaceProtocol = 0, 950a76fe7cSHans Petter Selasky .iInterface = INDEX_MIDI_IF, 960a76fe7cSHans Petter Selasky }; 970a76fe7cSHans Petter Selasky 980a76fe7cSHans Petter Selasky static const struct usb_temp_packet_size midi_mps = { 990a76fe7cSHans Petter Selasky .mps[USB_SPEED_LOW] = 8, 1000a76fe7cSHans Petter Selasky .mps[USB_SPEED_FULL] = 64, 1010a76fe7cSHans Petter Selasky .mps[USB_SPEED_HIGH] = 512, 1020a76fe7cSHans Petter Selasky }; 1030a76fe7cSHans Petter Selasky 1040a76fe7cSHans Petter Selasky static const uint8_t midi_desc_raw_7[5] = { 1050a76fe7cSHans Petter Selasky 0x05, 0x25, 0x01, 0x01, 0x01 1060a76fe7cSHans Petter Selasky }; 1070a76fe7cSHans Petter Selasky 1080a76fe7cSHans Petter Selasky static const void *midi_descs_2[] = { 1090a76fe7cSHans Petter Selasky &midi_desc_raw_7, 1100a76fe7cSHans Petter Selasky NULL 1110a76fe7cSHans Petter Selasky }; 1120a76fe7cSHans Petter Selasky 1130a76fe7cSHans Petter Selasky static const struct usb_temp_endpoint_desc midi_bulk_out_ep = { 1140a76fe7cSHans Petter Selasky .ppRawDesc = midi_descs_2, 1150a76fe7cSHans Petter Selasky .pPacketSize = &midi_mps, 1160a76fe7cSHans Petter Selasky .bEndpointAddress = UE_DIR_OUT, 1170a76fe7cSHans Petter Selasky .bmAttributes = UE_BULK, 1180a76fe7cSHans Petter Selasky }; 1190a76fe7cSHans Petter Selasky 1200a76fe7cSHans Petter Selasky static const uint8_t midi_desc_raw_6[5] = { 1210a76fe7cSHans Petter Selasky 0x05, 0x25, 0x01, 0x01, 0x03, 1220a76fe7cSHans Petter Selasky }; 1230a76fe7cSHans Petter Selasky 1240a76fe7cSHans Petter Selasky static const void *midi_descs_3[] = { 1250a76fe7cSHans Petter Selasky &midi_desc_raw_6, 1260a76fe7cSHans Petter Selasky NULL 1270a76fe7cSHans Petter Selasky }; 1280a76fe7cSHans Petter Selasky 1290a76fe7cSHans Petter Selasky static const struct usb_temp_endpoint_desc midi_bulk_in_ep = { 1300a76fe7cSHans Petter Selasky .ppRawDesc = midi_descs_3, 1310a76fe7cSHans Petter Selasky .pPacketSize = &midi_mps, 1320a76fe7cSHans Petter Selasky .bEndpointAddress = UE_DIR_IN, 1330a76fe7cSHans Petter Selasky .bmAttributes = UE_BULK, 1340a76fe7cSHans Petter Selasky }; 1350a76fe7cSHans Petter Selasky 1360a76fe7cSHans Petter Selasky static const struct usb_temp_endpoint_desc *midi_iface_1_ep[] = { 1370a76fe7cSHans Petter Selasky &midi_bulk_out_ep, 1380a76fe7cSHans Petter Selasky &midi_bulk_in_ep, 1390a76fe7cSHans Petter Selasky NULL, 1400a76fe7cSHans Petter Selasky }; 1410a76fe7cSHans Petter Selasky 1420a76fe7cSHans Petter Selasky static const uint8_t midi_desc_raw_1[7] = { 1430a76fe7cSHans Petter Selasky 0x07, 0x24, 0x01, 0x00, 0x01, /* wTotalLength: */ 0x41, 0x00 1440a76fe7cSHans Petter Selasky }; 1450a76fe7cSHans Petter Selasky 1460a76fe7cSHans Petter Selasky static const uint8_t midi_desc_raw_2[6] = { 1470a76fe7cSHans Petter Selasky 0x06, 0x24, 0x02, 0x01, 0x01, 0x00 1480a76fe7cSHans Petter Selasky }; 1490a76fe7cSHans Petter Selasky 1500a76fe7cSHans Petter Selasky static const uint8_t midi_desc_raw_3[6] = { 1510a76fe7cSHans Petter Selasky 0x06, 0x24, 0x02, 0x02, 0x02, 0x00 1520a76fe7cSHans Petter Selasky }; 1530a76fe7cSHans Petter Selasky 1540a76fe7cSHans Petter Selasky static const uint8_t midi_desc_raw_4[9] = { 1550a76fe7cSHans Petter Selasky 0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00 1560a76fe7cSHans Petter Selasky }; 1570a76fe7cSHans Petter Selasky 1580a76fe7cSHans Petter Selasky static const uint8_t midi_desc_raw_5[9] = { 1590a76fe7cSHans Petter Selasky 0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x00 1600a76fe7cSHans Petter Selasky }; 1610a76fe7cSHans Petter Selasky 1620a76fe7cSHans Petter Selasky static const void *midi_descs_1[] = { 1630a76fe7cSHans Petter Selasky &midi_desc_raw_1, 1640a76fe7cSHans Petter Selasky &midi_desc_raw_2, 1650a76fe7cSHans Petter Selasky &midi_desc_raw_3, 1660a76fe7cSHans Petter Selasky &midi_desc_raw_4, 1670a76fe7cSHans Petter Selasky &midi_desc_raw_5, 1680a76fe7cSHans Petter Selasky NULL 1690a76fe7cSHans Petter Selasky }; 1700a76fe7cSHans Petter Selasky 1710a76fe7cSHans Petter Selasky static const struct usb_temp_interface_desc midi_iface_1 = { 1720a76fe7cSHans Petter Selasky .ppRawDesc = midi_descs_1, 1730a76fe7cSHans Petter Selasky .ppEndpoints = midi_iface_1_ep, 174*4ffeccf1SEdward Tomasz Napierala .bInterfaceClass = UICLASS_AUDIO, 175*4ffeccf1SEdward Tomasz Napierala .bInterfaceSubClass = UISUBCLASS_MIDISTREAM, 1760a76fe7cSHans Petter Selasky .bInterfaceProtocol = 0, 1770a76fe7cSHans Petter Selasky .iInterface = INDEX_MIDI_IF, 1780a76fe7cSHans Petter Selasky }; 1790a76fe7cSHans Petter Selasky 1800a76fe7cSHans Petter Selasky static const struct usb_temp_interface_desc *midi_interfaces[] = { 1810a76fe7cSHans Petter Selasky &midi_iface_0, 1820a76fe7cSHans Petter Selasky &midi_iface_1, 1830a76fe7cSHans Petter Selasky NULL, 1840a76fe7cSHans Petter Selasky }; 1850a76fe7cSHans Petter Selasky 1860a76fe7cSHans Petter Selasky static const struct usb_temp_config_desc midi_config_desc = { 1870a76fe7cSHans Petter Selasky .ppIfaceDesc = midi_interfaces, 1880a76fe7cSHans Petter Selasky .bmAttributes = UC_BUS_POWERED, 1890a76fe7cSHans Petter Selasky .bMaxPower = 25, /* 50 mA */ 1900a76fe7cSHans Petter Selasky .iConfiguration = INDEX_MIDI_PRODUCT, 1910a76fe7cSHans Petter Selasky }; 1920a76fe7cSHans Petter Selasky 1930a76fe7cSHans Petter Selasky static const struct usb_temp_config_desc *midi_configs[] = { 1940a76fe7cSHans Petter Selasky &midi_config_desc, 1950a76fe7cSHans Petter Selasky NULL, 1960a76fe7cSHans Petter Selasky }; 1970a76fe7cSHans Petter Selasky 1980a76fe7cSHans Petter Selasky static usb_temp_get_string_desc_t midi_get_string_desc; 1990a76fe7cSHans Petter Selasky 2000a76fe7cSHans Petter Selasky const struct usb_temp_device_desc usb_template_midi = { 2010a76fe7cSHans Petter Selasky .getStringDesc = &midi_get_string_desc, 2020a76fe7cSHans Petter Selasky .ppConfigDesc = midi_configs, 2030a76fe7cSHans Petter Selasky .idVendor = USB_TEMPLATE_VENDOR, 2040a76fe7cSHans Petter Selasky .idProduct = 0x00BB, 2050a76fe7cSHans Petter Selasky .bcdDevice = 0x0100, 2060a76fe7cSHans Petter Selasky .bDeviceClass = 0, 2070a76fe7cSHans Petter Selasky .bDeviceSubClass = 0, 2080a76fe7cSHans Petter Selasky .bDeviceProtocol = 0, 2090a76fe7cSHans Petter Selasky .iManufacturer = 0, 2100a76fe7cSHans Petter Selasky .iProduct = INDEX_MIDI_PRODUCT, 2110a76fe7cSHans Petter Selasky .iSerialNumber = 0, 2120a76fe7cSHans Petter Selasky }; 2130a76fe7cSHans Petter Selasky 2140a76fe7cSHans Petter Selasky /*------------------------------------------------------------------------* 2150a76fe7cSHans Petter Selasky * midi_get_string_desc 2160a76fe7cSHans Petter Selasky * 2170a76fe7cSHans Petter Selasky * Return values: 2180a76fe7cSHans Petter Selasky * NULL: Failure. No such string. 2190a76fe7cSHans Petter Selasky * Else: Success. Pointer to string descriptor is returned. 2200a76fe7cSHans Petter Selasky *------------------------------------------------------------------------*/ 2210a76fe7cSHans Petter Selasky static const void * 2220a76fe7cSHans Petter Selasky midi_get_string_desc(uint16_t lang_id, uint8_t string_index) 2230a76fe7cSHans Petter Selasky { 2240a76fe7cSHans Petter Selasky static const void *ptr[INDEX_MIDI_MAX] = { 2250a76fe7cSHans Petter Selasky [INDEX_MIDI_LANG] = &usb_string_lang_en, 2260a76fe7cSHans Petter Selasky [INDEX_MIDI_IF] = &string_midi_if, 2270a76fe7cSHans Petter Selasky [INDEX_MIDI_PRODUCT] = &string_midi_product, 2280a76fe7cSHans Petter Selasky }; 2290a76fe7cSHans Petter Selasky 2300a76fe7cSHans Petter Selasky if (string_index == 0) { 2310a76fe7cSHans Petter Selasky return (&usb_string_lang_en); 2320a76fe7cSHans Petter Selasky } 2330a76fe7cSHans Petter Selasky if (lang_id != 0x0409) { 2340a76fe7cSHans Petter Selasky return (NULL); 2350a76fe7cSHans Petter Selasky } 2360a76fe7cSHans Petter Selasky if (string_index < INDEX_MIDI_MAX) { 2370a76fe7cSHans Petter Selasky return (ptr[string_index]); 2380a76fe7cSHans Petter Selasky } 2390a76fe7cSHans Petter Selasky return (NULL); 2400a76fe7cSHans Petter Selasky } 241