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);
Cache object: 3298c18247a84b11dcb265e3c27fcc8a
|