xref: /freebsd/sys/dev/usb/template/usb_template_phone.c (revision 71625ec9ad2a9bc8c09784fbd23b759830e0ee5f)
1f9478f91SHans Petter Selasky /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
342e42a9aSEdward Tomasz Napierala  *
48e06491aSEdward Tomasz Napierala  * Copyright (c) 2014 Hans Petter Selasky
58e06491aSEdward Tomasz Napierala  * Copyright (c) 2018 The FreeBSD Foundation
68e06491aSEdward Tomasz Napierala  * All rights reserved.
78e06491aSEdward Tomasz Napierala  *
88e06491aSEdward Tomasz Napierala  * Portions of this software were developed by Edward Tomasz Napierala
98e06491aSEdward Tomasz Napierala  * under sponsorship from the FreeBSD Foundation.
10f9478f91SHans Petter Selasky  *
11f9478f91SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
12f9478f91SHans Petter Selasky  * modification, are permitted provided that the following conditions
13f9478f91SHans Petter Selasky  * are met:
14f9478f91SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
15f9478f91SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
16f9478f91SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
17f9478f91SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
18f9478f91SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
19f9478f91SHans Petter Selasky  *
20f9478f91SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21f9478f91SHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22f9478f91SHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23f9478f91SHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24f9478f91SHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25f9478f91SHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26f9478f91SHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27f9478f91SHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28f9478f91SHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29f9478f91SHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30f9478f91SHans Petter Selasky  * SUCH DAMAGE.
31f9478f91SHans Petter Selasky  */
32f9478f91SHans Petter Selasky 
33f9478f91SHans Petter Selasky /*
34f9478f91SHans Petter Selasky  * This file contains the USB template for an USB phone device.
35f9478f91SHans Petter Selasky  */
36f9478f91SHans Petter Selasky 
37f9478f91SHans Petter Selasky #ifdef USB_GLOBAL_INCLUDE_FILE
38f9478f91SHans Petter Selasky #include USB_GLOBAL_INCLUDE_FILE
39f9478f91SHans Petter Selasky #else
40f9478f91SHans Petter Selasky #include <sys/stdint.h>
41f9478f91SHans Petter Selasky #include <sys/stddef.h>
42f9478f91SHans Petter Selasky #include <sys/param.h>
43f9478f91SHans Petter Selasky #include <sys/queue.h>
44f9478f91SHans Petter Selasky #include <sys/types.h>
45f9478f91SHans Petter Selasky #include <sys/systm.h>
46f9478f91SHans Petter Selasky #include <sys/kernel.h>
47f9478f91SHans Petter Selasky #include <sys/bus.h>
48f9478f91SHans Petter Selasky #include <sys/module.h>
49f9478f91SHans Petter Selasky #include <sys/lock.h>
50f9478f91SHans Petter Selasky #include <sys/mutex.h>
51f9478f91SHans Petter Selasky #include <sys/condvar.h>
52f9478f91SHans Petter Selasky #include <sys/sysctl.h>
53f9478f91SHans Petter Selasky #include <sys/sx.h>
54f9478f91SHans Petter Selasky #include <sys/unistd.h>
55f9478f91SHans Petter Selasky #include <sys/callout.h>
56f9478f91SHans Petter Selasky #include <sys/malloc.h>
57f9478f91SHans Petter Selasky #include <sys/priv.h>
58f9478f91SHans Petter Selasky 
59f9478f91SHans Petter Selasky #include <dev/usb/usb.h>
60f9478f91SHans Petter Selasky #include <dev/usb/usbdi.h>
61f9478f91SHans Petter Selasky #include <dev/usb/usb_core.h>
62f9478f91SHans Petter Selasky #include <dev/usb/usb_cdc.h>
638e06491aSEdward Tomasz Napierala #include <dev/usb/usb_ioctl.h>
648e06491aSEdward Tomasz Napierala #include <dev/usb/usb_util.h>
65f9478f91SHans Petter Selasky 
66f9478f91SHans Petter Selasky #include <dev/usb/template/usb_template.h>
67f9478f91SHans Petter Selasky #endif			/* USB_GLOBAL_INCLUDE_FILE */
68f9478f91SHans Petter Selasky 
69f9478f91SHans Petter Selasky enum {
708e06491aSEdward Tomasz Napierala 	PHONE_LANG_INDEX,
718e06491aSEdward Tomasz Napierala 	PHONE_MIXER_INDEX,
728e06491aSEdward Tomasz Napierala 	PHONE_RECORD_INDEX,
738e06491aSEdward Tomasz Napierala 	PHONE_PLAYBACK_INDEX,
748e06491aSEdward Tomasz Napierala 	PHONE_HID_INDEX,
751ee5bed7SEdward Tomasz Napierala 	PHONE_MANUFACTURER_INDEX,
761ee5bed7SEdward Tomasz Napierala 	PHONE_PRODUCT_INDEX,
771ee5bed7SEdward Tomasz Napierala 	PHONE_SERIAL_NUMBER_INDEX,
788e06491aSEdward Tomasz Napierala 	PHONE_MAX_INDEX,
79f9478f91SHans Petter Selasky };
80f9478f91SHans Petter Selasky 
811558eec6SEdward Tomasz Napierala #define	PHONE_DEFAULT_VENDOR_ID		USB_TEMPLATE_VENDOR
82d01c1c8bSEdward Tomasz Napierala #define	PHONE_DEFAULT_PRODUCT_ID	0x05dc
838e06491aSEdward Tomasz Napierala #define	PHONE_DEFAULT_MIXER		"Mixer interface"
848e06491aSEdward Tomasz Napierala #define	PHONE_DEFAULT_RECORD		"Record interface"
858e06491aSEdward Tomasz Napierala #define	PHONE_DEFAULT_PLAYBACK		"Playback interface"
868e06491aSEdward Tomasz Napierala #define	PHONE_DEFAULT_HID		"HID interface"
87d01c1c8bSEdward Tomasz Napierala #define	PHONE_DEFAULT_MANUFACTURER	USB_TEMPLATE_MANUFACTURER
881ee5bed7SEdward Tomasz Napierala #define	PHONE_DEFAULT_PRODUCT		"USB Phone Device"
891ee5bed7SEdward Tomasz Napierala #define	PHONE_DEFAULT_SERIAL_NUMBER	"March 2008"
90f9478f91SHans Petter Selasky 
918e06491aSEdward Tomasz Napierala static struct usb_string_descriptor	phone_mixer;
928e06491aSEdward Tomasz Napierala static struct usb_string_descriptor	phone_record;
938e06491aSEdward Tomasz Napierala static struct usb_string_descriptor	phone_playback;
948e06491aSEdward Tomasz Napierala static struct usb_string_descriptor	phone_hid;
951ee5bed7SEdward Tomasz Napierala static struct usb_string_descriptor	phone_manufacturer;
961ee5bed7SEdward Tomasz Napierala static struct usb_string_descriptor	phone_product;
971ee5bed7SEdward Tomasz Napierala static struct usb_string_descriptor	phone_serial_number;
98f9478f91SHans Petter Selasky 
998e06491aSEdward Tomasz Napierala static struct sysctl_ctx_list		phone_ctx_list;
100f9478f91SHans Petter Selasky 
101f9478f91SHans Petter Selasky /* prototypes */
102f9478f91SHans Petter Selasky 
103f9478f91SHans Petter Selasky /*
104f9478f91SHans Petter Selasky  * Phone Mixer description structures
105f9478f91SHans Petter Selasky  *
106f9478f91SHans Petter Selasky  * Some of the phone descriptors were dumped from no longer in
107f9478f91SHans Petter Selasky  * production Yealink VOIP USB phone adapter:
108f9478f91SHans Petter Selasky  */
109f9478f91SHans Petter Selasky static uint8_t phone_hid_descriptor[] = {
110f9478f91SHans Petter Selasky 	0x05, 0x0b, 0x09, 0x01, 0xa1, 0x01, 0x05, 0x09,
111f9478f91SHans Petter Selasky 	0x19, 0x01, 0x29, 0x3f, 0x15, 0x00, 0x25, 0x01,
112f9478f91SHans Petter Selasky 	0x75, 0x01, 0x95, 0x80, 0x81, 0x00, 0x05, 0x08,
113f9478f91SHans Petter Selasky 	0x19, 0x01, 0x29, 0x10, 0x15, 0x00, 0x25, 0x01,
114f9478f91SHans Petter Selasky 	0x75, 0x01, 0x95, 0x80, 0x91, 0x00, 0xc0
115f9478f91SHans Petter Selasky };
116f9478f91SHans Petter Selasky 
117f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_0[] = {
118f9478f91SHans Petter Selasky 	0x0a, 0x24, 0x01, 0x00, 0x01, 0x4a, 0x00, 0x02,
119f9478f91SHans Petter Selasky 	0x01, 0x02
120f9478f91SHans Petter Selasky };
121f9478f91SHans Petter Selasky 
122f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_1[] = {
123f9478f91SHans Petter Selasky 	0x0c, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00, 0x01,
124f9478f91SHans Petter Selasky 	0x00, 0x00, 0x00, 0x00
125f9478f91SHans Petter Selasky };
126f9478f91SHans Petter Selasky 
127f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_2[] = {
128f9478f91SHans Petter Selasky 	0x0c, 0x24, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01,
129f9478f91SHans Petter Selasky 	0x00, 0x00, 0x00, 0x00
130f9478f91SHans Petter Selasky };
131f9478f91SHans Petter Selasky 
132f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_3[] = {
133f9478f91SHans Petter Selasky 	0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x06,
134f9478f91SHans Petter Selasky 	0x00
135f9478f91SHans Petter Selasky };
136f9478f91SHans Petter Selasky 
137f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_4[] = {
138f9478f91SHans Petter Selasky 	0x09, 0x24, 0x03, 0x04, 0x01, 0x01, 0x00, 0x05,
139f9478f91SHans Petter Selasky 	0x00
140f9478f91SHans Petter Selasky };
141f9478f91SHans Petter Selasky 
142f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_5[] = {
143f9478f91SHans Petter Selasky 	0x0b, 0x24, 0x06, 0x05, 0x01, 0x02, 0x03, 0x00,
144f9478f91SHans Petter Selasky 	0x03, 0x00, 0x00
145f9478f91SHans Petter Selasky };
146f9478f91SHans Petter Selasky 
147f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_6[] = {
148f9478f91SHans Petter Selasky 	0x0b, 0x24, 0x06, 0x06, 0x02, 0x02, 0x03, 0x00,
149f9478f91SHans Petter Selasky 	0x03, 0x00, 0x00
150f9478f91SHans Petter Selasky };
151f9478f91SHans Petter Selasky 
152f9478f91SHans Petter Selasky static const void *phone_raw_iface_0_desc[] = {
153f9478f91SHans Petter Selasky 	phone_raw_desc_0,
154f9478f91SHans Petter Selasky 	phone_raw_desc_1,
155f9478f91SHans Petter Selasky 	phone_raw_desc_2,
156f9478f91SHans Petter Selasky 	phone_raw_desc_3,
157f9478f91SHans Petter Selasky 	phone_raw_desc_4,
158f9478f91SHans Petter Selasky 	phone_raw_desc_5,
159f9478f91SHans Petter Selasky 	phone_raw_desc_6,
160f9478f91SHans Petter Selasky 	NULL,
161f9478f91SHans Petter Selasky };
162f9478f91SHans Petter Selasky 
163f9478f91SHans Petter Selasky static const struct usb_temp_interface_desc phone_iface_0 = {
164f9478f91SHans Petter Selasky 	.ppEndpoints = NULL,		/* no endpoints */
165f9478f91SHans Petter Selasky 	.ppRawDesc = phone_raw_iface_0_desc,
1664ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
1674ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
168f9478f91SHans Petter Selasky 	.bInterfaceProtocol = 0,
1698e06491aSEdward Tomasz Napierala 	.iInterface = PHONE_MIXER_INDEX,
170f9478f91SHans Petter Selasky };
171f9478f91SHans Petter Selasky 
172f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_20[] = {
173f9478f91SHans Petter Selasky 	0x07, 0x24, 0x01, 0x04, 0x01, 0x01, 0x00
174f9478f91SHans Petter Selasky };
175f9478f91SHans Petter Selasky 
176f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_21[] = {
177f9478f91SHans Petter Selasky 	0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
178f9478f91SHans Petter Selasky 	/* 8kHz */
179f9478f91SHans Petter Selasky 	0x40, 0x1f, 0x00
180f9478f91SHans Petter Selasky };
181f9478f91SHans Petter Selasky 
182f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_22[] = {
183f9478f91SHans Petter Selasky 	0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
184f9478f91SHans Petter Selasky };
185f9478f91SHans Petter Selasky 
186f9478f91SHans Petter Selasky static const void *phone_raw_iface_1_desc[] = {
187f9478f91SHans Petter Selasky 	phone_raw_desc_20,
188f9478f91SHans Petter Selasky 	phone_raw_desc_21,
189f9478f91SHans Petter Selasky 	NULL,
190f9478f91SHans Petter Selasky };
191f9478f91SHans Petter Selasky 
192f9478f91SHans Petter Selasky static const void *phone_raw_ep_1_desc[] = {
193f9478f91SHans Petter Selasky 	phone_raw_desc_22,
194f9478f91SHans Petter Selasky 	NULL,
195f9478f91SHans Petter Selasky };
196f9478f91SHans Petter Selasky 
197f9478f91SHans Petter Selasky static const struct usb_temp_packet_size phone_isoc_mps = {
198f9478f91SHans Petter Selasky 	.mps[USB_SPEED_FULL] = 0x10,
199f9478f91SHans Petter Selasky 	.mps[USB_SPEED_HIGH] = 0x10,
200f9478f91SHans Petter Selasky };
201f9478f91SHans Petter Selasky 
202f9478f91SHans Petter Selasky static const struct usb_temp_interval phone_isoc_interval = {
203f9478f91SHans Petter Selasky 	.bInterval[USB_SPEED_FULL] = 1,	/* 1:1 */
204f9478f91SHans Petter Selasky 	.bInterval[USB_SPEED_HIGH] = 4,	/* 1:8 */
205f9478f91SHans Petter Selasky };
206f9478f91SHans Petter Selasky 
207f9478f91SHans Petter Selasky static const struct usb_temp_endpoint_desc phone_isoc_in_ep = {
208f9478f91SHans Petter Selasky 	.ppRawDesc = phone_raw_ep_1_desc,
209f9478f91SHans Petter Selasky 	.pPacketSize = &phone_isoc_mps,
210f9478f91SHans Petter Selasky 	.pIntervals = &phone_isoc_interval,
211f9478f91SHans Petter Selasky 	.bEndpointAddress = UE_DIR_IN,
212f9478f91SHans Petter Selasky 	.bmAttributes = UE_ISOCHRONOUS,
213f9478f91SHans Petter Selasky };
214f9478f91SHans Petter Selasky 
215f9478f91SHans Petter Selasky static const struct usb_temp_endpoint_desc *phone_iface_1_ep[] = {
216f9478f91SHans Petter Selasky 	&phone_isoc_in_ep,
217f9478f91SHans Petter Selasky 	NULL,
218f9478f91SHans Petter Selasky };
219f9478f91SHans Petter Selasky 
220f9478f91SHans Petter Selasky static const struct usb_temp_interface_desc phone_iface_1_alt_0 = {
221f9478f91SHans Petter Selasky 	.ppEndpoints = NULL,		/* no endpoints */
222f9478f91SHans Petter Selasky 	.ppRawDesc = NULL,		/* no raw descriptors */
2234ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
2244ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
225f9478f91SHans Petter Selasky 	.bInterfaceProtocol = 0,
2268e06491aSEdward Tomasz Napierala 	.iInterface = PHONE_PLAYBACK_INDEX,
227f9478f91SHans Petter Selasky };
228f9478f91SHans Petter Selasky 
229f9478f91SHans Petter Selasky static const struct usb_temp_interface_desc phone_iface_1_alt_1 = {
230f9478f91SHans Petter Selasky 	.ppEndpoints = phone_iface_1_ep,
231f9478f91SHans Petter Selasky 	.ppRawDesc = phone_raw_iface_1_desc,
2324ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
2334ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
234f9478f91SHans Petter Selasky 	.bInterfaceProtocol = 0,
2358e06491aSEdward Tomasz Napierala 	.iInterface = PHONE_PLAYBACK_INDEX,
236f9478f91SHans Petter Selasky 	.isAltInterface = 1,		/* this is an alternate setting */
237f9478f91SHans Petter Selasky };
238f9478f91SHans Petter Selasky 
239f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_30[] = {
240f9478f91SHans Petter Selasky 	0x07, 0x24, 0x01, 0x02, 0x01, 0x01, 0x00
241f9478f91SHans Petter Selasky };
242f9478f91SHans Petter Selasky 
243f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_31[] = {
244f9478f91SHans Petter Selasky 	0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
245f9478f91SHans Petter Selasky 	/* 8kHz */
246f9478f91SHans Petter Selasky 	0x40, 0x1f, 0x00
247f9478f91SHans Petter Selasky };
248f9478f91SHans Petter Selasky 
249f9478f91SHans Petter Selasky static const uint8_t phone_raw_desc_32[] = {
250f9478f91SHans Petter Selasky 	0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
251f9478f91SHans Petter Selasky };
252f9478f91SHans Petter Selasky 
253f9478f91SHans Petter Selasky static const void *phone_raw_iface_2_desc[] = {
254f9478f91SHans Petter Selasky 	phone_raw_desc_30,
255f9478f91SHans Petter Selasky 	phone_raw_desc_31,
256f9478f91SHans Petter Selasky 	NULL,
257f9478f91SHans Petter Selasky };
258f9478f91SHans Petter Selasky 
259f9478f91SHans Petter Selasky static const void *phone_raw_ep_2_desc[] = {
260f9478f91SHans Petter Selasky 	phone_raw_desc_32,
261f9478f91SHans Petter Selasky 	NULL,
262f9478f91SHans Petter Selasky };
263f9478f91SHans Petter Selasky 
264f9478f91SHans Petter Selasky static const struct usb_temp_endpoint_desc phone_isoc_out_ep = {
265f9478f91SHans Petter Selasky 	.ppRawDesc = phone_raw_ep_2_desc,
266f9478f91SHans Petter Selasky 	.pPacketSize = &phone_isoc_mps,
267f9478f91SHans Petter Selasky 	.pIntervals = &phone_isoc_interval,
268f9478f91SHans Petter Selasky 	.bEndpointAddress = UE_DIR_OUT,
269f9478f91SHans Petter Selasky 	.bmAttributes = UE_ISOCHRONOUS,
270f9478f91SHans Petter Selasky };
271f9478f91SHans Petter Selasky 
272f9478f91SHans Petter Selasky static const struct usb_temp_endpoint_desc *phone_iface_2_ep[] = {
273f9478f91SHans Petter Selasky 	&phone_isoc_out_ep,
274f9478f91SHans Petter Selasky 	NULL,
275f9478f91SHans Petter Selasky };
276f9478f91SHans Petter Selasky 
277f9478f91SHans Petter Selasky static const struct usb_temp_interface_desc phone_iface_2_alt_0 = {
278f9478f91SHans Petter Selasky 	.ppEndpoints = NULL,		/* no endpoints */
279f9478f91SHans Petter Selasky 	.ppRawDesc = NULL,		/* no raw descriptors */
2804ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
2814ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
282f9478f91SHans Petter Selasky 	.bInterfaceProtocol = 0,
2838e06491aSEdward Tomasz Napierala 	.iInterface = PHONE_RECORD_INDEX,
284f9478f91SHans Petter Selasky };
285f9478f91SHans Petter Selasky 
286f9478f91SHans Petter Selasky static const struct usb_temp_interface_desc phone_iface_2_alt_1 = {
287f9478f91SHans Petter Selasky 	.ppEndpoints = phone_iface_2_ep,
288f9478f91SHans Petter Selasky 	.ppRawDesc = phone_raw_iface_2_desc,
2894ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_AUDIO,
2904ffeccf1SEdward Tomasz Napierala 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
291f9478f91SHans Petter Selasky 	.bInterfaceProtocol = 0,
2928e06491aSEdward Tomasz Napierala 	.iInterface = PHONE_RECORD_INDEX,
293f9478f91SHans Petter Selasky 	.isAltInterface = 1,		/* this is an alternate setting */
294f9478f91SHans Petter Selasky };
295f9478f91SHans Petter Selasky 
296f9478f91SHans Petter Selasky static const uint8_t phone_hid_raw_desc_0[] = {
297f9478f91SHans Petter Selasky 	0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, sizeof(phone_hid_descriptor),
298f9478f91SHans Petter Selasky 	0x00
299f9478f91SHans Petter Selasky };
300f9478f91SHans Petter Selasky 
301f9478f91SHans Petter Selasky static const void *phone_hid_desc_0[] = {
302f9478f91SHans Petter Selasky 	phone_hid_raw_desc_0,
303f9478f91SHans Petter Selasky 	NULL,
304f9478f91SHans Petter Selasky };
305f9478f91SHans Petter Selasky 
306f9478f91SHans Petter Selasky static const struct usb_temp_packet_size phone_hid_mps = {
307f9478f91SHans Petter Selasky 	.mps[USB_SPEED_FULL] = 0x10,
308f9478f91SHans Petter Selasky 	.mps[USB_SPEED_HIGH] = 0x10,
309f9478f91SHans Petter Selasky };
310f9478f91SHans Petter Selasky 
311f9478f91SHans Petter Selasky static const struct usb_temp_interval phone_hid_interval = {
312f9478f91SHans Petter Selasky 	.bInterval[USB_SPEED_FULL] = 2,		/* 2ms */
313f9478f91SHans Petter Selasky 	.bInterval[USB_SPEED_HIGH] = 2,		/* 2ms */
314f9478f91SHans Petter Selasky };
315f9478f91SHans Petter Selasky 
316f9478f91SHans Petter Selasky static const struct usb_temp_endpoint_desc phone_hid_in_ep = {
317f9478f91SHans Petter Selasky 	.pPacketSize = &phone_hid_mps,
318f9478f91SHans Petter Selasky 	.pIntervals = &phone_hid_interval,
319f9478f91SHans Petter Selasky 	.bEndpointAddress = UE_DIR_IN,
320f9478f91SHans Petter Selasky 	.bmAttributes = UE_INTERRUPT,
321f9478f91SHans Petter Selasky };
322f9478f91SHans Petter Selasky 
323f9478f91SHans Petter Selasky static const struct usb_temp_endpoint_desc *phone_iface_3_ep[] = {
324f9478f91SHans Petter Selasky 	&phone_hid_in_ep,
325f9478f91SHans Petter Selasky 	NULL,
326f9478f91SHans Petter Selasky };
327f9478f91SHans Petter Selasky 
328f9478f91SHans Petter Selasky static const struct usb_temp_interface_desc phone_iface_3 = {
329f9478f91SHans Petter Selasky 	.ppEndpoints = phone_iface_3_ep,
330f9478f91SHans Petter Selasky 	.ppRawDesc = phone_hid_desc_0,
3314ffeccf1SEdward Tomasz Napierala 	.bInterfaceClass = UICLASS_HID,
332f9478f91SHans Petter Selasky 	.bInterfaceSubClass = 0,
333f9478f91SHans Petter Selasky 	.bInterfaceProtocol = 0,
3348e06491aSEdward Tomasz Napierala 	.iInterface = PHONE_HID_INDEX,
335f9478f91SHans Petter Selasky };
336f9478f91SHans Petter Selasky 
337f9478f91SHans Petter Selasky static const struct usb_temp_interface_desc *phone_interfaces[] = {
338f9478f91SHans Petter Selasky 	&phone_iface_0,
339f9478f91SHans Petter Selasky 	&phone_iface_1_alt_0,
340f9478f91SHans Petter Selasky 	&phone_iface_1_alt_1,
341f9478f91SHans Petter Selasky 	&phone_iface_2_alt_0,
342f9478f91SHans Petter Selasky 	&phone_iface_2_alt_1,
343f9478f91SHans Petter Selasky 	&phone_iface_3,
344f9478f91SHans Petter Selasky 	NULL,
345f9478f91SHans Petter Selasky };
346f9478f91SHans Petter Selasky 
347f9478f91SHans Petter Selasky static const struct usb_temp_config_desc phone_config_desc = {
348f9478f91SHans Petter Selasky 	.ppIfaceDesc = phone_interfaces,
349d008c0d7SEdward Tomasz Napierala 	.bmAttributes = 0,
350d008c0d7SEdward Tomasz Napierala 	.bMaxPower = 0,
3518e06491aSEdward Tomasz Napierala 	.iConfiguration = PHONE_PRODUCT_INDEX,
352f9478f91SHans Petter Selasky };
353f9478f91SHans Petter Selasky 
354f9478f91SHans Petter Selasky static const struct usb_temp_config_desc *phone_configs[] = {
355f9478f91SHans Petter Selasky 	&phone_config_desc,
356f9478f91SHans Petter Selasky 	NULL,
357f9478f91SHans Petter Selasky };
358f9478f91SHans Petter Selasky 
359f9478f91SHans Petter Selasky static usb_temp_get_string_desc_t phone_get_string_desc;
360f9478f91SHans Petter Selasky static usb_temp_get_vendor_desc_t phone_get_vendor_desc;
361f9478f91SHans Petter Selasky 
3628e06491aSEdward Tomasz Napierala struct usb_temp_device_desc usb_template_phone = {
363f9478f91SHans Petter Selasky 	.getStringDesc = &phone_get_string_desc,
364f9478f91SHans Petter Selasky 	.getVendorDesc = &phone_get_vendor_desc,
365f9478f91SHans Petter Selasky 	.ppConfigDesc = phone_configs,
3661558eec6SEdward Tomasz Napierala 	.idVendor = PHONE_DEFAULT_VENDOR_ID,
3671558eec6SEdward Tomasz Napierala 	.idProduct = PHONE_DEFAULT_PRODUCT_ID,
368f9478f91SHans Petter Selasky 	.bcdDevice = 0x0100,
369f9478f91SHans Petter Selasky 	.bDeviceClass = UDCLASS_IN_INTERFACE,
370f9478f91SHans Petter Selasky 	.bDeviceSubClass = 0,
371f9478f91SHans Petter Selasky 	.bDeviceProtocol = 0,
3721ee5bed7SEdward Tomasz Napierala 	.iManufacturer = PHONE_MANUFACTURER_INDEX,
3738e06491aSEdward Tomasz Napierala 	.iProduct = PHONE_PRODUCT_INDEX,
3741ee5bed7SEdward Tomasz Napierala 	.iSerialNumber = PHONE_SERIAL_NUMBER_INDEX,
375f9478f91SHans Petter Selasky };
376f9478f91SHans Petter Selasky 
377f9478f91SHans Petter Selasky /*------------------------------------------------------------------------*
378f9478f91SHans Petter Selasky  *      phone_get_vendor_desc
379f9478f91SHans Petter Selasky  *
380f9478f91SHans Petter Selasky  * Return values:
381f9478f91SHans Petter Selasky  * NULL: Failure. No such vendor descriptor.
382f9478f91SHans Petter Selasky  * Else: Success. Pointer to vendor descriptor is returned.
383f9478f91SHans Petter Selasky  *------------------------------------------------------------------------*/
384f9478f91SHans Petter Selasky static const void *
phone_get_vendor_desc(const struct usb_device_request * req,uint16_t * plen)385f9478f91SHans Petter Selasky phone_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
386f9478f91SHans Petter Selasky {
387f9478f91SHans Petter Selasky 	if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) &&
388f9478f91SHans Petter Selasky 	    (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) &&
389f9478f91SHans Petter Selasky 	    (req->wIndex[1] == 0) && (req->wIndex[0] == 3 /* iface */)) {
390f9478f91SHans Petter Selasky 		*plen = sizeof(phone_hid_descriptor);
391f9478f91SHans Petter Selasky 		return (phone_hid_descriptor);
392f9478f91SHans Petter Selasky 	}
393f9478f91SHans Petter Selasky 	return (NULL);
394f9478f91SHans Petter Selasky }
395f9478f91SHans Petter Selasky 
396f9478f91SHans Petter Selasky /*------------------------------------------------------------------------*
397f9478f91SHans Petter Selasky  *	phone_get_string_desc
398f9478f91SHans Petter Selasky  *
399f9478f91SHans Petter Selasky  * Return values:
400f9478f91SHans Petter Selasky  * NULL: Failure. No such string.
401f9478f91SHans Petter Selasky  * Else: Success. Pointer to string descriptor is returned.
402f9478f91SHans Petter Selasky  *------------------------------------------------------------------------*/
403f9478f91SHans Petter Selasky static const void *
phone_get_string_desc(uint16_t lang_id,uint8_t string_index)404f9478f91SHans Petter Selasky phone_get_string_desc(uint16_t lang_id, uint8_t string_index)
405f9478f91SHans Petter Selasky {
4068e06491aSEdward Tomasz Napierala 	static const void *ptr[PHONE_MAX_INDEX] = {
4078e06491aSEdward Tomasz Napierala 		[PHONE_LANG_INDEX] = &usb_string_lang_en,
4088e06491aSEdward Tomasz Napierala 		[PHONE_MIXER_INDEX] = &phone_mixer,
4098e06491aSEdward Tomasz Napierala 		[PHONE_RECORD_INDEX] = &phone_record,
4108e06491aSEdward Tomasz Napierala 		[PHONE_PLAYBACK_INDEX] = &phone_playback,
4118e06491aSEdward Tomasz Napierala 		[PHONE_HID_INDEX] = &phone_hid,
4121ee5bed7SEdward Tomasz Napierala 		[PHONE_MANUFACTURER_INDEX] = &phone_manufacturer,
4131ee5bed7SEdward Tomasz Napierala 		[PHONE_PRODUCT_INDEX] = &phone_product,
4141ee5bed7SEdward Tomasz Napierala 		[PHONE_SERIAL_NUMBER_INDEX] = &phone_serial_number,
415f9478f91SHans Petter Selasky 	};
416f9478f91SHans Petter Selasky 
417f9478f91SHans Petter Selasky 	if (string_index == 0) {
418f9478f91SHans Petter Selasky 		return (&usb_string_lang_en);
419f9478f91SHans Petter Selasky 	}
420f9478f91SHans Petter Selasky 	if (lang_id != 0x0409) {
421f9478f91SHans Petter Selasky 		return (NULL);
422f9478f91SHans Petter Selasky 	}
4238e06491aSEdward Tomasz Napierala 	if (string_index < PHONE_MAX_INDEX) {
424f9478f91SHans Petter Selasky 		return (ptr[string_index]);
425f9478f91SHans Petter Selasky 	}
426f9478f91SHans Petter Selasky 	return (NULL);
427f9478f91SHans Petter Selasky }
4288e06491aSEdward Tomasz Napierala 
4298e06491aSEdward Tomasz Napierala static void
phone_init(void * arg __unused)4308e06491aSEdward Tomasz Napierala phone_init(void *arg __unused)
4318e06491aSEdward Tomasz Napierala {
4328e06491aSEdward Tomasz Napierala 	struct sysctl_oid *parent;
4338e06491aSEdward Tomasz Napierala 	char parent_name[3];
4348e06491aSEdward Tomasz Napierala 
4358e06491aSEdward Tomasz Napierala 	usb_make_str_desc(&phone_mixer, sizeof(phone_mixer),
4368e06491aSEdward Tomasz Napierala 	    PHONE_DEFAULT_MIXER);
4378e06491aSEdward Tomasz Napierala 	usb_make_str_desc(&phone_record, sizeof(phone_record),
4388e06491aSEdward Tomasz Napierala 	    PHONE_DEFAULT_RECORD);
4398e06491aSEdward Tomasz Napierala 	usb_make_str_desc(&phone_playback, sizeof(phone_playback),
4408e06491aSEdward Tomasz Napierala 	    PHONE_DEFAULT_PLAYBACK);
4418e06491aSEdward Tomasz Napierala 	usb_make_str_desc(&phone_hid, sizeof(phone_hid),
4428e06491aSEdward Tomasz Napierala 	    PHONE_DEFAULT_HID);
4431ee5bed7SEdward Tomasz Napierala 	usb_make_str_desc(&phone_manufacturer, sizeof(phone_manufacturer),
4441ee5bed7SEdward Tomasz Napierala 	    PHONE_DEFAULT_MANUFACTURER);
4451ee5bed7SEdward Tomasz Napierala 	usb_make_str_desc(&phone_product, sizeof(phone_product),
4461ee5bed7SEdward Tomasz Napierala 	    PHONE_DEFAULT_PRODUCT);
4471ee5bed7SEdward Tomasz Napierala 	usb_make_str_desc(&phone_serial_number, sizeof(phone_serial_number),
4481ee5bed7SEdward Tomasz Napierala 	    PHONE_DEFAULT_SERIAL_NUMBER);
4498e06491aSEdward Tomasz Napierala 
4508e06491aSEdward Tomasz Napierala 	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_PHONE);
4518e06491aSEdward Tomasz Napierala 	sysctl_ctx_init(&phone_ctx_list);
4528e06491aSEdward Tomasz Napierala 
4538e06491aSEdward Tomasz Napierala 	parent = SYSCTL_ADD_NODE(&phone_ctx_list,
4548e06491aSEdward Tomasz Napierala 	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
455f8d2b1f3SPawel Biernacki 	    parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE,
4568e06491aSEdward Tomasz Napierala 	    0, "USB Phone device side template");
4578e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_U16(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4588e06491aSEdward Tomasz Napierala 	    "vendor_id", CTLFLAG_RWTUN,
4598e06491aSEdward Tomasz Napierala 	    &usb_template_cdce.idVendor, 1, "Vendor identifier");
4608e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_U16(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4618e06491aSEdward Tomasz Napierala 	    "product_id", CTLFLAG_RWTUN,
4628e06491aSEdward Tomasz Napierala 	    &usb_template_cdce.idProduct, 1, "Product identifier");
4638e06491aSEdward Tomasz Napierala #if 0
4648e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4658e06491aSEdward Tomasz Napierala 	    "mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4668e06491aSEdward Tomasz Napierala 	    &phone_mixer, sizeof(phone_mixer), usb_temp_sysctl,
4678e06491aSEdward Tomasz Napierala 	    "A", "Mixer interface string");
4688e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4698e06491aSEdward Tomasz Napierala 	    "record", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4708e06491aSEdward Tomasz Napierala 	    &phone_record, sizeof(phone_record), usb_temp_sysctl,
4718e06491aSEdward Tomasz Napierala 	    "A", "Record interface string");
4728e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4738e06491aSEdward Tomasz Napierala 	    "playback", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4748e06491aSEdward Tomasz Napierala 	    &phone_playback, sizeof(phone_playback), usb_temp_sysctl,
4758e06491aSEdward Tomasz Napierala 	    "A", "Playback interface string");
4761ee5bed7SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4771ee5bed7SEdward Tomasz Napierala 	    "hid", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4781ee5bed7SEdward Tomasz Napierala 	    &phone_hid, sizeof(phone_hid), usb_temp_sysctl,
4791ee5bed7SEdward Tomasz Napierala 	    "A", "HID interface string");
4808e06491aSEdward Tomasz Napierala #endif
4818e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4821ee5bed7SEdward Tomasz Napierala 	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4831ee5bed7SEdward Tomasz Napierala 	    &phone_manufacturer, sizeof(phone_manufacturer), usb_temp_sysctl,
4841ee5bed7SEdward Tomasz Napierala 	    "A", "Manufacturer string");
4851ee5bed7SEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4868e06491aSEdward Tomasz Napierala 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4878e06491aSEdward Tomasz Napierala 	    &phone_product, sizeof(phone_product), usb_temp_sysctl,
4888e06491aSEdward Tomasz Napierala 	    "A", "Product string");
4898e06491aSEdward Tomasz Napierala 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
4901ee5bed7SEdward Tomasz Napierala 	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
4911ee5bed7SEdward Tomasz Napierala 	    &phone_serial_number, sizeof(phone_serial_number), usb_temp_sysctl,
4921ee5bed7SEdward Tomasz Napierala 	    "A", "Serial number string");
4938e06491aSEdward Tomasz Napierala }
4948e06491aSEdward Tomasz Napierala 
4958e06491aSEdward Tomasz Napierala static void
phone_uninit(void * arg __unused)4968e06491aSEdward Tomasz Napierala phone_uninit(void *arg __unused)
4978e06491aSEdward Tomasz Napierala {
4988e06491aSEdward Tomasz Napierala 
4998e06491aSEdward Tomasz Napierala 	sysctl_ctx_free(&phone_ctx_list);
5008e06491aSEdward Tomasz Napierala }
5018e06491aSEdward Tomasz Napierala 
5028e06491aSEdward Tomasz Napierala SYSINIT(phone_init, SI_SUB_LOCK, SI_ORDER_FIRST, phone_init, NULL);
503c70e38e4SHans Petter Selasky SYSUNINIT(phone_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, phone_uninit, NULL);
504