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