]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/template/usb_template_phone.c
Merge ACPICA 20180313.
[FreeBSD/FreeBSD.git] / sys / dev / usb / template / usb_template_phone.c
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);