xref: /freebsd/sys/dev/usb/template/usb_template_phone.c (revision ef36b3f75658d201edb495068db5e1be49593de5)
1 /* $FreeBSD$ */
2 /*-
3  * Copyright (c) 2014 Hans Petter Selasky. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * This file contains the USB template for an USB phone device.
29  */
30 
31 #ifdef USB_GLOBAL_INCLUDE_FILE
32 #include USB_GLOBAL_INCLUDE_FILE
33 #else
34 #include <sys/stdint.h>
35 #include <sys/stddef.h>
36 #include <sys/param.h>
37 #include <sys/queue.h>
38 #include <sys/types.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/bus.h>
42 #include <sys/module.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/condvar.h>
46 #include <sys/sysctl.h>
47 #include <sys/sx.h>
48 #include <sys/unistd.h>
49 #include <sys/callout.h>
50 #include <sys/malloc.h>
51 #include <sys/priv.h>
52 
53 #include <dev/usb/usb.h>
54 #include <dev/usb/usbdi.h>
55 #include <dev/usb/usb_core.h>
56 #include <dev/usb/usb_cdc.h>
57 
58 #include <dev/usb/template/usb_template.h>
59 #endif			/* USB_GLOBAL_INCLUDE_FILE */
60 
61 enum {
62 	INDEX_PHONE_LANG,
63 	INDEX_PHONE_MIXER,
64 	INDEX_PHONE_RECORD,
65 	INDEX_PHONE_PLAYBACK,
66 	INDEX_PHONE_PRODUCT,
67 	INDEX_PHONE_HID,
68 	INDEX_PHONE_MAX,
69 };
70 
71 #define	STRING_PHONE_PRODUCT \
72   "U\0S\0B\0 \0P\0h\0o\0n\0e\0 \0D\0e\0v\0i\0c\0e"
73 
74 #define	STRING_PHONE_MIXER \
75   "M\0i\0x\0e\0r\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e"
76 
77 #define	STRING_PHONE_RECORD \
78   "R\0e\0c\0o\0r\0d\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e"
79 
80 #define	STRING_PHONE_PLAYBACK \
81   "P\0l\0a\0y\0b\0a\0c\0k\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e"
82 
83 #define	STRING_PHONE_HID \
84   "H\0I\0D\0 \0i\0n\0t\0e\0r\0f\0a\0c\0e"
85 
86 /* make the real string descriptors */
87 
88 USB_MAKE_STRING_DESC(STRING_PHONE_MIXER, string_phone_mixer);
89 USB_MAKE_STRING_DESC(STRING_PHONE_RECORD, string_phone_record);
90 USB_MAKE_STRING_DESC(STRING_PHONE_PLAYBACK, string_phone_playback);
91 USB_MAKE_STRING_DESC(STRING_PHONE_PRODUCT, string_phone_product);
92 USB_MAKE_STRING_DESC(STRING_PHONE_HID, string_phone_hid);
93 
94 /* prototypes */
95 
96 /*
97  * Phone Mixer description structures
98  *
99  * Some of the phone descriptors were dumped from no longer in
100  * production Yealink VOIP USB phone adapter:
101  */
102 static uint8_t phone_hid_descriptor[] = {
103 	0x05, 0x0b, 0x09, 0x01, 0xa1, 0x01, 0x05, 0x09,
104 	0x19, 0x01, 0x29, 0x3f, 0x15, 0x00, 0x25, 0x01,
105 	0x75, 0x01, 0x95, 0x80, 0x81, 0x00, 0x05, 0x08,
106 	0x19, 0x01, 0x29, 0x10, 0x15, 0x00, 0x25, 0x01,
107 	0x75, 0x01, 0x95, 0x80, 0x91, 0x00, 0xc0
108 };
109 
110 static const uint8_t phone_raw_desc_0[] = {
111 	0x0a, 0x24, 0x01, 0x00, 0x01, 0x4a, 0x00, 0x02,
112 	0x01, 0x02
113 };
114 
115 static const uint8_t phone_raw_desc_1[] = {
116 	0x0c, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00, 0x01,
117 	0x00, 0x00, 0x00, 0x00
118 };
119 
120 static const uint8_t phone_raw_desc_2[] = {
121 	0x0c, 0x24, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01,
122 	0x00, 0x00, 0x00, 0x00
123 };
124 
125 static const uint8_t phone_raw_desc_3[] = {
126 	0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x06,
127 	0x00
128 };
129 
130 static const uint8_t phone_raw_desc_4[] = {
131 	0x09, 0x24, 0x03, 0x04, 0x01, 0x01, 0x00, 0x05,
132 	0x00
133 };
134 
135 static const uint8_t phone_raw_desc_5[] = {
136 	0x0b, 0x24, 0x06, 0x05, 0x01, 0x02, 0x03, 0x00,
137 	0x03, 0x00, 0x00
138 };
139 
140 static const uint8_t phone_raw_desc_6[] = {
141 	0x0b, 0x24, 0x06, 0x06, 0x02, 0x02, 0x03, 0x00,
142 	0x03, 0x00, 0x00
143 };
144 
145 static const void *phone_raw_iface_0_desc[] = {
146 	phone_raw_desc_0,
147 	phone_raw_desc_1,
148 	phone_raw_desc_2,
149 	phone_raw_desc_3,
150 	phone_raw_desc_4,
151 	phone_raw_desc_5,
152 	phone_raw_desc_6,
153 	NULL,
154 };
155 
156 static const struct usb_temp_interface_desc phone_iface_0 = {
157 	.ppEndpoints = NULL,		/* no endpoints */
158 	.ppRawDesc = phone_raw_iface_0_desc,
159 	.bInterfaceClass = UICLASS_AUDIO,
160 	.bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
161 	.bInterfaceProtocol = 0,
162 	.iInterface = INDEX_PHONE_MIXER,
163 };
164 
165 static const uint8_t phone_raw_desc_20[] = {
166 	0x07, 0x24, 0x01, 0x04, 0x01, 0x01, 0x00
167 };
168 
169 static const uint8_t phone_raw_desc_21[] = {
170 	0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
171 	/* 8kHz */
172 	0x40, 0x1f, 0x00
173 };
174 
175 static const uint8_t phone_raw_desc_22[] = {
176 	0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
177 };
178 
179 static const void *phone_raw_iface_1_desc[] = {
180 	phone_raw_desc_20,
181 	phone_raw_desc_21,
182 	NULL,
183 };
184 
185 static const void *phone_raw_ep_1_desc[] = {
186 	phone_raw_desc_22,
187 	NULL,
188 };
189 
190 static const struct usb_temp_packet_size phone_isoc_mps = {
191 	.mps[USB_SPEED_FULL] = 0x10,
192 	.mps[USB_SPEED_HIGH] = 0x10,
193 };
194 
195 static const struct usb_temp_interval phone_isoc_interval = {
196 	.bInterval[USB_SPEED_FULL] = 1,	/* 1:1 */
197 	.bInterval[USB_SPEED_HIGH] = 4,	/* 1:8 */
198 };
199 
200 static const struct usb_temp_endpoint_desc phone_isoc_in_ep = {
201 	.ppRawDesc = phone_raw_ep_1_desc,
202 	.pPacketSize = &phone_isoc_mps,
203 	.pIntervals = &phone_isoc_interval,
204 	.bEndpointAddress = UE_DIR_IN,
205 	.bmAttributes = UE_ISOCHRONOUS,
206 };
207 
208 static const struct usb_temp_endpoint_desc *phone_iface_1_ep[] = {
209 	&phone_isoc_in_ep,
210 	NULL,
211 };
212 
213 static const struct usb_temp_interface_desc phone_iface_1_alt_0 = {
214 	.ppEndpoints = NULL,		/* no endpoints */
215 	.ppRawDesc = NULL,		/* no raw descriptors */
216 	.bInterfaceClass = UICLASS_AUDIO,
217 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
218 	.bInterfaceProtocol = 0,
219 	.iInterface = INDEX_PHONE_PLAYBACK,
220 };
221 
222 static const struct usb_temp_interface_desc phone_iface_1_alt_1 = {
223 	.ppEndpoints = phone_iface_1_ep,
224 	.ppRawDesc = phone_raw_iface_1_desc,
225 	.bInterfaceClass = UICLASS_AUDIO,
226 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
227 	.bInterfaceProtocol = 0,
228 	.iInterface = INDEX_PHONE_PLAYBACK,
229 	.isAltInterface = 1,		/* this is an alternate setting */
230 };
231 
232 static const uint8_t phone_raw_desc_30[] = {
233 	0x07, 0x24, 0x01, 0x02, 0x01, 0x01, 0x00
234 };
235 
236 static const uint8_t phone_raw_desc_31[] = {
237 	0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
238 	/* 8kHz */
239 	0x40, 0x1f, 0x00
240 };
241 
242 static const uint8_t phone_raw_desc_32[] = {
243 	0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
244 };
245 
246 static const void *phone_raw_iface_2_desc[] = {
247 	phone_raw_desc_30,
248 	phone_raw_desc_31,
249 	NULL,
250 };
251 
252 static const void *phone_raw_ep_2_desc[] = {
253 	phone_raw_desc_32,
254 	NULL,
255 };
256 
257 static const struct usb_temp_endpoint_desc phone_isoc_out_ep = {
258 	.ppRawDesc = phone_raw_ep_2_desc,
259 	.pPacketSize = &phone_isoc_mps,
260 	.pIntervals = &phone_isoc_interval,
261 	.bEndpointAddress = UE_DIR_OUT,
262 	.bmAttributes = UE_ISOCHRONOUS,
263 };
264 
265 static const struct usb_temp_endpoint_desc *phone_iface_2_ep[] = {
266 	&phone_isoc_out_ep,
267 	NULL,
268 };
269 
270 static const struct usb_temp_interface_desc phone_iface_2_alt_0 = {
271 	.ppEndpoints = NULL,		/* no endpoints */
272 	.ppRawDesc = NULL,		/* no raw descriptors */
273 	.bInterfaceClass = UICLASS_AUDIO,
274 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
275 	.bInterfaceProtocol = 0,
276 	.iInterface = INDEX_PHONE_RECORD,
277 };
278 
279 static const struct usb_temp_interface_desc phone_iface_2_alt_1 = {
280 	.ppEndpoints = phone_iface_2_ep,
281 	.ppRawDesc = phone_raw_iface_2_desc,
282 	.bInterfaceClass = UICLASS_AUDIO,
283 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
284 	.bInterfaceProtocol = 0,
285 	.iInterface = INDEX_PHONE_RECORD,
286 	.isAltInterface = 1,		/* this is an alternate setting */
287 };
288 
289 static const uint8_t phone_hid_raw_desc_0[] = {
290 	0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, sizeof(phone_hid_descriptor),
291 	0x00
292 };
293 
294 static const void *phone_hid_desc_0[] = {
295 	phone_hid_raw_desc_0,
296 	NULL,
297 };
298 
299 static const struct usb_temp_packet_size phone_hid_mps = {
300 	.mps[USB_SPEED_FULL] = 0x10,
301 	.mps[USB_SPEED_HIGH] = 0x10,
302 };
303 
304 static const struct usb_temp_interval phone_hid_interval = {
305 	.bInterval[USB_SPEED_FULL] = 2,		/* 2ms */
306 	.bInterval[USB_SPEED_HIGH] = 2,		/* 2ms */
307 };
308 
309 static const struct usb_temp_endpoint_desc phone_hid_in_ep = {
310 	.pPacketSize = &phone_hid_mps,
311 	.pIntervals = &phone_hid_interval,
312 	.bEndpointAddress = UE_DIR_IN,
313 	.bmAttributes = UE_INTERRUPT,
314 };
315 
316 static const struct usb_temp_endpoint_desc *phone_iface_3_ep[] = {
317 	&phone_hid_in_ep,
318 	NULL,
319 };
320 
321 static const struct usb_temp_interface_desc phone_iface_3 = {
322 	.ppEndpoints = phone_iface_3_ep,
323 	.ppRawDesc = phone_hid_desc_0,
324 	.bInterfaceClass = UICLASS_HID,
325 	.bInterfaceSubClass = 0,
326 	.bInterfaceProtocol = 0,
327 	.iInterface = INDEX_PHONE_HID,
328 };
329 
330 static const struct usb_temp_interface_desc *phone_interfaces[] = {
331 	&phone_iface_0,
332 	&phone_iface_1_alt_0,
333 	&phone_iface_1_alt_1,
334 	&phone_iface_2_alt_0,
335 	&phone_iface_2_alt_1,
336 	&phone_iface_3,
337 	NULL,
338 };
339 
340 static const struct usb_temp_config_desc phone_config_desc = {
341 	.ppIfaceDesc = phone_interfaces,
342 	.bmAttributes = UC_BUS_POWERED,
343 	.bMaxPower = 25,		/* 50 mA */
344 	.iConfiguration = INDEX_PHONE_PRODUCT,
345 };
346 
347 static const struct usb_temp_config_desc *phone_configs[] = {
348 	&phone_config_desc,
349 	NULL,
350 };
351 
352 static usb_temp_get_string_desc_t phone_get_string_desc;
353 static usb_temp_get_vendor_desc_t phone_get_vendor_desc;
354 
355 const struct usb_temp_device_desc usb_template_phone = {
356 	.getStringDesc = &phone_get_string_desc,
357 	.getVendorDesc = &phone_get_vendor_desc,
358 	.ppConfigDesc = phone_configs,
359 	.idVendor = USB_TEMPLATE_VENDOR,
360 	.idProduct = 0xb001,
361 	.bcdDevice = 0x0100,
362 	.bDeviceClass = UDCLASS_IN_INTERFACE,
363 	.bDeviceSubClass = 0,
364 	.bDeviceProtocol = 0,
365 	.iManufacturer = 0,
366 	.iProduct = INDEX_PHONE_PRODUCT,
367 	.iSerialNumber = 0,
368 };
369 
370 /*------------------------------------------------------------------------*
371  *      phone_get_vendor_desc
372  *
373  * Return values:
374  * NULL: Failure. No such vendor descriptor.
375  * Else: Success. Pointer to vendor descriptor is returned.
376  *------------------------------------------------------------------------*/
377 static const void *
378 phone_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
379 {
380 	if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) &&
381 	    (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) &&
382 	    (req->wIndex[1] == 0) && (req->wIndex[0] == 3 /* iface */)) {
383 
384 		*plen = sizeof(phone_hid_descriptor);
385 		return (phone_hid_descriptor);
386 	}
387 	return (NULL);
388 }
389 
390 /*------------------------------------------------------------------------*
391  *	phone_get_string_desc
392  *
393  * Return values:
394  * NULL: Failure. No such string.
395  * Else: Success. Pointer to string descriptor is returned.
396  *------------------------------------------------------------------------*/
397 static const void *
398 phone_get_string_desc(uint16_t lang_id, uint8_t string_index)
399 {
400 	static const void *ptr[INDEX_PHONE_MAX] = {
401 		[INDEX_PHONE_LANG] = &usb_string_lang_en,
402 		[INDEX_PHONE_MIXER] = &string_phone_mixer,
403 		[INDEX_PHONE_RECORD] = &string_phone_record,
404 		[INDEX_PHONE_PLAYBACK] = &string_phone_playback,
405 		[INDEX_PHONE_PRODUCT] = &string_phone_product,
406 		[INDEX_PHONE_HID] = &string_phone_hid,
407 	};
408 
409 	if (string_index == 0) {
410 		return (&usb_string_lang_en);
411 	}
412 	if (lang_id != 0x0409) {
413 		return (NULL);
414 	}
415 	if (string_index < INDEX_PHONE_MAX) {
416 		return (ptr[string_index]);
417 	}
418 	return (NULL);
419 }
420