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