xref: /freebsd/sys/dev/usb/template/usb_template_phone.c (revision 5bf5ca772c6de2d53344a78cf461447cc322ccea)
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_MIXER		"Mixer interface"
83 #define	PHONE_DEFAULT_RECORD		"Record interface"
84 #define	PHONE_DEFAULT_PLAYBACK		"Playback interface"
85 #define	PHONE_DEFAULT_HID		"HID interface"
86 #define	PHONE_DEFAULT_MANUFACTURER	"FreeBSD foundation"
87 #define	PHONE_DEFAULT_PRODUCT		"USB Phone Device"
88 #define	PHONE_DEFAULT_SERIAL_NUMBER	"March 2008"
89 
90 static struct usb_string_descriptor	phone_mixer;
91 static struct usb_string_descriptor	phone_record;
92 static struct usb_string_descriptor	phone_playback;
93 static struct usb_string_descriptor	phone_hid;
94 static struct usb_string_descriptor	phone_manufacturer;
95 static struct usb_string_descriptor	phone_product;
96 static struct usb_string_descriptor	phone_serial_number;
97 
98 static struct sysctl_ctx_list		phone_ctx_list;
99 
100 /* prototypes */
101 
102 /*
103  * Phone Mixer description structures
104  *
105  * Some of the phone descriptors were dumped from no longer in
106  * production Yealink VOIP USB phone adapter:
107  */
108 static uint8_t phone_hid_descriptor[] = {
109 	0x05, 0x0b, 0x09, 0x01, 0xa1, 0x01, 0x05, 0x09,
110 	0x19, 0x01, 0x29, 0x3f, 0x15, 0x00, 0x25, 0x01,
111 	0x75, 0x01, 0x95, 0x80, 0x81, 0x00, 0x05, 0x08,
112 	0x19, 0x01, 0x29, 0x10, 0x15, 0x00, 0x25, 0x01,
113 	0x75, 0x01, 0x95, 0x80, 0x91, 0x00, 0xc0
114 };
115 
116 static const uint8_t phone_raw_desc_0[] = {
117 	0x0a, 0x24, 0x01, 0x00, 0x01, 0x4a, 0x00, 0x02,
118 	0x01, 0x02
119 };
120 
121 static const uint8_t phone_raw_desc_1[] = {
122 	0x0c, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00, 0x01,
123 	0x00, 0x00, 0x00, 0x00
124 };
125 
126 static const uint8_t phone_raw_desc_2[] = {
127 	0x0c, 0x24, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01,
128 	0x00, 0x00, 0x00, 0x00
129 };
130 
131 static const uint8_t phone_raw_desc_3[] = {
132 	0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x06,
133 	0x00
134 };
135 
136 static const uint8_t phone_raw_desc_4[] = {
137 	0x09, 0x24, 0x03, 0x04, 0x01, 0x01, 0x00, 0x05,
138 	0x00
139 };
140 
141 static const uint8_t phone_raw_desc_5[] = {
142 	0x0b, 0x24, 0x06, 0x05, 0x01, 0x02, 0x03, 0x00,
143 	0x03, 0x00, 0x00
144 };
145 
146 static const uint8_t phone_raw_desc_6[] = {
147 	0x0b, 0x24, 0x06, 0x06, 0x02, 0x02, 0x03, 0x00,
148 	0x03, 0x00, 0x00
149 };
150 
151 static const void *phone_raw_iface_0_desc[] = {
152 	phone_raw_desc_0,
153 	phone_raw_desc_1,
154 	phone_raw_desc_2,
155 	phone_raw_desc_3,
156 	phone_raw_desc_4,
157 	phone_raw_desc_5,
158 	phone_raw_desc_6,
159 	NULL,
160 };
161 
162 static const struct usb_temp_interface_desc phone_iface_0 = {
163 	.ppEndpoints = NULL,		/* no endpoints */
164 	.ppRawDesc = phone_raw_iface_0_desc,
165 	.bInterfaceClass = UICLASS_AUDIO,
166 	.bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
167 	.bInterfaceProtocol = 0,
168 	.iInterface = PHONE_MIXER_INDEX,
169 };
170 
171 static const uint8_t phone_raw_desc_20[] = {
172 	0x07, 0x24, 0x01, 0x04, 0x01, 0x01, 0x00
173 };
174 
175 static const uint8_t phone_raw_desc_21[] = {
176 	0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
177 	/* 8kHz */
178 	0x40, 0x1f, 0x00
179 };
180 
181 static const uint8_t phone_raw_desc_22[] = {
182 	0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
183 };
184 
185 static const void *phone_raw_iface_1_desc[] = {
186 	phone_raw_desc_20,
187 	phone_raw_desc_21,
188 	NULL,
189 };
190 
191 static const void *phone_raw_ep_1_desc[] = {
192 	phone_raw_desc_22,
193 	NULL,
194 };
195 
196 static const struct usb_temp_packet_size phone_isoc_mps = {
197 	.mps[USB_SPEED_FULL] = 0x10,
198 	.mps[USB_SPEED_HIGH] = 0x10,
199 };
200 
201 static const struct usb_temp_interval phone_isoc_interval = {
202 	.bInterval[USB_SPEED_FULL] = 1,	/* 1:1 */
203 	.bInterval[USB_SPEED_HIGH] = 4,	/* 1:8 */
204 };
205 
206 static const struct usb_temp_endpoint_desc phone_isoc_in_ep = {
207 	.ppRawDesc = phone_raw_ep_1_desc,
208 	.pPacketSize = &phone_isoc_mps,
209 	.pIntervals = &phone_isoc_interval,
210 	.bEndpointAddress = UE_DIR_IN,
211 	.bmAttributes = UE_ISOCHRONOUS,
212 };
213 
214 static const struct usb_temp_endpoint_desc *phone_iface_1_ep[] = {
215 	&phone_isoc_in_ep,
216 	NULL,
217 };
218 
219 static const struct usb_temp_interface_desc phone_iface_1_alt_0 = {
220 	.ppEndpoints = NULL,		/* no endpoints */
221 	.ppRawDesc = NULL,		/* no raw descriptors */
222 	.bInterfaceClass = UICLASS_AUDIO,
223 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
224 	.bInterfaceProtocol = 0,
225 	.iInterface = PHONE_PLAYBACK_INDEX,
226 };
227 
228 static const struct usb_temp_interface_desc phone_iface_1_alt_1 = {
229 	.ppEndpoints = phone_iface_1_ep,
230 	.ppRawDesc = phone_raw_iface_1_desc,
231 	.bInterfaceClass = UICLASS_AUDIO,
232 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
233 	.bInterfaceProtocol = 0,
234 	.iInterface = PHONE_PLAYBACK_INDEX,
235 	.isAltInterface = 1,		/* this is an alternate setting */
236 };
237 
238 static const uint8_t phone_raw_desc_30[] = {
239 	0x07, 0x24, 0x01, 0x02, 0x01, 0x01, 0x00
240 };
241 
242 static const uint8_t phone_raw_desc_31[] = {
243 	0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
244 	/* 8kHz */
245 	0x40, 0x1f, 0x00
246 };
247 
248 static const uint8_t phone_raw_desc_32[] = {
249 	0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
250 };
251 
252 static const void *phone_raw_iface_2_desc[] = {
253 	phone_raw_desc_30,
254 	phone_raw_desc_31,
255 	NULL,
256 };
257 
258 static const void *phone_raw_ep_2_desc[] = {
259 	phone_raw_desc_32,
260 	NULL,
261 };
262 
263 static const struct usb_temp_endpoint_desc phone_isoc_out_ep = {
264 	.ppRawDesc = phone_raw_ep_2_desc,
265 	.pPacketSize = &phone_isoc_mps,
266 	.pIntervals = &phone_isoc_interval,
267 	.bEndpointAddress = UE_DIR_OUT,
268 	.bmAttributes = UE_ISOCHRONOUS,
269 };
270 
271 static const struct usb_temp_endpoint_desc *phone_iface_2_ep[] = {
272 	&phone_isoc_out_ep,
273 	NULL,
274 };
275 
276 static const struct usb_temp_interface_desc phone_iface_2_alt_0 = {
277 	.ppEndpoints = NULL,		/* no endpoints */
278 	.ppRawDesc = NULL,		/* no raw descriptors */
279 	.bInterfaceClass = UICLASS_AUDIO,
280 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
281 	.bInterfaceProtocol = 0,
282 	.iInterface = PHONE_RECORD_INDEX,
283 };
284 
285 static const struct usb_temp_interface_desc phone_iface_2_alt_1 = {
286 	.ppEndpoints = phone_iface_2_ep,
287 	.ppRawDesc = phone_raw_iface_2_desc,
288 	.bInterfaceClass = UICLASS_AUDIO,
289 	.bInterfaceSubClass = UISUBCLASS_AUDIOSTREAM,
290 	.bInterfaceProtocol = 0,
291 	.iInterface = PHONE_RECORD_INDEX,
292 	.isAltInterface = 1,		/* this is an alternate setting */
293 };
294 
295 static const uint8_t phone_hid_raw_desc_0[] = {
296 	0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, sizeof(phone_hid_descriptor),
297 	0x00
298 };
299 
300 static const void *phone_hid_desc_0[] = {
301 	phone_hid_raw_desc_0,
302 	NULL,
303 };
304 
305 static const struct usb_temp_packet_size phone_hid_mps = {
306 	.mps[USB_SPEED_FULL] = 0x10,
307 	.mps[USB_SPEED_HIGH] = 0x10,
308 };
309 
310 static const struct usb_temp_interval phone_hid_interval = {
311 	.bInterval[USB_SPEED_FULL] = 2,		/* 2ms */
312 	.bInterval[USB_SPEED_HIGH] = 2,		/* 2ms */
313 };
314 
315 static const struct usb_temp_endpoint_desc phone_hid_in_ep = {
316 	.pPacketSize = &phone_hid_mps,
317 	.pIntervals = &phone_hid_interval,
318 	.bEndpointAddress = UE_DIR_IN,
319 	.bmAttributes = UE_INTERRUPT,
320 };
321 
322 static const struct usb_temp_endpoint_desc *phone_iface_3_ep[] = {
323 	&phone_hid_in_ep,
324 	NULL,
325 };
326 
327 static const struct usb_temp_interface_desc phone_iface_3 = {
328 	.ppEndpoints = phone_iface_3_ep,
329 	.ppRawDesc = phone_hid_desc_0,
330 	.bInterfaceClass = UICLASS_HID,
331 	.bInterfaceSubClass = 0,
332 	.bInterfaceProtocol = 0,
333 	.iInterface = PHONE_HID_INDEX,
334 };
335 
336 static const struct usb_temp_interface_desc *phone_interfaces[] = {
337 	&phone_iface_0,
338 	&phone_iface_1_alt_0,
339 	&phone_iface_1_alt_1,
340 	&phone_iface_2_alt_0,
341 	&phone_iface_2_alt_1,
342 	&phone_iface_3,
343 	NULL,
344 };
345 
346 static const struct usb_temp_config_desc phone_config_desc = {
347 	.ppIfaceDesc = phone_interfaces,
348 	.bmAttributes = UC_BUS_POWERED,
349 	.bMaxPower = 25,		/* 50 mA */
350 	.iConfiguration = PHONE_PRODUCT_INDEX,
351 };
352 
353 static const struct usb_temp_config_desc *phone_configs[] = {
354 	&phone_config_desc,
355 	NULL,
356 };
357 
358 static usb_temp_get_string_desc_t phone_get_string_desc;
359 static usb_temp_get_vendor_desc_t phone_get_vendor_desc;
360 
361 struct usb_temp_device_desc usb_template_phone = {
362 	.getStringDesc = &phone_get_string_desc,
363 	.getVendorDesc = &phone_get_vendor_desc,
364 	.ppConfigDesc = phone_configs,
365 	.idVendor = USB_TEMPLATE_VENDOR,
366 	.idProduct = 0xb001,
367 	.bcdDevice = 0x0100,
368 	.bDeviceClass = UDCLASS_IN_INTERFACE,
369 	.bDeviceSubClass = 0,
370 	.bDeviceProtocol = 0,
371 	.iManufacturer = PHONE_MANUFACTURER_INDEX,
372 	.iProduct = PHONE_PRODUCT_INDEX,
373 	.iSerialNumber = PHONE_SERIAL_NUMBER_INDEX,
374 };
375 
376 /*------------------------------------------------------------------------*
377  *      phone_get_vendor_desc
378  *
379  * Return values:
380  * NULL: Failure. No such vendor descriptor.
381  * Else: Success. Pointer to vendor descriptor is returned.
382  *------------------------------------------------------------------------*/
383 static const void *
384 phone_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
385 {
386 	if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) &&
387 	    (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) &&
388 	    (req->wIndex[1] == 0) && (req->wIndex[0] == 3 /* iface */)) {
389 
390 		*plen = sizeof(phone_hid_descriptor);
391 		return (phone_hid_descriptor);
392 	}
393 	return (NULL);
394 }
395 
396 /*------------------------------------------------------------------------*
397  *	phone_get_string_desc
398  *
399  * Return values:
400  * NULL: Failure. No such string.
401  * Else: Success. Pointer to string descriptor is returned.
402  *------------------------------------------------------------------------*/
403 static const void *
404 phone_get_string_desc(uint16_t lang_id, uint8_t string_index)
405 {
406 	static const void *ptr[PHONE_MAX_INDEX] = {
407 		[PHONE_LANG_INDEX] = &usb_string_lang_en,
408 		[PHONE_MIXER_INDEX] = &phone_mixer,
409 		[PHONE_RECORD_INDEX] = &phone_record,
410 		[PHONE_PLAYBACK_INDEX] = &phone_playback,
411 		[PHONE_HID_INDEX] = &phone_hid,
412 		[PHONE_MANUFACTURER_INDEX] = &phone_manufacturer,
413 		[PHONE_PRODUCT_INDEX] = &phone_product,
414 		[PHONE_SERIAL_NUMBER_INDEX] = &phone_serial_number,
415 	};
416 
417 	if (string_index == 0) {
418 		return (&usb_string_lang_en);
419 	}
420 	if (lang_id != 0x0409) {
421 		return (NULL);
422 	}
423 	if (string_index < PHONE_MAX_INDEX) {
424 		return (ptr[string_index]);
425 	}
426 	return (NULL);
427 }
428 
429 static void
430 phone_init(void *arg __unused)
431 {
432 	struct sysctl_oid *parent;
433 	char parent_name[3];
434 
435 	usb_make_str_desc(&phone_mixer, sizeof(phone_mixer),
436 	    PHONE_DEFAULT_MIXER);
437 	usb_make_str_desc(&phone_record, sizeof(phone_record),
438 	    PHONE_DEFAULT_RECORD);
439 	usb_make_str_desc(&phone_playback, sizeof(phone_playback),
440 	    PHONE_DEFAULT_PLAYBACK);
441 	usb_make_str_desc(&phone_hid, sizeof(phone_hid),
442 	    PHONE_DEFAULT_HID);
443 	usb_make_str_desc(&phone_manufacturer, sizeof(phone_manufacturer),
444 	    PHONE_DEFAULT_MANUFACTURER);
445 	usb_make_str_desc(&phone_product, sizeof(phone_product),
446 	    PHONE_DEFAULT_PRODUCT);
447 	usb_make_str_desc(&phone_serial_number, sizeof(phone_serial_number),
448 	    PHONE_DEFAULT_SERIAL_NUMBER);
449 
450 	snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_PHONE);
451 	sysctl_ctx_init(&phone_ctx_list);
452 
453 	parent = SYSCTL_ADD_NODE(&phone_ctx_list,
454 	    SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
455 	    parent_name, CTLFLAG_RW,
456 	    0, "USB Phone device side template");
457 	SYSCTL_ADD_U16(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
458 	    "vendor_id", CTLFLAG_RWTUN,
459 	    &usb_template_cdce.idVendor, 1, "Vendor identifier");
460 	SYSCTL_ADD_U16(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
461 	    "product_id", CTLFLAG_RWTUN,
462 	    &usb_template_cdce.idProduct, 1, "Product identifier");
463 #if 0
464 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
465 	    "mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
466 	    &phone_mixer, sizeof(phone_mixer), usb_temp_sysctl,
467 	    "A", "Mixer interface string");
468 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
469 	    "record", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
470 	    &phone_record, sizeof(phone_record), usb_temp_sysctl,
471 	    "A", "Record interface string");
472 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
473 	    "playback", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
474 	    &phone_playback, sizeof(phone_playback), usb_temp_sysctl,
475 	    "A", "Playback interface string");
476 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
477 	    "hid", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
478 	    &phone_hid, sizeof(phone_hid), usb_temp_sysctl,
479 	    "A", "HID interface string");
480 #endif
481 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
482 	    "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
483 	    &phone_manufacturer, sizeof(phone_manufacturer), usb_temp_sysctl,
484 	    "A", "Manufacturer string");
485 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
486 	    "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
487 	    &phone_product, sizeof(phone_product), usb_temp_sysctl,
488 	    "A", "Product string");
489 	SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
490 	    "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
491 	    &phone_serial_number, sizeof(phone_serial_number), usb_temp_sysctl,
492 	    "A", "Serial number string");
493 }
494 
495 static void
496 phone_uninit(void *arg __unused)
497 {
498 
499 	sysctl_ctx_free(&phone_ctx_list);
500 }
501 
502 SYSINIT(phone_init, SI_SUB_LOCK, SI_ORDER_FIRST, phone_init, NULL);
503 SYSUNINIT(phone_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, phone_uninit, NULL);
504