FreeBSD kernel usb device Code
usb_template_phone.c
Go to the documentation of this file.
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
68#endif /* USB_GLOBAL_INCLUDE_FILE */
69
70enum {
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
99
100static 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 */
110static 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
118static const uint8_t phone_raw_desc_0[] = {
119 0x0a, 0x24, 0x01, 0x00, 0x01, 0x4a, 0x00, 0x02,
120 0x01, 0x02
121};
122
123static const uint8_t phone_raw_desc_1[] = {
124 0x0c, 0x24, 0x02, 0x01, 0x01, 0x02, 0x00, 0x01,
125 0x00, 0x00, 0x00, 0x00
126};
127
128static const uint8_t phone_raw_desc_2[] = {
129 0x0c, 0x24, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01,
130 0x00, 0x00, 0x00, 0x00
131};
132
133static const uint8_t phone_raw_desc_3[] = {
134 0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x06,
135 0x00
136};
137
138static const uint8_t phone_raw_desc_4[] = {
139 0x09, 0x24, 0x03, 0x04, 0x01, 0x01, 0x00, 0x05,
140 0x00
141};
142
143static const uint8_t phone_raw_desc_5[] = {
144 0x0b, 0x24, 0x06, 0x05, 0x01, 0x02, 0x03, 0x00,
145 0x03, 0x00, 0x00
146};
147
148static const uint8_t phone_raw_desc_6[] = {
149 0x0b, 0x24, 0x06, 0x06, 0x02, 0x02, 0x03, 0x00,
150 0x03, 0x00, 0x00
151};
152
153static const void *phone_raw_iface_0_desc[] = {
161 NULL,
162};
163
165 .ppEndpoints = NULL, /* no endpoints */
167 .bInterfaceClass = UICLASS_AUDIO,
168 .bInterfaceSubClass = UISUBCLASS_AUDIOCONTROL,
169 .bInterfaceProtocol = 0,
170 .iInterface = PHONE_MIXER_INDEX,
171};
172
173static const uint8_t phone_raw_desc_20[] = {
174 0x07, 0x24, 0x01, 0x04, 0x01, 0x01, 0x00
175};
176
177static const uint8_t phone_raw_desc_21[] = {
178 0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
179 /* 8kHz */
180 0x40, 0x1f, 0x00
181};
182
183static const uint8_t phone_raw_desc_22[] = {
184 0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
185};
186
187static const void *phone_raw_iface_1_desc[] = {
190 NULL,
191};
192
193static const void *phone_raw_ep_1_desc[] = {
195 NULL,
196};
197
199 .mps[USB_SPEED_FULL] = 0x10,
200 .mps[USB_SPEED_HIGH] = 0x10,
201};
202
204 .bInterval[USB_SPEED_FULL] = 1, /* 1:1 */
205 .bInterval[USB_SPEED_HIGH] = 4, /* 1:8 */
206};
207
210 .pPacketSize = &phone_isoc_mps,
211 .pIntervals = &phone_isoc_interval,
212 .bEndpointAddress = UE_DIR_IN,
213 .bmAttributes = UE_ISOCHRONOUS,
214};
215
216static const struct usb_temp_endpoint_desc *phone_iface_1_ep[] = {
218 NULL,
219};
220
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
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
240static const uint8_t phone_raw_desc_30[] = {
241 0x07, 0x24, 0x01, 0x02, 0x01, 0x01, 0x00
242};
243
244static const uint8_t phone_raw_desc_31[] = {
245 0x0b, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x01,
246 /* 8kHz */
247 0x40, 0x1f, 0x00
248};
249
250static const uint8_t phone_raw_desc_32[] = {
251 0x07, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00
252};
253
254static const void *phone_raw_iface_2_desc[] = {
257 NULL,
258};
259
260static const void *phone_raw_ep_2_desc[] = {
262 NULL,
263};
264
267 .pPacketSize = &phone_isoc_mps,
268 .pIntervals = &phone_isoc_interval,
269 .bEndpointAddress = UE_DIR_OUT,
270 .bmAttributes = UE_ISOCHRONOUS,
271};
272
273static const struct usb_temp_endpoint_desc *phone_iface_2_ep[] = {
275 NULL,
276};
277
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
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
297static const uint8_t phone_hid_raw_desc_0[] = {
298 0x09, 0x21, 0x00, 0x01, 0x00, 0x01, 0x22, sizeof(phone_hid_descriptor),
299 0x00
300};
301
302static const void *phone_hid_desc_0[] = {
304 NULL,
305};
306
307static const struct usb_temp_packet_size phone_hid_mps = {
308 .mps[USB_SPEED_FULL] = 0x10,
309 .mps[USB_SPEED_HIGH] = 0x10,
310};
311
313 .bInterval[USB_SPEED_FULL] = 2, /* 2ms */
314 .bInterval[USB_SPEED_HIGH] = 2, /* 2ms */
315};
316
319 .pIntervals = &phone_hid_interval,
320 .bEndpointAddress = UE_DIR_IN,
321 .bmAttributes = UE_INTERRUPT,
322};
323
324static const struct usb_temp_endpoint_desc *phone_iface_3_ep[] = {
326 NULL,
327};
328
332 .bInterfaceClass = UICLASS_HID,
333 .bInterfaceSubClass = 0,
334 .bInterfaceProtocol = 0,
335 .iInterface = PHONE_HID_INDEX,
336};
337
345 NULL,
346};
347
350 .bmAttributes = 0,
351 .bMaxPower = 0,
352 .iConfiguration = PHONE_PRODUCT_INDEX,
353};
354
355static const struct usb_temp_config_desc *phone_configs[] = {
357 NULL,
358};
359
362
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 *------------------------------------------------------------------------*/
385static const void *
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 *------------------------------------------------------------------------*/
404static const void *
405phone_get_string_desc(uint16_t lang_id, uint8_t string_index)
406{
407 static const void *ptr[PHONE_MAX_INDEX] = {
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
430static void
431phone_init(void *arg __unused)
432{
433 struct sysctl_oid *parent;
434 char parent_name[3];
435
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,
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,
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,
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,
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,
485 "A", "Manufacturer string");
486 SYSCTL_ADD_PROC(&phone_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
487 "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
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,
493 "A", "Serial number string");
494}
495
496static void
497phone_uninit(void *arg __unused)
498{
499
500 sysctl_ctx_free(&phone_ctx_list);
501}
502
503SYSINIT(phone_init, SI_SUB_LOCK, SI_ORDER_FIRST, phone_init, NULL);
504SYSUNINIT(phone_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, phone_uninit, NULL);
const struct usb_temp_interface_desc ** ppIfaceDesc
Definition: usb_template.h:79
usb_temp_get_string_desc_t * getStringDesc
Definition: usb_template.h:86
const struct usb_temp_packet_size * pPacketSize
Definition: usb_template.h:57
const void ** ppRawDesc
Definition: usb_template.h:56
const struct usb_temp_endpoint_desc ** ppEndpoints
Definition: usb_template.h:70
uint8_t bInterval[USB_SPEED_MAX]
Definition: usb_template.h:52
uint16_t mps[USB_SPEED_MAX]
Definition: usb_template.h:48
#define UE_INTERRUPT
Definition: usb.h:544
#define UE_DIR_IN
Definition: usb.h:531
#define UICLASS_HID
Definition: usb.h:453
#define UISUBCLASS_AUDIOSTREAM
Definition: usb.h:431
@ USB_SPEED_FULL
Definition: usb.h:754
@ USB_SPEED_HIGH
Definition: usb.h:755
#define UE_DIR_OUT
Definition: usb.h:532
#define UICLASS_AUDIO
Definition: usb.h:429
#define UISUBCLASS_AUDIOCONTROL
Definition: usb.h:430
#define UE_ISOCHRONOUS
Definition: usb.h:542
#define UDCLASS_IN_INTERFACE
Definition: usb.h:371
const struct usb_string_lang usb_string_lang_en
Definition: usb_core.c:63
uint16_t * plen
Definition: usb_if.m:53
const void * req
Definition: usb_if.m:51
@ USB_TEMP_PHONE
Definition: usb_ioctl.h:59
int usb_temp_sysctl(SYSCTL_HANDLER_ARGS)
Definition: usb_template.c:173
const void *() usb_temp_get_vendor_desc_t(const struct usb_device_request *req, uint16_t *plen)
Definition: usb_template.h:45
const void *() usb_temp_get_string_desc_t(uint16_t lang_id, uint8_t string_index)
Definition: usb_template.h:44
struct usb_temp_device_desc usb_template_cdce
static const uint8_t phone_raw_desc_32[]
static const uint8_t phone_raw_desc_31[]
static const uint8_t phone_raw_desc_4[]
#define PHONE_DEFAULT_RECORD
static const struct usb_temp_interface_desc phone_iface_3
#define PHONE_DEFAULT_HID
static struct sysctl_ctx_list phone_ctx_list
static const void * phone_raw_ep_2_desc[]
static const void * phone_raw_iface_2_desc[]
static const uint8_t phone_raw_desc_30[]
static const uint8_t phone_raw_desc_21[]
static const struct usb_temp_endpoint_desc phone_isoc_out_ep
static const uint8_t phone_raw_desc_0[]
static const struct usb_temp_packet_size phone_isoc_mps
static const struct usb_temp_interface_desc phone_iface_2_alt_0
static const struct usb_temp_endpoint_desc phone_hid_in_ep
static struct usb_string_descriptor phone_playback
static const struct usb_temp_interval phone_hid_interval
static const struct usb_temp_interface_desc phone_iface_2_alt_1
static const struct usb_temp_endpoint_desc * phone_iface_3_ep[]
#define PHONE_DEFAULT_MIXER
static const void * phone_raw_ep_1_desc[]
static struct usb_string_descriptor phone_serial_number
static const void * phone_raw_iface_0_desc[]
static uint8_t phone_hid_descriptor[]
struct usb_temp_device_desc usb_template_phone
static const struct usb_temp_interface_desc * phone_interfaces[]
static const uint8_t phone_raw_desc_1[]
#define PHONE_DEFAULT_VENDOR_ID
static const uint8_t phone_raw_desc_20[]
static const struct usb_temp_interface_desc phone_iface_1_alt_1
static const struct usb_temp_endpoint_desc * phone_iface_1_ep[]
static const uint8_t phone_raw_desc_5[]
static const struct usb_temp_interval phone_isoc_interval
SYSUNINIT(phone_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, phone_uninit, NULL)
static const uint8_t phone_raw_desc_3[]
static const uint8_t phone_hid_raw_desc_0[]
#define PHONE_DEFAULT_PLAYBACK
static const uint8_t phone_raw_desc_22[]
static const uint8_t phone_raw_desc_6[]
SYSINIT(phone_init, SI_SUB_LOCK, SI_ORDER_FIRST, phone_init, NULL)
static void phone_uninit(void *arg __unused)
static const struct usb_temp_config_desc phone_config_desc
#define PHONE_DEFAULT_SERIAL_NUMBER
#define PHONE_DEFAULT_PRODUCT_ID
static const void * phone_hid_desc_0[]
@ PHONE_RECORD_INDEX
@ PHONE_MAX_INDEX
@ PHONE_PRODUCT_INDEX
@ PHONE_MIXER_INDEX
@ PHONE_LANG_INDEX
@ PHONE_PLAYBACK_INDEX
@ PHONE_HID_INDEX
@ PHONE_MANUFACTURER_INDEX
@ PHONE_SERIAL_NUMBER_INDEX
static const struct usb_temp_endpoint_desc phone_isoc_in_ep
static struct usb_string_descriptor phone_record
static const void * phone_raw_iface_1_desc[]
static struct usb_string_descriptor phone_product
static struct usb_string_descriptor phone_manufacturer
static usb_temp_get_vendor_desc_t phone_get_vendor_desc
static void phone_init(void *arg __unused)
static const struct usb_temp_packet_size phone_hid_mps
static const struct usb_temp_endpoint_desc * phone_iface_2_ep[]
static struct usb_string_descriptor phone_mixer
static const struct usb_temp_config_desc * phone_configs[]
static usb_temp_get_string_desc_t phone_get_string_desc
static struct usb_string_descriptor phone_hid
#define PHONE_DEFAULT_MANUFACTURER
static const uint8_t phone_raw_desc_2[]
#define PHONE_DEFAULT_PRODUCT
static const struct usb_temp_interface_desc phone_iface_0
static const struct usb_temp_interface_desc phone_iface_1_alt_0
uint8_t usb_make_str_desc(void *ptr, uint16_t max_len, const char *s)
Definition: usb_util.c:193