102ac6454SAndrew Thompson #include <sys/cdefs.h> 202ac6454SAndrew Thompson __FBSDID("$FreeBSD$"); 302ac6454SAndrew Thompson 402ac6454SAndrew Thompson /*- 55d38a4d4SEd Schouten * Copyright (c) 2008 Hans Petter Selasky <hselasky@FreeBSD.org> 602ac6454SAndrew Thompson * All rights reserved. 702ac6454SAndrew Thompson * 802ac6454SAndrew Thompson * Redistribution and use in source and binary forms, with or without 902ac6454SAndrew Thompson * modification, are permitted provided that the following conditions 1002ac6454SAndrew Thompson * are met: 1102ac6454SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 1202ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer. 1302ac6454SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 1402ac6454SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 1502ac6454SAndrew Thompson * documentation and/or other materials provided with the distribution. 1602ac6454SAndrew Thompson * 1702ac6454SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1802ac6454SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1902ac6454SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2002ac6454SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2102ac6454SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2202ac6454SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2302ac6454SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2402ac6454SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2502ac6454SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2602ac6454SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2702ac6454SAndrew Thompson * SUCH DAMAGE. 2802ac6454SAndrew Thompson */ 2902ac6454SAndrew Thompson 3002ac6454SAndrew Thompson /* 3102ac6454SAndrew Thompson * This file contains the USB templates for an USB Message Transfer 3202ac6454SAndrew Thompson * Protocol device. 3302ac6454SAndrew Thompson * 3402ac6454SAndrew Thompson * NOTE: It is common practice that MTP devices use some dummy 3502ac6454SAndrew Thompson * descriptor cludges to be automatically detected by the host 3602ac6454SAndrew Thompson * operating system. These descriptors are documented in the LibMTP 3702ac6454SAndrew Thompson * library at sourceforge.net. The alternative is to supply the host 3802ac6454SAndrew Thompson * operating system the VID and PID of your device. 3902ac6454SAndrew Thompson */ 4002ac6454SAndrew Thompson 4102ac6454SAndrew Thompson #include <dev/usb/usb.h> 4202ac6454SAndrew Thompson #include <dev/usb/usb_mfunc.h> 4302ac6454SAndrew Thompson 4402ac6454SAndrew Thompson #include <dev/usb/usb_core.h> 4502ac6454SAndrew Thompson 4602ac6454SAndrew Thompson #include <dev/usb/template/usb_template.h> 4702ac6454SAndrew Thompson 4802ac6454SAndrew Thompson #define MTP_BREQUEST 0x08 4902ac6454SAndrew Thompson 5002ac6454SAndrew Thompson enum { 5102ac6454SAndrew Thompson STRING_LANG_INDEX, 5202ac6454SAndrew Thompson STRING_MTP_DATA_INDEX, 5302ac6454SAndrew Thompson STRING_MTP_CONFIG_INDEX, 5402ac6454SAndrew Thompson STRING_MTP_VENDOR_INDEX, 5502ac6454SAndrew Thompson STRING_MTP_PRODUCT_INDEX, 5602ac6454SAndrew Thompson STRING_MTP_SERIAL_INDEX, 5702ac6454SAndrew Thompson STRING_MTP_MAX, 5802ac6454SAndrew Thompson }; 5902ac6454SAndrew Thompson 6002ac6454SAndrew Thompson #define STRING_LANG \ 6102ac6454SAndrew Thompson 0x09, 0x04, /* American English */ 6202ac6454SAndrew Thompson 6302ac6454SAndrew Thompson #define STRING_MTP_DATA \ 6402ac6454SAndrew Thompson 'U', 0, 'S', 0, 'B', 0, ' ', 0, \ 6502ac6454SAndrew Thompson 'M', 0, 'T', 0, 'P', 0, \ 6602ac6454SAndrew Thompson ' ', 0, 'I', 0, 'n', 0, 't', 0, \ 6702ac6454SAndrew Thompson 'e', 0, 'r', 0, 'f', 0, 'a', 0, \ 6802ac6454SAndrew Thompson 'c', 0, 'e', 0, 6902ac6454SAndrew Thompson 7002ac6454SAndrew Thompson #define STRING_MTP_CONFIG \ 7102ac6454SAndrew Thompson 'D', 0, 'e', 0, 'f', 0, 'a', 0, \ 7202ac6454SAndrew Thompson 'u', 0, 'l', 0, 't', 0, ' ', 0, \ 7302ac6454SAndrew Thompson 'c', 0, 'o', 0, 'n', 0, 'f', 0, \ 7402ac6454SAndrew Thompson 'i', 0, 'g', 0, 7502ac6454SAndrew Thompson 7602ac6454SAndrew Thompson #define STRING_MTP_VENDOR \ 7702ac6454SAndrew Thompson 'F', 0, 'r', 0, 'e', 0, 'e', 0, \ 7802ac6454SAndrew Thompson 'B', 0, 'S', 0, 'D', 0, ' ', 0, \ 7902ac6454SAndrew Thompson 'f', 0, 'o', 0, 'u', 0, 'n', 0, \ 8002ac6454SAndrew Thompson 'd', 0, 'a', 0, 't', 0, 'i', 0, \ 8102ac6454SAndrew Thompson 'o', 0, 'n', 0, 8202ac6454SAndrew Thompson 8302ac6454SAndrew Thompson #define STRING_MTP_PRODUCT \ 8402ac6454SAndrew Thompson 'U', 0, 'S', 0, 'B', 0, ' ', 0, \ 8502ac6454SAndrew Thompson 'M', 0, 'T', 0, 'P', 0, 8602ac6454SAndrew Thompson 8702ac6454SAndrew Thompson #define STRING_MTP_SERIAL \ 8802ac6454SAndrew Thompson 'J', 0, 'u', 0, 'n', 0, 'e', 0, \ 8902ac6454SAndrew Thompson ' ', 0, '2', 0, '0', 0, '0', 0, \ 9002ac6454SAndrew Thompson '8', 0, 9102ac6454SAndrew Thompson 9202ac6454SAndrew Thompson /* make the real string descriptors */ 9302ac6454SAndrew Thompson 9402ac6454SAndrew Thompson USB_MAKE_STRING_DESC(STRING_LANG, string_lang); 9502ac6454SAndrew Thompson USB_MAKE_STRING_DESC(STRING_MTP_DATA, string_mtp_data); 9602ac6454SAndrew Thompson USB_MAKE_STRING_DESC(STRING_MTP_CONFIG, string_mtp_config); 9702ac6454SAndrew Thompson USB_MAKE_STRING_DESC(STRING_MTP_VENDOR, string_mtp_vendor); 9802ac6454SAndrew Thompson USB_MAKE_STRING_DESC(STRING_MTP_PRODUCT, string_mtp_product); 9902ac6454SAndrew Thompson USB_MAKE_STRING_DESC(STRING_MTP_SERIAL, string_mtp_serial); 10002ac6454SAndrew Thompson 10102ac6454SAndrew Thompson /* prototypes */ 10202ac6454SAndrew Thompson 10302ac6454SAndrew Thompson static usb2_temp_get_string_desc_t mtp_get_string_desc; 10402ac6454SAndrew Thompson static usb2_temp_get_vendor_desc_t mtp_get_vendor_desc; 10502ac6454SAndrew Thompson 106760bc48eSAndrew Thompson static const struct usb_temp_packet_size bulk_mps = { 10702ac6454SAndrew Thompson .mps[USB_SPEED_FULL] = 64, 10802ac6454SAndrew Thompson .mps[USB_SPEED_HIGH] = 512, 10902ac6454SAndrew Thompson }; 11002ac6454SAndrew Thompson 111760bc48eSAndrew Thompson static const struct usb_temp_packet_size intr_mps = { 11202ac6454SAndrew Thompson .mps[USB_SPEED_FULL] = 64, 11302ac6454SAndrew Thompson .mps[USB_SPEED_HIGH] = 64, 11402ac6454SAndrew Thompson }; 11502ac6454SAndrew Thompson 116760bc48eSAndrew Thompson static const struct usb_temp_endpoint_desc bulk_out_ep = { 11702ac6454SAndrew Thompson .pPacketSize = &bulk_mps, 11802ac6454SAndrew Thompson #ifdef USB_HIP_OUT_EP_0 11902ac6454SAndrew Thompson .bEndpointAddress = USB_HIP_OUT_EP_0, 12002ac6454SAndrew Thompson #else 12102ac6454SAndrew Thompson .bEndpointAddress = UE_DIR_OUT, 12202ac6454SAndrew Thompson #endif 12302ac6454SAndrew Thompson .bmAttributes = UE_BULK, 12402ac6454SAndrew Thompson }; 12502ac6454SAndrew Thompson 126760bc48eSAndrew Thompson static const struct usb_temp_endpoint_desc intr_in_ep = { 12702ac6454SAndrew Thompson .pPacketSize = &intr_mps, 12802ac6454SAndrew Thompson .bEndpointAddress = UE_DIR_IN, 12902ac6454SAndrew Thompson .bmAttributes = UE_INTERRUPT, 13002ac6454SAndrew Thompson }; 13102ac6454SAndrew Thompson 132760bc48eSAndrew Thompson static const struct usb_temp_endpoint_desc bulk_in_ep = { 13302ac6454SAndrew Thompson .pPacketSize = &bulk_mps, 13402ac6454SAndrew Thompson #ifdef USB_HIP_IN_EP_0 13502ac6454SAndrew Thompson .bEndpointAddress = USB_HIP_IN_EP_0, 13602ac6454SAndrew Thompson #else 13702ac6454SAndrew Thompson .bEndpointAddress = UE_DIR_IN, 13802ac6454SAndrew Thompson #endif 13902ac6454SAndrew Thompson .bmAttributes = UE_BULK, 14002ac6454SAndrew Thompson }; 14102ac6454SAndrew Thompson 142760bc48eSAndrew Thompson static const struct usb_temp_endpoint_desc *mtp_data_endpoints[] = { 14302ac6454SAndrew Thompson &bulk_in_ep, 14402ac6454SAndrew Thompson &bulk_out_ep, 14502ac6454SAndrew Thompson &intr_in_ep, 14602ac6454SAndrew Thompson NULL, 14702ac6454SAndrew Thompson }; 14802ac6454SAndrew Thompson 149760bc48eSAndrew Thompson static const struct usb_temp_interface_desc mtp_data_interface = { 15002ac6454SAndrew Thompson .ppEndpoints = mtp_data_endpoints, 15102ac6454SAndrew Thompson .bInterfaceClass = UICLASS_IMAGE, 15202ac6454SAndrew Thompson .bInterfaceSubClass = UISUBCLASS_SIC, /* Still Image Class */ 15302ac6454SAndrew Thompson .bInterfaceProtocol = 1, /* PIMA 15740 */ 15402ac6454SAndrew Thompson .iInterface = STRING_MTP_DATA_INDEX, 15502ac6454SAndrew Thompson }; 15602ac6454SAndrew Thompson 157760bc48eSAndrew Thompson static const struct usb_temp_interface_desc *mtp_interfaces[] = { 15802ac6454SAndrew Thompson &mtp_data_interface, 15902ac6454SAndrew Thompson NULL, 16002ac6454SAndrew Thompson }; 16102ac6454SAndrew Thompson 162760bc48eSAndrew Thompson static const struct usb_temp_config_desc mtp_config_desc = { 16302ac6454SAndrew Thompson .ppIfaceDesc = mtp_interfaces, 16402ac6454SAndrew Thompson .bmAttributes = UC_BUS_POWERED, 16502ac6454SAndrew Thompson .bMaxPower = 25, /* 50 mA */ 16602ac6454SAndrew Thompson .iConfiguration = STRING_MTP_CONFIG_INDEX, 16702ac6454SAndrew Thompson }; 16802ac6454SAndrew Thompson 169760bc48eSAndrew Thompson static const struct usb_temp_config_desc *mtp_configs[] = { 17002ac6454SAndrew Thompson &mtp_config_desc, 17102ac6454SAndrew Thompson NULL, 17202ac6454SAndrew Thompson }; 17302ac6454SAndrew Thompson 174760bc48eSAndrew Thompson const struct usb_temp_device_desc usb2_template_mtp = { 17502ac6454SAndrew Thompson .getStringDesc = &mtp_get_string_desc, 17602ac6454SAndrew Thompson .getVendorDesc = &mtp_get_vendor_desc, 17702ac6454SAndrew Thompson .ppConfigDesc = mtp_configs, 17802ac6454SAndrew Thompson .idVendor = 0x0001, 17902ac6454SAndrew Thompson .idProduct = 0x0001, 18002ac6454SAndrew Thompson .bcdDevice = 0x0100, 18102ac6454SAndrew Thompson .bDeviceClass = 0, 18202ac6454SAndrew Thompson .bDeviceSubClass = 0, 18302ac6454SAndrew Thompson .bDeviceProtocol = 0, 18402ac6454SAndrew Thompson .iManufacturer = STRING_MTP_VENDOR_INDEX, 18502ac6454SAndrew Thompson .iProduct = STRING_MTP_PRODUCT_INDEX, 18602ac6454SAndrew Thompson .iSerialNumber = STRING_MTP_SERIAL_INDEX, 18702ac6454SAndrew Thompson }; 18802ac6454SAndrew Thompson 18902ac6454SAndrew Thompson /*------------------------------------------------------------------------* 19002ac6454SAndrew Thompson * mtp_get_vendor_desc 19102ac6454SAndrew Thompson * 19202ac6454SAndrew Thompson * Return values: 19302ac6454SAndrew Thompson * NULL: Failure. No such vendor descriptor. 19402ac6454SAndrew Thompson * Else: Success. Pointer to vendor descriptor is returned. 19502ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 19602ac6454SAndrew Thompson static const void * 197760bc48eSAndrew Thompson mtp_get_vendor_desc(const struct usb_device_request *req) 19802ac6454SAndrew Thompson { 19902ac6454SAndrew Thompson static const uint8_t dummy_desc[0x28] = { 20002ac6454SAndrew Thompson 0x28, 0, 0, 0, 0, 1, 4, 0, 20102ac6454SAndrew Thompson 1, 0, 0, 0, 0, 0, 0, 0, 20202ac6454SAndrew Thompson 0, 1, 0x4D, 0x54, 0x50, 0, 0, 0, 20302ac6454SAndrew Thompson 0, 0, 0, 0, 0, 0, 0, 0, 20402ac6454SAndrew Thompson 0, 0, 0, 0, 0, 0, 0, 0, 20502ac6454SAndrew Thompson }; 20602ac6454SAndrew Thompson 20702ac6454SAndrew Thompson if ((req->bmRequestType == UT_READ_VENDOR_DEVICE) && 20802ac6454SAndrew Thompson (req->bRequest == MTP_BREQUEST) && (req->wValue[0] == 0) && 20902ac6454SAndrew Thompson (req->wValue[1] == 0) && (req->wIndex[1] == 0) && 21002ac6454SAndrew Thompson ((req->wIndex[0] == 4) || (req->wIndex[0] == 5))) { 21102ac6454SAndrew Thompson /* 21202ac6454SAndrew Thompson * By returning this descriptor LibMTP will 21302ac6454SAndrew Thompson * automatically pickup our device. 21402ac6454SAndrew Thompson */ 21502ac6454SAndrew Thompson return (dummy_desc); 21602ac6454SAndrew Thompson } 21702ac6454SAndrew Thompson return (NULL); 21802ac6454SAndrew Thompson } 21902ac6454SAndrew Thompson 22002ac6454SAndrew Thompson /*------------------------------------------------------------------------* 22102ac6454SAndrew Thompson * mtp_get_string_desc 22202ac6454SAndrew Thompson * 22302ac6454SAndrew Thompson * Return values: 22402ac6454SAndrew Thompson * NULL: Failure. No such string. 22502ac6454SAndrew Thompson * Else: Success. Pointer to string descriptor is returned. 22602ac6454SAndrew Thompson *------------------------------------------------------------------------*/ 22702ac6454SAndrew Thompson static const void * 22802ac6454SAndrew Thompson mtp_get_string_desc(uint16_t lang_id, uint8_t string_index) 22902ac6454SAndrew Thompson { 23002ac6454SAndrew Thompson static const void *ptr[STRING_MTP_MAX] = { 23102ac6454SAndrew Thompson [STRING_LANG_INDEX] = &string_lang, 23202ac6454SAndrew Thompson [STRING_MTP_DATA_INDEX] = &string_mtp_data, 23302ac6454SAndrew Thompson [STRING_MTP_CONFIG_INDEX] = &string_mtp_config, 23402ac6454SAndrew Thompson [STRING_MTP_VENDOR_INDEX] = &string_mtp_vendor, 23502ac6454SAndrew Thompson [STRING_MTP_PRODUCT_INDEX] = &string_mtp_product, 23602ac6454SAndrew Thompson [STRING_MTP_SERIAL_INDEX] = &string_mtp_serial, 23702ac6454SAndrew Thompson }; 23802ac6454SAndrew Thompson 23902ac6454SAndrew Thompson static const uint8_t dummy_desc[0x12] = { 24002ac6454SAndrew Thompson 0x12, 0x03, 0x4D, 0x00, 0x53, 0x00, 0x46, 0x00, 24102ac6454SAndrew Thompson 0x54, 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 24202ac6454SAndrew Thompson MTP_BREQUEST, 0x00, 24302ac6454SAndrew Thompson }; 24402ac6454SAndrew Thompson 24502ac6454SAndrew Thompson if (string_index == 0xEE) { 24602ac6454SAndrew Thompson /* 24702ac6454SAndrew Thompson * By returning this string LibMTP will automatically 24802ac6454SAndrew Thompson * pickup our device. 24902ac6454SAndrew Thompson */ 25002ac6454SAndrew Thompson return (dummy_desc); 25102ac6454SAndrew Thompson } 25202ac6454SAndrew Thompson if (string_index == 0) { 25302ac6454SAndrew Thompson return (&string_lang); 25402ac6454SAndrew Thompson } 25502ac6454SAndrew Thompson if (lang_id != 0x0409) { 25602ac6454SAndrew Thompson return (NULL); 25702ac6454SAndrew Thompson } 25802ac6454SAndrew Thompson if (string_index < STRING_MTP_MAX) { 25902ac6454SAndrew Thompson return (ptr[string_index]); 26002ac6454SAndrew Thompson } 26102ac6454SAndrew Thompson return (NULL); 26202ac6454SAndrew Thompson } 263