xref: /freebsd/sys/dev/usb/template/usb_template_phone.c (revision 62cfcf62f627e5093fb37026a6d8c98e4d2ef04c)
1 /* $FreeBSD$ */
2 /*-
3  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4  *
5  * Copyright (c) 2014 Hans Petter Selasky
6  * Copyright (c) 2018 The FreeBSD Foundation
7  * All rights reserved.
8  *
9  * Portions of this software were developed by Edward Tomasz Napierala
10  * under sponsorship from the FreeBSD Foundation.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*
35  * This file contains the USB template for an USB phone device.
36  */
37 
38 #ifdef USB_GLOBAL_INCLUDE_FILE
39 #include USB_GLOBAL_INCLUDE_FILE
40 #else
41 #include <sys/stdint.h>
42 #include <sys/stddef.h>
43 #include <sys/param.h>
44 #include <sys/queue.h>
45 #include <sys/types.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/bus.h>
49 #include <sys/module.h>
50 #include <sys/lock.h>
51 #include <sys/mutex.h>
52 #include <sys/condvar.h>
53 #include <sys/sysctl.h>
54 #include <sys/sx.h>
55 #include <sys/unistd.h>
56 #include <sys/callout.h>
57 #include <sys/malloc.h>
58 #include <sys/priv.h>
59 
60 #include <dev/usb/usb.h>
61 #include <dev/usb/usbdi.h>
62 #include <dev/usb/usb_core.h>
63 #include <dev/usb/usb_cdc.h>
64 #include <dev/usb/usb_ioctl.h>
65 #include <dev/usb/usb_util.h>
66 
67 #include <dev/usb/template/usb_template.h>
68 #endif			/* USB_GLOBAL_INCLUDE_FILE */
69 
70 enum {
71 	PHONE_LANG_INDEX,
72 	PHONE_MIXER_INDEX,
73 	PHONE_RECORD_INDEX,
74 	PHONE_PLAYBACK_INDEX,
75 	PHONE_HID_INDEX,
76 	PHONE_MANUFACTURER_INDEX,
77 	PHONE_PRODUCT_INDEX,
78 	PHONE_SERIAL_NUMBER_INDEX,
79 	PHONE_MAX_INDEX,
80 };
81 
82 #define	PHONE_DEFAULT_VENDOR_ID		USB_TEMPLATE_VENDOR
83 #define	PHONE_DEFAULT_PRODUCT_ID	0x05dc
84 #define	PHONE_DEFAULT_MIXER		"Mixer interface"
85 #define	PHONE_DEFAULT_RECORD		"Record interface"
86 #define	PHONE_DEFAULT_PLAYBACK		"Playback interface"
87 #define	PHONE_DEFAULT_HID		"HID interface"
88 #define	PHONE_DEFAULT_MANUFACTURER	USB_TEMPLATE_MANUFACTURER
89 #define	PHONE_DEFAULT_PRODUCT		"USB Phone Device"
90 #define	PHONE_DEFAULT_SERIAL_NUMBER	"March 2008"
91 
92 static struct usb_string_descriptor	phone_mixer;
93 static struct usb_string_descriptor	phone_record;
94 static struct usb_string_descriptor	phone_playback;
95 static struct usb_string_descriptor	phone_hid;
96 static struct usb_string_descriptor	phone_manufacturer;
97 static struct usb_string_descriptor	phone_product;
98 static struct usb_string_descriptor	phone_serial_number;
99 
100 static struct sysctl_ctx_list		phone_ctx_list;
101 
102 /* prototypes */
103 
104 /*
105  * Phone Mixer description structures
106  *
107  * Some of the phone descriptors were dumped from no longer in
108  * production Yealink VOIP USB phone adapter:
109  */
110 static uint8_t phone_hid_descriptor[] = {
111 	0x05, 0x0b, 0x09, 0x01, 0xa1, 0x01, 0x05, 0x09,
112 	0x19, 0x01, 0x29, 0x3f, 0x15, 0x00, 0x25, 0x01,
113 	0x75, 0x01, 0x95, 0x80, 0x81, 0x00, 0x05, 0x08,
114 	0x19, 0x01, 0x29, 0x10, 0x15, 0x00, 0x25, 0x01,
115 	0x75, 0x01, 0x95, 0x80, 0x91, 0x00, 0xc0
116 };
117 
118 static const uint8_t phone_raw_desc_0[] = {
119 	0x0a, 0x24, 0x01, 0x00, 0x01, 0x4a, 0x00, 0x02,
120 	0x01, 0x02
121 };
122 
123 static const uint8_t phone_raw_desc_1[] = {
124 	0x0c, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00, 0x01,
125 	0x00, 0x00, 0x00, 0x00
126 };
127 
128 static const uint8_t phone_raw_desc_2[] = {
129 	0x0c, 0x24, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01,
130 	0x00, 0x00, 0x00, 0x00
131 };
132 
133 static const uint8_t phone_raw_desc_3[] = {
134 	0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x06,
135 	0x00
136 };
137 
138 static const uint8_t phone_raw_desc_4[] = {
139 	0x09, 0x24, 0x03, 0x04, 0x01, 0x01, 0x00, 0x05,
140 	0x00
141 };
142 
143 static const uint8_t phone_raw_desc_5[] = {
144 	0x0b, 0x24, 0x06, 0x05, 0x01, 0x02, 0x03, 0x00,
145 	0x03, 0x00, 0x00
146 };
147 
148 static const uint8_t phone_raw_desc_6[] = {
149 	0x0b, 0x24, 0x06, 0x06, 0x02, 0x02, 0x03, 0x00,
150 	0x03, 0x00, 0x00
151 };
152 
153 static const void *phone_raw_iface_0_desc[] = {
154 	phone_raw_desc_0,
155 	phone_raw_desc_1,
156 	phone_raw_desc_2,
157 	phone_raw_desc_3,
158 	phone_raw_desc_4,
159 	phone_raw_desc_5,
160 	phone_raw_desc_6,
161 	NULL,
162 };
163 
164 static const struct usb_temp_interface_desc phone_iface_0 = {
165 	.ppEndpoints = NULL,		/* no endpoints */
166 	.ppRawDesc = phone_raw_iface_0_desc,
167 	.bInterfaceClass = UICLASS_AUDIO,
168 	.bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
169 	.bInterfaceProtocol = 0,
170 	.iInterface = PHONE_MIXER_INDEX,
171 };
172 
173 static const uint8_t phone_raw_desc_20[] = {
174 	0x07, 0x24, 0x01, 0x04, 0x01, 0x01, 0x00
175 };
176 
177 static const uint8_t phone_raw_desc_21[] = {
178 	0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
179 	/* 8kHz */
180 	0x40, 0x1f, 0x00
181 };
182 
183 static const uint8_t phone_raw_desc_22[] = {
184 	0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
185 };
186 
187 static const void *phone_raw_iface_1_desc[] = {
188 	phone_raw_desc_20,
189 	phone_raw_desc_21,
190 	NULL,
191 };
192 
193 static const void *phone_raw_ep_1_desc[] = {
194 	phone_raw_desc_22,
195 	NULL,
196 };
197 
198 static const struct usb_temp_packet_size phone_isoc_mps = {
199 	.mps[USB_SPEED_FULL] = 0x10,
200 	.mps[USB_SPEED_HIGH] = 0x10,
201 };
202 
203 static const struct usb_temp_interval phone_isoc_interval = {
204 	.bInterval[USB_SPEED_FULL] = 1,	/* 1:1 */
205 	.bInterval[USB_SPEED_HIGH] = 4,	/* 1:8 */
206 };
207 
208 static const struct usb_temp_endpoint_desc phone_isoc_in_ep = {
209 	.ppRawDesc = phone_raw_ep_1_desc,
210 	.pPacketSize = &phone_isoc_mps,
211 	.pIntervals = &phone_isoc_interval,
212 	.bEndpointAddress = UE_DIR_IN,
213 	.bmAttributes = UE_ISOCHRONOUS,
214 };
215 
216 static const struct usb_temp_endpoint_desc *phone_iface_1_ep[] = {
217 	&phone_isoc_in_ep,
218 	NULL,
219 };
220 
221 static const struct usb_temp_interface_desc phone_iface_1_alt_0 = {
222 	.ppEndpoints = NULL,		/* no endpoints */
223 	.ppRawDesc = NULL,		/* no raw descriptors */
224 	.bInterfaceClass = UICLASS_AUDIO,
225 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
226 	.bInterfaceProtocol = 0,
227 	.iInterface = PHONE_PLAYBACK_INDEX,
228 };
229 
230 static const struct usb_temp_interface_desc phone_iface_1_alt_1 = {
231 	.ppEndpoints = phone_iface_1_ep,
232 	.ppRawDesc = phone_raw_iface_1_desc,
233 	.bInterfaceClass = UICLASS_AUDIO,
234 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
235 	.bInterfaceProtocol = 0,
236 	.iInterface = PHONE_PLAYBACK_INDEX,
237 	.isAltInterface = 1,		/* this is an alternate setting */
238 };
239 
240 static const uint8_t phone_raw_desc_30[] = {
241 	0x07, 0x24, 0x01, 0x02, 0x01, 0x01, 0x00
242 };
243 
244 static const uint8_t phone_raw_desc_31[] = {
245 	0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
246 	/* 8kHz */
247 	0x40, 0x1f, 0x00
248 };
249 
250 static const uint8_t phone_raw_desc_32[] = {
251 	0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
252 };
253 
254 static const void *phone_raw_iface_2_desc[] = {
255 	phone_raw_desc_30,
256 	phone_raw_desc_31,
257 	NULL,
258 };
259 
260 static const void *phone_raw_ep_2_desc[] = {
261 	phone_raw_desc_32,
262 	NULL,
263 };
264 
265 static const struct usb_temp_endpoint_desc phone_isoc_out_ep = {
266 	.ppRawDesc = phone_raw_ep_2_desc,
267 	.pPacketSize = &phone_isoc_mps,
268 	.pIntervals = &phone_isoc_interval,
269 	.bEndpointAddress = UE_DIR_OUT,
270 	.bmAttributes = UE_ISOCHRONOUS,
271 };
272 
273 static const struct usb_temp_endpoint_desc *phone_iface_2_ep[] = {
274 	&phone_isoc_out_ep,
275 	NULL,
276 };
277 
278 static const struct usb_temp_interface_desc phone_iface_2_alt_0 = {
279 	.ppEndpoints = NULL,		/* no endpoints */
280 	.ppRawDesc = NULL,		/* no raw descriptors */
281 	.bInterfaceClass = UICLASS_AUDIO,
282 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
283 	.bInterfaceProtocol = 0,
284 	.iInterface = PHONE_RECORD_INDEX,
285 };
286 
287 static const struct usb_temp_interface_desc phone_iface_2_alt_1 = {
288 	.ppEndpoints = phone_iface_2_ep,
289 	.ppRawDesc = phone_raw_iface_2_desc,
290 	.bInterfaceClass = UICLASS_AUDIO,
291 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
292 	.bInterfaceProtocol = 0,
293 	.iInterface = PHONE_RECORD_INDEX,
294 	.isAltInterface = 1,		/* this is an alternate setting */
295 };
296 
297 static const uint8_t phone_hid_raw_desc_0[] = {
298 	0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, sizeof(phone_hid_descriptor),
299 	0x00
300 };
301 
302 static const void *phone_hid_desc_0[] = {
303 	phone_hid_raw_desc_0,
304 	NULL,
305 };
306 
307 static const struct usb_temp_packet_size phone_hid_mps = {
308 	.mps[USB_SPEED_FULL] = 0x10,
309 	.mps[USB_SPEED_HIGH] = 0x10,
310 };
311 
312 static const struct usb_temp_interval phone_hid_interval = {
313 	.bInterval[USB_SPEED_FULL] = 2,		/* 2ms */
314 	.bInterval[USB_SPEED_HIGH] = 2,		/* 2ms */
315 };
316 
317 static const struct usb_temp_endpoint_desc phone_hid_in_ep = {
318 	.pPacketSize = &phone_hid_mps,
319 	.pIntervals = &phone_hid_interval,
320 	.bEndpointAddress = UE_DIR_IN,
321 	.bmAttributes = UE_INTERRUPT,
322 };
323 
324 static const struct usb_temp_endpoint_desc *phone_iface_3_ep[] = {
325 	&phone_hid_in_ep,
326 	NULL,
327 };
328 
329 static const struct usb_temp_interface_desc phone_iface_3 = {
330 	.ppEndpoints = phone_iface_3_ep,
331 	.ppRawDesc = phone_hid_desc_0,
332 	.bInterfaceClass = UICLASS_HID,
333 	.bInterfaceSubClass = 0,
334 	.bInterfaceProtocol = 0,
335 	.iInterface = PHONE_HID_INDEX,
336 };
337 
338 static const struct usb_temp_interface_desc *phone_interfaces[] = {
339 	&phone_iface_0,
340 	&phone_iface_1_alt_0,
341 	&phone_iface_1_alt_1,
342 	&phone_iface_2_alt_0,
343 	&phone_iface_2_alt_1,
344 	&phone_iface_3,
345 	NULL,
346 };
347 
348 static const struct usb_temp_config_desc phone_config_desc = {
349 	.ppIfaceDesc = phone_interfaces,
350 	.bmAttributes = 0,
351 	.bMaxPower = 0,
352 	.iConfiguration = PHONE_PRODUCT_INDEX,
353 };
354 
355 static const struct usb_temp_config_desc *phone_configs[] = {
356 	&phone_config_desc,
357 	NULL,
358 };
359 
360 static usb_temp_get_string_desc_t phone_get_string_desc;
361 static usb_temp_get_vendor_desc_t phone_get_vendor_desc;
362 
363 struct usb_temp_device_desc usb_template_phone = {
364 	.getStringDesc = &phone_get_string_desc,
365 	.getVendorDesc = &phone_get_vendor_desc,
366 	.ppConfigDesc = phone_configs,
367 	.idVendor = PHONE_DEFAULT_VENDOR_ID,
368 	.idProduct = PHONE_DEFAULT_PRODUCT_ID,
369 	.bcdDevice = 0x0100,
370 	.bDeviceClass = UDCLASS_IN_INTERFACE,
371 	.bDeviceSubClass = 0,
372 	.bDeviceProtocol = 0,
373 	.iManufacturer = PHONE_MANUFACTURER_INDEX,
374 	.iProduct = PHONE_PRODUCT_INDEX,
375 	.iSerialNumber = PHONE_SERIAL_NUMBER_INDEX,
376 };
377 
378 /*------------------------------------------------------------------------*
379  *      phone_get_vendor_desc
380  *
381  * Return values:
382  * NULL: Failure. No such vendor descriptor.
383  * Else: Success. Pointer to vendor descriptor is returned.
384  *------------------------------------------------------------------------*/
385 static const void *
386 phone_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
387 {
388 	if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) &&
389 	    (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) &&
390 	    (req->wIndex[1] == 0) && (req->wIndex[0] == 3 /* iface */)) {
391 
392 		*plen = sizeof(phone_hid_descriptor);
393 		return (phone_hid_descriptor);
394 	}
395 	return (NULL);
396 }
397 
398 /*------------------------------------------------------------------------*
399  *	phone_get_string_desc
400  *
401  * Return values:
402  * NULL: Failure. No such string.
403  * Else: Success. Pointer to string descriptor is returned.
404  *------------------------------------------------------------------------*/
405 static const void *
406 phone_get_string_desc(uint16_t lang_id, uint8_t string_index)
407 {
408 	static const void *ptr[PHONE_MAX_INDEX] = {
409 		[PHONE_LANG_INDEX] = &usb_string_lang_en,
410 		[PHONE_MIXER_INDEX] = &phone_mixer,
411 		[PHONE_RECORD_INDEX] = &phone_record,
412 		[PHONE_PLAYBACK_INDEX] = &phone_playback,
413 		[PHONE_HID_INDEX] = &phone_hid,
414 		[PHONE_MANUFACTURER_INDEX] = &phone_manufacturer,
415 		[PHONE_PRODUCT_INDEX] = &phone_product,
416 		[PHONE_SERIAL_NUMBER_INDEX] = &phone_serial_number,
417 	};
418 
419 	if (string_index == 0) {
420 		return (&usb_string_lang_en);
421 	}
422 	if (lang_id != 0x0409) {
423 		return (NULL);
424 	}
425 	if (string_index < PHONE_MAX_INDEX) {
426 		return (ptr[string_index]);
427 	}
428 	return (NULL);
429 }
430 
431 static void
432 phone_init(void *arg __unused)
433 {
434 	struct sysctl_oid *parent;
435 	char parent_name[3];
436 
437 	usb_make_str_desc(&phone_mixer, sizeof(phone_mixer),
438 	    PHONE_DEFAULT_MIXER);
439 	usb_make_str_desc(&phone_record, sizeof(phone_record),
440 	    PHONE_DEFAULT_RECORD);
441 	usb_make_str_desc(&phone_playback, sizeof(phone_playback),
442 	    PHONE_DEFAULT_PLAYBACK);
443 	usb_make_str_desc(&phone_hid, sizeof(phone_hid),
444 	    PHONE_DEFAULT_HID);
445 	usb_make_str_desc(&phone_manufacturer, sizeof(phone_manufacturer),
446 	    PHONE_DEFAULT_MANUFACTURER);
447 	usb_make_str_desc(&phone_product, sizeof(phone_product),
448 	    PHONE_DEFAULT_PRODUCT);
449 	usb_make_str_desc(&phone_serial_number, sizeof(phone_serial_number),
450 	    PHONE_DEFAULT_SERIAL_NUMBER);
451 
452 	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_PHONE);
453 	sysctl_ctx_init(&phone_ctx_list);
454 
455 	parent = SYSCTL_ADD_NODE(&phone_ctx_list,
456 	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
457 	    parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE,
458 	    0, "USB Phone device side template");
459 	SYSCTL_ADD_U16(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
460 	    "vendor_id", CTLFLAG_RWTUN,
461 	    &usb_template_cdce.idVendor, 1, "Vendor identifier");
462 	SYSCTL_ADD_U16(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
463 	    "product_id", CTLFLAG_RWTUN,
464 	    &usb_template_cdce.idProduct, 1, "Product identifier");
465 #if 0
466 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
467 	    "mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
468 	    &phone_mixer, sizeof(phone_mixer), usb_temp_sysctl,
469 	    "A", "Mixer interface string");
470 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
471 	    "record", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
472 	    &phone_record, sizeof(phone_record), usb_temp_sysctl,
473 	    "A", "Record interface string");
474 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
475 	    "playback", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
476 	    &phone_playback, sizeof(phone_playback), usb_temp_sysctl,
477 	    "A", "Playback interface string");
478 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
479 	    "hid", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
480 	    &phone_hid, sizeof(phone_hid), usb_temp_sysctl,
481 	    "A", "HID interface string");
482 #endif
483 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
484 	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
485 	    &phone_manufacturer, sizeof(phone_manufacturer), usb_temp_sysctl,
486 	    "A", "Manufacturer string");
487 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
488 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
489 	    &phone_product, sizeof(phone_product), usb_temp_sysctl,
490 	    "A", "Product string");
491 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
492 	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
493 	    &phone_serial_number, sizeof(phone_serial_number), usb_temp_sysctl,
494 	    "A", "Serial number string");
495 }
496 
497 static void
498 phone_uninit(void *arg __unused)
499 {
500 
501 	sysctl_ctx_free(&phone_ctx_list);
502 }
503 
504 SYSINIT(phone_init, SI_SUB_LOCK, SI_ORDER_FIRST, phone_init, NULL);
505 SYSUNINIT(phone_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, phone_uninit, NULL);
506