FreeBSD kernel usb device Code
usb_template_modem.c
Go to the documentation of this file.
1/* $FreeBSD$ */
2/*-
3 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 *
5 * Copyright (c) 2010 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 Modem 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 {
77};
78
79#define MODEM_DEFAULT_VENDOR_ID USB_TEMPLATE_VENDOR
80#define MODEM_DEFAULT_PRODUCT_ID 0x27dd
81#define MODEM_DEFAULT_INTERFACE "Virtual serial port"
82#define MODEM_DEFAULT_MANUFACTURER USB_TEMPLATE_MANUFACTURER
83#define MODEM_DEFAULT_PRODUCT "Virtual serial port"
84/*
85 * The reason for this being called like this is that OSX
86 * derives the device node name from it, resulting in a somewhat
87 * user-friendly "/dev/cu.usbmodemFreeBSD1". And yes, the "1"
88 * needs to be there, otherwise OSX will mangle it.
89 */
90#define MODEM_DEFAULT_SERIAL_NUMBER "FreeBSD1"
91
96
97static struct sysctl_ctx_list modem_ctx_list;
98
99#define MODEM_IFACE_0 0
100#define MODEM_IFACE_1 1
101
102/* prototypes */
103
105 .mps[USB_SPEED_LOW] = 8,
106 .mps[USB_SPEED_FULL] = 64,
107 .mps[USB_SPEED_HIGH] = 512,
108};
109
111 .mps[USB_SPEED_LOW] = 8,
112 .mps[USB_SPEED_FULL] = 8,
113 .mps[USB_SPEED_HIGH] = 8,
114};
115
117 .bInterval[USB_SPEED_LOW] = 8, /* 8ms */
118 .bInterval[USB_SPEED_FULL] = 8, /* 8ms */
119 .bInterval[USB_SPEED_HIGH] = 7, /* 8ms */
120};
121
122static const struct usb_temp_endpoint_desc modem_ep_0 = {
124 .pIntervals = &modem_intr_interval,
125 .bEndpointAddress = UE_DIR_IN,
126 .bmAttributes = UE_INTERRUPT,
127};
128
129static const struct usb_temp_endpoint_desc modem_ep_1 = {
131 .bEndpointAddress = UE_DIR_OUT,
132 .bmAttributes = UE_BULK,
133};
134
135static const struct usb_temp_endpoint_desc modem_ep_2 = {
137 .bEndpointAddress = UE_DIR_IN,
138 .bmAttributes = UE_BULK,
139};
140
141static const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = {
142 &modem_ep_0,
143 NULL,
144};
145
146static const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = {
147 &modem_ep_1,
148 &modem_ep_2,
149 NULL,
150};
151
152static const uint8_t modem_raw_desc_0[] = {
153 0x05, 0x24, 0x00, 0x10, 0x01
154};
155
156static const uint8_t modem_raw_desc_1[] = {
157 0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1
158};
159
160static const uint8_t modem_raw_desc_2[] = {
161 0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1
162};
163
164static const uint8_t modem_raw_desc_3[] = {
165 0x04, 0x24, 0x02, 0x07
166};
167
168static const void *modem_iface_0_desc[] = {
173 NULL,
174};
175
178 .ppEndpoints = modem_iface_0_ep,
179 .bInterfaceClass = UICLASS_CDC,
180 .bInterfaceSubClass = UISUBCLASS_ABSTRACT_CONTROL_MODEL,
181 .bInterfaceProtocol = UIPROTO_CDC_NONE,
182 .iInterface = MODEM_INTERFACE_INDEX,
183};
184
187 .bInterfaceClass = UICLASS_CDC_DATA,
188 .bInterfaceSubClass = UISUBCLASS_DATA,
189 .bInterfaceProtocol = UIPROTO_CDC_NONE,
190 .iInterface = MODEM_INTERFACE_INDEX,
191};
192
196 NULL,
197};
198
201 .bmAttributes = 0,
202 .bMaxPower = 0,
203 .iConfiguration = MODEM_PRODUCT_INDEX,
204};
205
206static const struct usb_temp_config_desc *modem_configs[] = {
208 NULL,
209};
210
213
216 .getVendorDesc = &modem_get_vendor_desc,
217 .ppConfigDesc = modem_configs,
218 .idVendor = MODEM_DEFAULT_VENDOR_ID,
219 .idProduct = MODEM_DEFAULT_PRODUCT_ID,
220 .bcdDevice = 0x0100,
221 .bDeviceClass = UDCLASS_COMM,
222 .bDeviceSubClass = 0,
223 .bDeviceProtocol = 0,
224 .iManufacturer = MODEM_MANUFACTURER_INDEX,
225 .iProduct = MODEM_PRODUCT_INDEX,
226 .iSerialNumber = MODEM_SERIAL_NUMBER_INDEX,
227};
228
229/*------------------------------------------------------------------------*
230 * modem_get_vendor_desc
231 *
232 * Return values:
233 * NULL: Failure. No such vendor descriptor.
234 * Else: Success. Pointer to vendor descriptor is returned.
235 *------------------------------------------------------------------------*/
236static const void *
238{
239 return (NULL);
240}
241
242/*------------------------------------------------------------------------*
243 * modem_get_string_desc
244 *
245 * Return values:
246 * NULL: Failure. No such string.
247 * Else: Success. Pointer to string descriptor is returned.
248 *------------------------------------------------------------------------*/
249static const void *
250modem_get_string_desc(uint16_t lang_id, uint8_t string_index)
251{
252 static const void *ptr[MODEM_MAX_INDEX] = {
258 };
259
260 if (string_index == 0) {
261 return (&usb_string_lang_en);
262 }
263 if (lang_id != 0x0409) {
264 return (NULL);
265 }
266 if (string_index < MODEM_MAX_INDEX) {
267 return (ptr[string_index]);
268 }
269 return (NULL);
270}
271
272static void
273modem_init(void *arg __unused)
274{
275 struct sysctl_oid *parent;
276 char parent_name[3];
277
286
287 snprintf(parent_name, sizeof(parent_name), "%d", USB_TEMP_MODEM);
288 sysctl_ctx_init(&modem_ctx_list);
289
290 parent = SYSCTL_ADD_NODE(&modem_ctx_list,
291 SYSCTL_STATIC_CHILDREN(_hw_usb_templates), OID_AUTO,
292 parent_name, CTLFLAG_RW | CTLFLAG_MPSAFE,
293 0, "Virtual serial port device side template");
294 SYSCTL_ADD_U16(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
295 "vendor_id", CTLFLAG_RWTUN,
296 &usb_template_modem.idVendor, 1, "Vendor identifier");
297 SYSCTL_ADD_U16(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
298 "product_id", CTLFLAG_RWTUN,
299 &usb_template_modem.idProduct, 1, "Product identifier");
300#if 0
301 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
302 "keyboard", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
304 "A", "Interface string");
305#endif
306 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
307 "manufacturer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
309 "A", "Manufacturer string");
310 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
311 "product", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
313 "A", "Product string");
314 SYSCTL_ADD_PROC(&modem_ctx_list, SYSCTL_CHILDREN(parent), OID_AUTO,
315 "serial_number", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
317 "A", "Serial number string");
318}
319
320static void
321modem_uninit(void *arg __unused)
322{
323
324 sysctl_ctx_free(&modem_ctx_list);
325}
326
327SYSINIT(modem_init, SI_SUB_LOCK, SI_ORDER_FIRST, modem_init, NULL);
328SYSUNINIT(modem_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, modem_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 struct usb_temp_endpoint_desc ** ppEndpoints
Definition: usb_template.h:70
const void ** ppRawDesc
Definition: usb_template.h:69
uint8_t bInterval[USB_SPEED_MAX]
Definition: usb_template.h:52
uint16_t mps[USB_SPEED_MAX]
Definition: usb_template.h:48
#define UIPROTO_CDC_NONE
Definition: usb.h:449
#define UE_INTERRUPT
Definition: usb.h:544
#define UICLASS_CDC_DATA
Definition: usb.h:485
#define UE_BULK
Definition: usb.h:543
#define UE_DIR_IN
Definition: usb.h:531
#define UICLASS_CDC
Definition: usb.h:434
@ USB_SPEED_LOW
Definition: usb.h:753
@ USB_SPEED_FULL
Definition: usb.h:754
@ USB_SPEED_HIGH
Definition: usb.h:755
#define UE_DIR_OUT
Definition: usb.h:532
#define UISUBCLASS_ABSTRACT_CONTROL_MODEL
Definition: usb.h:436
#define UISUBCLASS_DATA
Definition: usb.h:486
#define UDCLASS_COMM
Definition: usb.h:372
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_MODEM
Definition: usb_ioctl.h:55
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
static const struct usb_temp_interface_desc modem_iface_1
#define MODEM_DEFAULT_PRODUCT_ID
@ MODEM_PRODUCT_INDEX
@ MODEM_INTERFACE_INDEX
@ MODEM_MAX_INDEX
@ MODEM_MANUFACTURER_INDEX
@ MODEM_SERIAL_NUMBER_INDEX
@ MODEM_LANG_INDEX
SYSINIT(modem_init, SI_SUB_LOCK, SI_ORDER_FIRST, modem_init, NULL)
static struct usb_string_descriptor modem_serial_number
#define MODEM_DEFAULT_VENDOR_ID
#define MODEM_DEFAULT_MANUFACTURER
struct usb_temp_device_desc usb_template_modem
#define MODEM_DEFAULT_INTERFACE
static const struct usb_temp_config_desc * modem_configs[]
static const uint8_t modem_raw_desc_0[]
static const struct usb_temp_interval modem_intr_interval
static void modem_init(void *arg __unused)
static struct usb_string_descriptor modem_interface
SYSUNINIT(modem_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, modem_uninit, NULL)
static const struct usb_temp_packet_size modem_intr_mps
static const struct usb_temp_packet_size modem_bulk_mps
#define MODEM_DEFAULT_SERIAL_NUMBER
static usb_temp_get_string_desc_t modem_get_string_desc
static usb_temp_get_vendor_desc_t modem_get_vendor_desc
static const struct usb_temp_interface_desc * modem_interfaces[]
static const uint8_t modem_raw_desc_1[]
static const struct usb_temp_endpoint_desc modem_ep_0
static void modem_uninit(void *arg __unused)
static const uint8_t modem_raw_desc_3[]
#define MODEM_IFACE_1
#define MODEM_DEFAULT_PRODUCT
static const struct usb_temp_endpoint_desc * modem_iface_0_ep[]
static const struct usb_temp_endpoint_desc * modem_iface_1_ep[]
static const void * modem_iface_0_desc[]
static struct usb_string_descriptor modem_manufacturer
#define MODEM_IFACE_0
static const struct usb_temp_endpoint_desc modem_ep_1
static const struct usb_temp_config_desc modem_config_desc
static const struct usb_temp_interface_desc modem_iface_0
static struct sysctl_ctx_list modem_ctx_list
static struct usb_string_descriptor modem_product
static const uint8_t modem_raw_desc_2[]
static const struct usb_temp_endpoint_desc modem_ep_2
uint8_t usb_make_str_desc(void *ptr, uint16_t max_len, const char *s)
Definition: usb_util.c:193