xref: /freebsd/sys/dev/usb/template/usb_template_phone.c (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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 		*plen = sizeof(phone_hid_descriptor);
392 		return (phone_hid_descriptor);
393 	}
394 	return (NULL);
395 }
396 
397 /*------------------------------------------------------------------------*
398  *	phone_get_string_desc
399  *
400  * Return values:
401  * NULL: Failure. No such string.
402  * Else: Success. Pointer to string descriptor is returned.
403  *------------------------------------------------------------------------*/
404 static const void *
405 phone_get_string_desc(uint16_t lang_id, uint8_t string_index)
406 {
407 	static const void *ptr[PHONE_MAX_INDEX] = {
408 		[PHONE_LANG_INDEX] = &usb_string_lang_en,
409 		[PHONE_MIXER_INDEX] = &phone_mixer,
410 		[PHONE_RECORD_INDEX] = &phone_record,
411 		[PHONE_PLAYBACK_INDEX] = &phone_playback,
412 		[PHONE_HID_INDEX] = &phone_hid,
413 		[PHONE_MANUFACTURER_INDEX] = &phone_manufacturer,
414 		[PHONE_PRODUCT_INDEX] = &phone_product,
415 		[PHONE_SERIAL_NUMBER_INDEX] = &phone_serial_number,
416 	};
417 
418 	if (string_index == 0) {
419 		return (&usb_string_lang_en);
420 	}
421 	if (lang_id != 0x0409) {
422 		return (NULL);
423 	}
424 	if (string_index < PHONE_MAX_INDEX) {
425 		return (ptr[string_index]);
426 	}
427 	return (NULL);
428 }
429 
430 static void
431 phone_init(void *arg __unused)
432 {
433 	struct sysctl_oid *parent;
434 	char parent_name[3];
435 
436 	usb_make_str_desc(&phone_mixer, sizeof(phone_mixer),
437 	    PHONE_DEFAULT_MIXER);
438 	usb_make_str_desc(&phone_record, sizeof(phone_record),
439 	    PHONE_DEFAULT_RECORD);
440 	usb_make_str_desc(&phone_playback, sizeof(phone_playback),
441 	    PHONE_DEFAULT_PLAYBACK);
442 	usb_make_str_desc(&phone_hid, sizeof(phone_hid),
443 	    PHONE_DEFAULT_HID);
444 	usb_make_str_desc(&phone_manufacturer, sizeof(phone_manufacturer),
445 	    PHONE_DEFAULT_MANUFACTURER);
446 	usb_make_str_desc(&phone_product, sizeof(phone_product),
447 	    PHONE_DEFAULT_PRODUCT);
448 	usb_make_str_desc(&phone_serial_number, sizeof(phone_serial_number),
449 	    PHONE_DEFAULT_SERIAL_NUMBER);
450 
451 	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_PHONE);
452 	sysctl_ctx_init(&phone_ctx_list);
453 
454 	parent = SYSCTL_ADD_NODE(&phone_ctx_list,
455 	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
456 	    parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE,
457 	    0, "USB Phone device side template");
458 	SYSCTL_ADD_U16(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
459 	    "vendor_id", CTLFLAG_RWTUN,
460 	    &usb_template_cdce.idVendor, 1, "Vendor identifier");
461 	SYSCTL_ADD_U16(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
462 	    "product_id", CTLFLAG_RWTUN,
463 	    &usb_template_cdce.idProduct, 1, "Product identifier");
464 #if 0
465 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
466 	    "mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
467 	    &phone_mixer, sizeof(phone_mixer), usb_temp_sysctl,
468 	    "A", "Mixer interface string");
469 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
470 	    "record", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
471 	    &phone_record, sizeof(phone_record), usb_temp_sysctl,
472 	    "A", "Record interface string");
473 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
474 	    "playback", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
475 	    &phone_playback, sizeof(phone_playback), usb_temp_sysctl,
476 	    "A", "Playback interface string");
477 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
478 	    "hid", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
479 	    &phone_hid, sizeof(phone_hid), usb_temp_sysctl,
480 	    "A", "HID interface string");
481 #endif
482 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
483 	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
484 	    &phone_manufacturer, sizeof(phone_manufacturer), usb_temp_sysctl,
485 	    "A", "Manufacturer string");
486 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
487 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
488 	    &phone_product, sizeof(phone_product), usb_temp_sysctl,
489 	    "A", "Product string");
490 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
491 	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
492 	    &phone_serial_number, sizeof(phone_serial_number), usb_temp_sysctl,
493 	    "A", "Serial number string");
494 }
495 
496 static void
497 phone_uninit(void *arg __unused)
498 {
499 
500 	sysctl_ctx_free(&phone_ctx_list);
501 }
502 
503 SYSINIT(phone_init, SI_SUB_LOCK, SI_ORDER_FIRST, phone_init, NULL);
504 SYSUNINIT(phone_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, phone_uninit, NULL);
505