3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 * Copyright (c) 2014 Hans Petter Selasky
6 * Copyright (c) 2018 The FreeBSD Foundation
9 * Portions of this software were developed by Edward Tomasz Napierala
10 * under sponsorship from the FreeBSD Foundation.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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.
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
35 * This file contains the USB template for an USB phone device.
38 #ifdef USB_GLOBAL_INCLUDE_FILE
39 #include USB_GLOBAL_INCLUDE_FILE
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>
49 #include <sys/module.h>
51 #include <sys/mutex.h>
52 #include <sys/condvar.h>
53 #include <sys/sysctl.h>
55 #include <sys/unistd.h>
56 #include <sys/callout.h>
57 #include <sys/malloc.h>
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>
67 #include <dev/usb/template/usb_template.h>
68 #endif /* USB_GLOBAL_INCLUDE_FILE */
76 PHONE_MANUFACTURER_INDEX,
78 PHONE_SERIAL_NUMBER_INDEX,
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"
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;
98 static struct sysctl_ctx_list phone_ctx_list;
103 * Phone Mixer description structures
105 * Some of the phone descriptors were dumped from no longer in
106 * production Yealink VOIP USB phone adapter:
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
116 static const uint8_t phone_raw_desc_0[] = {
117 0x0a, 0x24, 0x01, 0x00, 0x01, 0x4a, 0x00, 0x02,
121 static const uint8_t phone_raw_desc_1[] = {
122 0x0c, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00, 0x01,
123 0x00, 0x00, 0x00, 0x00
126 static const uint8_t phone_raw_desc_2[] = {
127 0x0c, 0x24, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01,
128 0x00, 0x00, 0x00, 0x00
131 static const uint8_t phone_raw_desc_3[] = {
132 0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x06,
136 static const uint8_t phone_raw_desc_4[] = {
137 0x09, 0x24, 0x03, 0x04, 0x01, 0x01, 0x00, 0x05,
141 static const uint8_t phone_raw_desc_5[] = {
142 0x0b, 0x24, 0x06, 0x05, 0x01, 0x02, 0x03, 0x00,
146 static const uint8_t phone_raw_desc_6[] = {
147 0x0b, 0x24, 0x06, 0x06, 0x02, 0x02, 0x03, 0x00,
151 static const void *phone_raw_iface_0_desc[] = {
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,
171 static const uint8_t phone_raw_desc_20[] = {
172 0x07, 0x24, 0x01, 0x04, 0x01, 0x01, 0x00
175 static const uint8_t phone_raw_desc_21[] = {
176 0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
181 static const uint8_t phone_raw_desc_22[] = {
182 0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
185 static const void *phone_raw_iface_1_desc[] = {
191 static const void *phone_raw_ep_1_desc[] = {
196 static const struct usb_temp_packet_size phone_isoc_mps = {
197 .mps[USB_SPEED_FULL] = 0x10,
198 .mps[USB_SPEED_HIGH] = 0x10,
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 */
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,
214 static const struct usb_temp_endpoint_desc *phone_iface_1_ep[] = {
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,
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 */
238 static const uint8_t phone_raw_desc_30[] = {
239 0x07, 0x24, 0x01, 0x02, 0x01, 0x01, 0x00
242 static const uint8_t phone_raw_desc_31[] = {
243 0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
248 static const uint8_t phone_raw_desc_32[] = {
249 0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
252 static const void *phone_raw_iface_2_desc[] = {
258 static const void *phone_raw_ep_2_desc[] = {
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,
271 static const struct usb_temp_endpoint_desc *phone_iface_2_ep[] = {
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,
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 */
295 static const uint8_t phone_hid_raw_desc_0[] = {
296 0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, sizeof(phone_hid_descriptor),
300 static const void *phone_hid_desc_0[] = {
301 phone_hid_raw_desc_0,
305 static const struct usb_temp_packet_size phone_hid_mps = {
306 .mps[USB_SPEED_FULL] = 0x10,
307 .mps[USB_SPEED_HIGH] = 0x10,
310 static const struct usb_temp_interval phone_hid_interval = {
311 .bInterval[USB_SPEED_FULL] = 2, /* 2ms */
312 .bInterval[USB_SPEED_HIGH] = 2, /* 2ms */
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,
322 static const struct usb_temp_endpoint_desc *phone_iface_3_ep[] = {
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,
336 static const struct usb_temp_interface_desc *phone_interfaces[] = {
338 &phone_iface_1_alt_0,
339 &phone_iface_1_alt_1,
340 &phone_iface_2_alt_0,
341 &phone_iface_2_alt_1,
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,
353 static const struct usb_temp_config_desc *phone_configs[] = {
358 static usb_temp_get_string_desc_t phone_get_string_desc;
359 static usb_temp_get_vendor_desc_t phone_get_vendor_desc;
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,
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,
376 /*------------------------------------------------------------------------*
377 * phone_get_vendor_desc
380 * NULL: Failure. No such vendor descriptor.
381 * Else: Success. Pointer to vendor descriptor is returned.
382 *------------------------------------------------------------------------*/
384 phone_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen)
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 */)) {
390 *plen = sizeof(phone_hid_descriptor);
391 return (phone_hid_descriptor);
396 /*------------------------------------------------------------------------*
397 * phone_get_string_desc
400 * NULL: Failure. No such string.
401 * Else: Success. Pointer to string descriptor is returned.
402 *------------------------------------------------------------------------*/
404 phone_get_string_desc(uint16_t lang_id, uint8_t string_index)
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,
417 if (string_index == 0) {
418 return (&usb_string_lang_en);
420 if (lang_id != 0x0409) {
423 if (string_index < PHONE_MAX_INDEX) {
424 return (ptr[string_index]);
430 phone_init(void *arg __unused)
432 struct sysctl_oid *parent;
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),
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);
450 snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_PHONE);
451 sysctl_ctx_init(&phone_ctx_list);
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");
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");
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");
496 phone_uninit(void *arg __unused)
499 sysctl_ctx_free(&phone_ctx_list);
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);