Deleted Added
full compact
ufoma.c (187970) ufoma.c (188413)
1/* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */
2
3#include <sys/cdefs.h>
1/* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */
2
3#include <sys/cdefs.h>
4__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/ufoma2.c 187970 2009-02-01 00:51:25Z thompsa $");
4__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/ufoma2.c 188413 2009-02-09 22:05:25Z thompsa $");
5#define UFOMA_HANDSFREE
6/*-
7 * Copyright (c) 2005, Takanori Watanabe
8 * Copyright (c) 2003, M. Warner Losh <imp@freebsd.org>.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*-
34 * Copyright (c) 1998 The NetBSD Foundation, Inc.
35 * All rights reserved.
36 *
37 * This code is derived from software contributed to The NetBSD Foundation
38 * by Lennart Augustsson (lennart@augustsson.net) at
39 * Carlstedt Research & Technology.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. All advertising materials mentioning features or use of this software
50 * must display the following acknowledgement:
51 * This product includes software developed by the NetBSD
52 * Foundation, Inc. and its contributors.
53 * 4. Neither the name of The NetBSD Foundation nor the names of its
54 * contributors may be used to endorse or promote products derived
55 * from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
58 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
60 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
61 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
62 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
63 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
66 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67 * POSSIBILITY OF SUCH DAMAGE.
68 */
69
70/*
71 * Comm Class spec: http://www.usb.org/developers/devclass_docs/usbccs10.pdf
72 * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
73 */
74
75/*
76 * TODO:
77 * - Implement a Call Device for modems without multiplexed commands.
78 */
79
80/*
81 * NOTE: all function names beginning like "ufoma_cfg_" can only
82 * be called from within the config thread function !
83 */
84
85#include <dev/usb2/include/usb2_devid.h>
86#include <dev/usb2/include/usb2_standard.h>
87#include <dev/usb2/include/usb2_mfunc.h>
88#include <dev/usb2/include/usb2_error.h>
89#include <dev/usb2/include/usb2_cdc.h>
90
91#define USB_DEBUG_VAR usb2_debug
92
93#include <dev/usb2/core/usb2_core.h>
94#include <dev/usb2/core/usb2_debug.h>
95#include <dev/usb2/core/usb2_process.h>
96#include <dev/usb2/core/usb2_request.h>
97#include <dev/usb2/core/usb2_lookup.h>
98#include <dev/usb2/core/usb2_util.h>
99#include <dev/usb2/core/usb2_parse.h>
100#include <dev/usb2/core/usb2_busdma.h>
101
102#include <dev/usb2/serial/usb2_serial.h>
103#include <sys/sysctl.h>
104#include <sys/sbuf.h>
105
106typedef struct ufoma_mobile_acm_descriptor {
107 uint8_t bFunctionLength;
108 uint8_t bDescriptorType;
109 uint8_t bDescriptorSubtype;
110 uint8_t bType;
111 uint8_t bMode[1];
112} __packed usb2_mcpc_acm_descriptor;
113
114#define UISUBCLASS_MCPC 0x88
115
116#define UDESC_VS_INTERFACE 0x44
117#define UDESCSUB_MCPC_ACM 0x11
118
119#define UMCPC_ACM_TYPE_AB1 0x1
120#define UMCPC_ACM_TYPE_AB2 0x2
121#define UMCPC_ACM_TYPE_AB5 0x5
122#define UMCPC_ACM_TYPE_AB6 0x6
123
124#define UMCPC_ACM_MODE_DEACTIVATED 0x0
125#define UMCPC_ACM_MODE_MODEM 0x1
126#define UMCPC_ACM_MODE_ATCOMMAND 0x2
127#define UMCPC_ACM_MODE_OBEX 0x60
128#define UMCPC_ACM_MODE_VENDOR1 0xc0
129#define UMCPC_ACM_MODE_VENDOR2 0xfe
130#define UMCPC_ACM_MODE_UNLINKED 0xff
131
132#define UMCPC_CM_MOBILE_ACM 0x0
133
134#define UMCPC_ACTIVATE_MODE 0x60
135#define UMCPC_GET_MODETABLE 0x61
136#define UMCPC_SET_LINK 0x62
137#define UMCPC_CLEAR_LINK 0x63
138
139#define UMCPC_REQUEST_ACKNOWLEDGE 0x31
140
141#define UFOMA_MAX_TIMEOUT 15 /* standard says 10 seconds */
142#define UFOMA_CMD_BUF_SIZE 64 /* bytes */
143
144#define UFOMA_BULK_BUF_SIZE 1024 /* bytes */
145
146enum {
147 UFOMA_CTRL_ENDPT_INTR,
5#define UFOMA_HANDSFREE
6/*-
7 * Copyright (c) 2005, Takanori Watanabe
8 * Copyright (c) 2003, M. Warner Losh <imp@freebsd.org>.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*-
34 * Copyright (c) 1998 The NetBSD Foundation, Inc.
35 * All rights reserved.
36 *
37 * This code is derived from software contributed to The NetBSD Foundation
38 * by Lennart Augustsson (lennart@augustsson.net) at
39 * Carlstedt Research & Technology.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. All advertising materials mentioning features or use of this software
50 * must display the following acknowledgement:
51 * This product includes software developed by the NetBSD
52 * Foundation, Inc. and its contributors.
53 * 4. Neither the name of The NetBSD Foundation nor the names of its
54 * contributors may be used to endorse or promote products derived
55 * from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
58 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
60 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
61 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
62 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
63 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
66 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67 * POSSIBILITY OF SUCH DAMAGE.
68 */
69
70/*
71 * Comm Class spec: http://www.usb.org/developers/devclass_docs/usbccs10.pdf
72 * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf
73 */
74
75/*
76 * TODO:
77 * - Implement a Call Device for modems without multiplexed commands.
78 */
79
80/*
81 * NOTE: all function names beginning like "ufoma_cfg_" can only
82 * be called from within the config thread function !
83 */
84
85#include <dev/usb2/include/usb2_devid.h>
86#include <dev/usb2/include/usb2_standard.h>
87#include <dev/usb2/include/usb2_mfunc.h>
88#include <dev/usb2/include/usb2_error.h>
89#include <dev/usb2/include/usb2_cdc.h>
90
91#define USB_DEBUG_VAR usb2_debug
92
93#include <dev/usb2/core/usb2_core.h>
94#include <dev/usb2/core/usb2_debug.h>
95#include <dev/usb2/core/usb2_process.h>
96#include <dev/usb2/core/usb2_request.h>
97#include <dev/usb2/core/usb2_lookup.h>
98#include <dev/usb2/core/usb2_util.h>
99#include <dev/usb2/core/usb2_parse.h>
100#include <dev/usb2/core/usb2_busdma.h>
101
102#include <dev/usb2/serial/usb2_serial.h>
103#include <sys/sysctl.h>
104#include <sys/sbuf.h>
105
106typedef struct ufoma_mobile_acm_descriptor {
107 uint8_t bFunctionLength;
108 uint8_t bDescriptorType;
109 uint8_t bDescriptorSubtype;
110 uint8_t bType;
111 uint8_t bMode[1];
112} __packed usb2_mcpc_acm_descriptor;
113
114#define UISUBCLASS_MCPC 0x88
115
116#define UDESC_VS_INTERFACE 0x44
117#define UDESCSUB_MCPC_ACM 0x11
118
119#define UMCPC_ACM_TYPE_AB1 0x1
120#define UMCPC_ACM_TYPE_AB2 0x2
121#define UMCPC_ACM_TYPE_AB5 0x5
122#define UMCPC_ACM_TYPE_AB6 0x6
123
124#define UMCPC_ACM_MODE_DEACTIVATED 0x0
125#define UMCPC_ACM_MODE_MODEM 0x1
126#define UMCPC_ACM_MODE_ATCOMMAND 0x2
127#define UMCPC_ACM_MODE_OBEX 0x60
128#define UMCPC_ACM_MODE_VENDOR1 0xc0
129#define UMCPC_ACM_MODE_VENDOR2 0xfe
130#define UMCPC_ACM_MODE_UNLINKED 0xff
131
132#define UMCPC_CM_MOBILE_ACM 0x0
133
134#define UMCPC_ACTIVATE_MODE 0x60
135#define UMCPC_GET_MODETABLE 0x61
136#define UMCPC_SET_LINK 0x62
137#define UMCPC_CLEAR_LINK 0x63
138
139#define UMCPC_REQUEST_ACKNOWLEDGE 0x31
140
141#define UFOMA_MAX_TIMEOUT 15 /* standard says 10 seconds */
142#define UFOMA_CMD_BUF_SIZE 64 /* bytes */
143
144#define UFOMA_BULK_BUF_SIZE 1024 /* bytes */
145
146enum {
147 UFOMA_CTRL_ENDPT_INTR,
148 UFOMA_CTRL_ENDPT_INTR_CLEAR,
149 UFOMA_CTRL_ENDPT_READ,
150 UFOMA_CTRL_ENDPT_WRITE,
148 UFOMA_CTRL_ENDPT_READ,
149 UFOMA_CTRL_ENDPT_WRITE,
151 UFOMA_CTRL_ENDPT_MAX = 4,
150 UFOMA_CTRL_ENDPT_MAX,
152};
153
154enum {
155 UFOMA_BULK_ENDPT_WRITE,
156 UFOMA_BULK_ENDPT_READ,
151};
152
153enum {
154 UFOMA_BULK_ENDPT_WRITE,
155 UFOMA_BULK_ENDPT_READ,
157 UFOMA_BULK_ENDPT_WRITE_CLEAR,
158 UFOMA_BULK_ENDPT_READ_CLEAR,
159 UFOMA_BULK_ENDPT_MAX = 4,
156 UFOMA_BULK_ENDPT_MAX,
160};
161
162struct ufoma_softc {
163 struct usb2_com_super_softc sc_super_ucom;
164 struct usb2_com_softc sc_ucom;
165 struct cv sc_cv;
166
167 struct usb2_xfer *sc_ctrl_xfer[UFOMA_CTRL_ENDPT_MAX];
168 struct usb2_xfer *sc_bulk_xfer[UFOMA_BULK_ENDPT_MAX];
169 uint8_t *sc_modetable;
170 device_t sc_dev;
171 struct usb2_device *sc_udev;
172
173 uint32_t sc_unit;
174
175 uint16_t sc_line;
176
177 uint8_t sc_num_msg;
178 uint8_t sc_nobulk;
179 uint8_t sc_ctrl_iface_no;
180 uint8_t sc_ctrl_iface_index;
181 uint8_t sc_data_iface_no;
182 uint8_t sc_data_iface_index;
183 uint8_t sc_cm_cap;
184 uint8_t sc_acm_cap;
185 uint8_t sc_lsr;
186 uint8_t sc_msr;
187 uint8_t sc_modetoactivate;
188 uint8_t sc_currentmode;
157};
158
159struct ufoma_softc {
160 struct usb2_com_super_softc sc_super_ucom;
161 struct usb2_com_softc sc_ucom;
162 struct cv sc_cv;
163
164 struct usb2_xfer *sc_ctrl_xfer[UFOMA_CTRL_ENDPT_MAX];
165 struct usb2_xfer *sc_bulk_xfer[UFOMA_BULK_ENDPT_MAX];
166 uint8_t *sc_modetable;
167 device_t sc_dev;
168 struct usb2_device *sc_udev;
169
170 uint32_t sc_unit;
171
172 uint16_t sc_line;
173
174 uint8_t sc_num_msg;
175 uint8_t sc_nobulk;
176 uint8_t sc_ctrl_iface_no;
177 uint8_t sc_ctrl_iface_index;
178 uint8_t sc_data_iface_no;
179 uint8_t sc_data_iface_index;
180 uint8_t sc_cm_cap;
181 uint8_t sc_acm_cap;
182 uint8_t sc_lsr;
183 uint8_t sc_msr;
184 uint8_t sc_modetoactivate;
185 uint8_t sc_currentmode;
189 uint8_t sc_flags;
190#define UFOMA_FLAG_INTR_STALL 0x01
191#define UFOMA_FLAG_BULK_WRITE_STALL 0x02
192#define UFOMA_FLAG_BULK_READ_STALL 0x04
193
194 uint8_t sc_name[16];
195};
196
197/* prototypes */
198
199static device_probe_t ufoma_probe;
200static device_attach_t ufoma_attach;
201static device_detach_t ufoma_detach;
202
203static usb2_callback_t ufoma_ctrl_read_callback;
204static usb2_callback_t ufoma_ctrl_write_callback;
186 uint8_t sc_name[16];
187};
188
189/* prototypes */
190
191static device_probe_t ufoma_probe;
192static device_attach_t ufoma_attach;
193static device_detach_t ufoma_detach;
194
195static usb2_callback_t ufoma_ctrl_read_callback;
196static usb2_callback_t ufoma_ctrl_write_callback;
205static usb2_callback_t ufoma_intr_clear_stall_callback;
206static usb2_callback_t ufoma_intr_callback;
207static usb2_callback_t ufoma_bulk_write_callback;
197static usb2_callback_t ufoma_intr_callback;
198static usb2_callback_t ufoma_bulk_write_callback;
208static usb2_callback_t ufoma_bulk_write_clear_stall_callback;
209static usb2_callback_t ufoma_bulk_read_callback;
199static usb2_callback_t ufoma_bulk_read_callback;
210static usb2_callback_t ufoma_bulk_read_clear_stall_callback;
211
200
212static void ufoma_cfg_do_request(struct ufoma_softc *,
213 struct usb2_device_request *, void *);
214static void *ufoma_get_intconf(struct usb2_config_descriptor *,
215 struct usb2_interface_descriptor *, uint8_t, uint8_t);
216static void ufoma_cfg_link_state(struct ufoma_softc *);
217static void ufoma_cfg_activate_state(struct ufoma_softc *, uint16_t);
218static void ufoma_cfg_open(struct usb2_com_softc *);
219static void ufoma_cfg_close(struct usb2_com_softc *);
220static void ufoma_cfg_set_break(struct usb2_com_softc *, uint8_t);
221static void ufoma_cfg_get_status(struct usb2_com_softc *, uint8_t *,
222 uint8_t *);
223static void ufoma_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
224static void ufoma_cfg_set_rts(struct usb2_com_softc *, uint8_t);
225static int ufoma_pre_param(struct usb2_com_softc *, struct termios *);
226static void ufoma_cfg_param(struct usb2_com_softc *, struct termios *);
227static int ufoma_modem_setup(device_t, struct ufoma_softc *,
228 struct usb2_attach_arg *);
229static void ufoma_start_read(struct usb2_com_softc *);
230static void ufoma_stop_read(struct usb2_com_softc *);
231static void ufoma_start_write(struct usb2_com_softc *);
232static void ufoma_stop_write(struct usb2_com_softc *);
233
234/*sysctl stuff*/
235static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS);
236static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS);
237static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS);
238
239
240static const struct usb2_config
241 ufoma_ctrl_config[UFOMA_CTRL_ENDPT_MAX] = {
242
243 [UFOMA_CTRL_ENDPT_INTR] = {
244 .type = UE_INTERRUPT,
245 .endpoint = UE_ADDR_ANY,
246 .direction = UE_DIR_IN,
247 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
248 .mh.bufsize = sizeof(struct usb2_cdc_notification),
249 .mh.callback = &ufoma_intr_callback,
250 },
251
201static void *ufoma_get_intconf(struct usb2_config_descriptor *,
202 struct usb2_interface_descriptor *, uint8_t, uint8_t);
203static void ufoma_cfg_link_state(struct ufoma_softc *);
204static void ufoma_cfg_activate_state(struct ufoma_softc *, uint16_t);
205static void ufoma_cfg_open(struct usb2_com_softc *);
206static void ufoma_cfg_close(struct usb2_com_softc *);
207static void ufoma_cfg_set_break(struct usb2_com_softc *, uint8_t);
208static void ufoma_cfg_get_status(struct usb2_com_softc *, uint8_t *,
209 uint8_t *);
210static void ufoma_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
211static void ufoma_cfg_set_rts(struct usb2_com_softc *, uint8_t);
212static int ufoma_pre_param(struct usb2_com_softc *, struct termios *);
213static void ufoma_cfg_param(struct usb2_com_softc *, struct termios *);
214static int ufoma_modem_setup(device_t, struct ufoma_softc *,
215 struct usb2_attach_arg *);
216static void ufoma_start_read(struct usb2_com_softc *);
217static void ufoma_stop_read(struct usb2_com_softc *);
218static void ufoma_start_write(struct usb2_com_softc *);
219static void ufoma_stop_write(struct usb2_com_softc *);
220
221/*sysctl stuff*/
222static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS);
223static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS);
224static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS);
225
226
227static const struct usb2_config
228 ufoma_ctrl_config[UFOMA_CTRL_ENDPT_MAX] = {
229
230 [UFOMA_CTRL_ENDPT_INTR] = {
231 .type = UE_INTERRUPT,
232 .endpoint = UE_ADDR_ANY,
233 .direction = UE_DIR_IN,
234 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
235 .mh.bufsize = sizeof(struct usb2_cdc_notification),
236 .mh.callback = &ufoma_intr_callback,
237 },
238
252 [UFOMA_CTRL_ENDPT_INTR_CLEAR] = {
253 .type = UE_CONTROL,
254 .endpoint = 0x00, /* Control pipe */
255 .direction = UE_DIR_ANY,
256 .mh.bufsize = sizeof(struct usb2_device_request),
257 .mh.flags = {},
258 .mh.callback = &ufoma_intr_clear_stall_callback,
259 .mh.timeout = 1000, /* 1 second */
260 .mh.interval = 50, /* 50ms */
261 },
262
263 [UFOMA_CTRL_ENDPT_READ] = {
264 .type = UE_CONTROL,
265 .endpoint = 0x00, /* Control pipe */
266 .direction = UE_DIR_ANY,
267 .mh.bufsize = (sizeof(struct usb2_device_request) + UFOMA_CMD_BUF_SIZE),
268 .mh.flags = {.short_xfer_ok = 1,},
269 .mh.callback = &ufoma_ctrl_read_callback,
270 .mh.timeout = 1000, /* 1 second */
271 },
272
273 [UFOMA_CTRL_ENDPT_WRITE] = {
274 .type = UE_CONTROL,
275 .endpoint = 0x00, /* Control pipe */
276 .direction = UE_DIR_ANY,
277 .mh.bufsize = (sizeof(struct usb2_device_request) + 1),
278 .mh.flags = {},
279 .mh.callback = &ufoma_ctrl_write_callback,
280 .mh.timeout = 1000, /* 1 second */
281 },
282};
283
284static const struct usb2_config
285 ufoma_bulk_config[UFOMA_BULK_ENDPT_MAX] = {
286
287 [UFOMA_BULK_ENDPT_WRITE] = {
288 .type = UE_BULK,
289 .endpoint = UE_ADDR_ANY,
290 .direction = UE_DIR_OUT,
291 .mh.bufsize = UFOMA_BULK_BUF_SIZE,
292 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
293 .mh.callback = &ufoma_bulk_write_callback,
294 },
295
296 [UFOMA_BULK_ENDPT_READ] = {
297 .type = UE_BULK,
298 .endpoint = UE_ADDR_ANY,
299 .direction = UE_DIR_IN,
300 .mh.bufsize = UFOMA_BULK_BUF_SIZE,
301 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
302 .mh.callback = &ufoma_bulk_read_callback,
303 },
239 [UFOMA_CTRL_ENDPT_READ] = {
240 .type = UE_CONTROL,
241 .endpoint = 0x00, /* Control pipe */
242 .direction = UE_DIR_ANY,
243 .mh.bufsize = (sizeof(struct usb2_device_request) + UFOMA_CMD_BUF_SIZE),
244 .mh.flags = {.short_xfer_ok = 1,},
245 .mh.callback = &ufoma_ctrl_read_callback,
246 .mh.timeout = 1000, /* 1 second */
247 },
248
249 [UFOMA_CTRL_ENDPT_WRITE] = {
250 .type = UE_CONTROL,
251 .endpoint = 0x00, /* Control pipe */
252 .direction = UE_DIR_ANY,
253 .mh.bufsize = (sizeof(struct usb2_device_request) + 1),
254 .mh.flags = {},
255 .mh.callback = &ufoma_ctrl_write_callback,
256 .mh.timeout = 1000, /* 1 second */
257 },
258};
259
260static const struct usb2_config
261 ufoma_bulk_config[UFOMA_BULK_ENDPT_MAX] = {
262
263 [UFOMA_BULK_ENDPT_WRITE] = {
264 .type = UE_BULK,
265 .endpoint = UE_ADDR_ANY,
266 .direction = UE_DIR_OUT,
267 .mh.bufsize = UFOMA_BULK_BUF_SIZE,
268 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
269 .mh.callback = &ufoma_bulk_write_callback,
270 },
271
272 [UFOMA_BULK_ENDPT_READ] = {
273 .type = UE_BULK,
274 .endpoint = UE_ADDR_ANY,
275 .direction = UE_DIR_IN,
276 .mh.bufsize = UFOMA_BULK_BUF_SIZE,
277 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
278 .mh.callback = &ufoma_bulk_read_callback,
279 },
304
305 [UFOMA_BULK_ENDPT_WRITE_CLEAR] = {
306 .type = UE_CONTROL,
307 .endpoint = 0x00, /* Control pipe */
308 .direction = UE_DIR_ANY,
309 .mh.bufsize = sizeof(struct usb2_device_request),
310 .mh.flags = {},
311 .mh.callback = &ufoma_bulk_write_clear_stall_callback,
312 .mh.timeout = 1000, /* 1 second */
313 .mh.interval = 50, /* 50ms */
314 },
315
316 [UFOMA_BULK_ENDPT_READ_CLEAR] = {
317 .type = UE_CONTROL,
318 .endpoint = 0x00, /* Control pipe */
319 .direction = UE_DIR_ANY,
320 .mh.bufsize = sizeof(struct usb2_device_request),
321 .mh.flags = {},
322 .mh.callback = &ufoma_bulk_read_clear_stall_callback,
323 .mh.timeout = 1000, /* 1 second */
324 .mh.interval = 50, /* 50ms */
325 },
326};
327
328static const struct usb2_com_callback ufoma_callback = {
329 .usb2_com_cfg_get_status = &ufoma_cfg_get_status,
330 .usb2_com_cfg_set_dtr = &ufoma_cfg_set_dtr,
331 .usb2_com_cfg_set_rts = &ufoma_cfg_set_rts,
332 .usb2_com_cfg_set_break = &ufoma_cfg_set_break,
333 .usb2_com_cfg_param = &ufoma_cfg_param,
334 .usb2_com_cfg_open = &ufoma_cfg_open,
335 .usb2_com_cfg_close = &ufoma_cfg_close,
336 .usb2_com_pre_param = &ufoma_pre_param,
337 .usb2_com_start_read = &ufoma_start_read,
338 .usb2_com_stop_read = &ufoma_stop_read,
339 .usb2_com_start_write = &ufoma_start_write,
340 .usb2_com_stop_write = &ufoma_stop_write,
341};
342
343static device_method_t ufoma_methods[] = {
344 /* Device methods */
345 DEVMETHOD(device_probe, ufoma_probe),
346 DEVMETHOD(device_attach, ufoma_attach),
347 DEVMETHOD(device_detach, ufoma_detach),
348 {0, 0}
349};
350
351static devclass_t ufoma_devclass;
352
353static driver_t ufoma_driver = {
354 .name = "ufoma",
355 .methods = ufoma_methods,
356 .size = sizeof(struct ufoma_softc),
357};
358
359DRIVER_MODULE(ufoma, ushub, ufoma_driver, ufoma_devclass, NULL, 0);
360MODULE_DEPEND(ufoma, usb2_serial, 1, 1, 1);
361MODULE_DEPEND(ufoma, usb2_core, 1, 1, 1);
362
363static int
364ufoma_probe(device_t dev)
365{
366 struct usb2_attach_arg *uaa = device_get_ivars(dev);
367 struct usb2_interface_descriptor *id;
368 struct usb2_config_descriptor *cd;
369 usb2_mcpc_acm_descriptor *mad;
370
371 if (uaa->usb2_mode != USB_MODE_HOST) {
372 return (ENXIO);
373 }
374 id = usb2_get_interface_descriptor(uaa->iface);
375 cd = usb2_get_config_descriptor(uaa->device);
376
377 if ((id == NULL) ||
378 (cd == NULL) ||
379 (id->bInterfaceClass != UICLASS_CDC) ||
380 (id->bInterfaceSubClass != UISUBCLASS_MCPC)) {
381 return (ENXIO);
382 }
383 mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
384 if (mad == NULL) {
385 return (ENXIO);
386 }
387#ifndef UFOMA_HANDSFREE
388 if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
389 (mad->bType == UMCPC_ACM_TYPE_AB6)) {
390 return (ENXIO);
391 }
392#endif
393 return (0);
394}
395
396static int
397ufoma_attach(device_t dev)
398{
399 struct usb2_attach_arg *uaa = device_get_ivars(dev);
400 struct ufoma_softc *sc = device_get_softc(dev);
401 struct usb2_config_descriptor *cd;
402 struct usb2_interface_descriptor *id;
403 struct sysctl_ctx_list *sctx;
404 struct sysctl_oid *soid;
405
406 usb2_mcpc_acm_descriptor *mad;
407 uint8_t elements;
408 int32_t error;
409
410 sc->sc_udev = uaa->device;
411 sc->sc_dev = dev;
412 sc->sc_unit = device_get_unit(dev);
413
414 usb2_cv_init(&sc->sc_cv, "CWAIT");
415
416 device_set_usb2_desc(dev);
417
418 snprintf(sc->sc_name, sizeof(sc->sc_name),
419 "%s", device_get_nameunit(dev));
420
421 DPRINTF("\n");
422
423 /* setup control transfers */
424
425 cd = usb2_get_config_descriptor(uaa->device);
426 id = usb2_get_interface_descriptor(uaa->iface);
427 sc->sc_ctrl_iface_no = id->bInterfaceNumber;
428 sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex;
429
430 error = usb2_transfer_setup(uaa->device,
431 &sc->sc_ctrl_iface_index, sc->sc_ctrl_xfer,
432 ufoma_ctrl_config, UFOMA_CTRL_ENDPT_MAX, sc, &Giant);
433
434 if (error) {
435 device_printf(dev, "allocating control USB "
436 "transfers failed!\n");
437 goto detach;
438 }
439 mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
440 if (mad == NULL) {
441 goto detach;
442 }
443 if (mad->bFunctionLength < sizeof(*mad)) {
444 device_printf(dev, "invalid MAD descriptor\n");
445 goto detach;
446 }
447 if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
448 (mad->bType == UMCPC_ACM_TYPE_AB6)) {
449 sc->sc_nobulk = 1;
450 } else {
451 sc->sc_nobulk = 0;
452 if (ufoma_modem_setup(dev, sc, uaa)) {
453 goto detach;
454 }
455 }
456
457 elements = (mad->bFunctionLength - sizeof(*mad) + 1);
458
459 /* initialize mode variables */
460
461 sc->sc_modetable = malloc(elements + 1, M_USBDEV, M_WAITOK);
462
463 if (sc->sc_modetable == NULL) {
464 goto detach;
465 }
466 sc->sc_modetable[0] = (elements + 1);
467 bcopy(mad->bMode, &sc->sc_modetable[1], elements);
468
469 sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED;
470 sc->sc_modetoactivate = mad->bMode[0];
471
280};
281
282static const struct usb2_com_callback ufoma_callback = {
283 .usb2_com_cfg_get_status = &ufoma_cfg_get_status,
284 .usb2_com_cfg_set_dtr = &ufoma_cfg_set_dtr,
285 .usb2_com_cfg_set_rts = &ufoma_cfg_set_rts,
286 .usb2_com_cfg_set_break = &ufoma_cfg_set_break,
287 .usb2_com_cfg_param = &ufoma_cfg_param,
288 .usb2_com_cfg_open = &ufoma_cfg_open,
289 .usb2_com_cfg_close = &ufoma_cfg_close,
290 .usb2_com_pre_param = &ufoma_pre_param,
291 .usb2_com_start_read = &ufoma_start_read,
292 .usb2_com_stop_read = &ufoma_stop_read,
293 .usb2_com_start_write = &ufoma_start_write,
294 .usb2_com_stop_write = &ufoma_stop_write,
295};
296
297static device_method_t ufoma_methods[] = {
298 /* Device methods */
299 DEVMETHOD(device_probe, ufoma_probe),
300 DEVMETHOD(device_attach, ufoma_attach),
301 DEVMETHOD(device_detach, ufoma_detach),
302 {0, 0}
303};
304
305static devclass_t ufoma_devclass;
306
307static driver_t ufoma_driver = {
308 .name = "ufoma",
309 .methods = ufoma_methods,
310 .size = sizeof(struct ufoma_softc),
311};
312
313DRIVER_MODULE(ufoma, ushub, ufoma_driver, ufoma_devclass, NULL, 0);
314MODULE_DEPEND(ufoma, usb2_serial, 1, 1, 1);
315MODULE_DEPEND(ufoma, usb2_core, 1, 1, 1);
316
317static int
318ufoma_probe(device_t dev)
319{
320 struct usb2_attach_arg *uaa = device_get_ivars(dev);
321 struct usb2_interface_descriptor *id;
322 struct usb2_config_descriptor *cd;
323 usb2_mcpc_acm_descriptor *mad;
324
325 if (uaa->usb2_mode != USB_MODE_HOST) {
326 return (ENXIO);
327 }
328 id = usb2_get_interface_descriptor(uaa->iface);
329 cd = usb2_get_config_descriptor(uaa->device);
330
331 if ((id == NULL) ||
332 (cd == NULL) ||
333 (id->bInterfaceClass != UICLASS_CDC) ||
334 (id->bInterfaceSubClass != UISUBCLASS_MCPC)) {
335 return (ENXIO);
336 }
337 mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
338 if (mad == NULL) {
339 return (ENXIO);
340 }
341#ifndef UFOMA_HANDSFREE
342 if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
343 (mad->bType == UMCPC_ACM_TYPE_AB6)) {
344 return (ENXIO);
345 }
346#endif
347 return (0);
348}
349
350static int
351ufoma_attach(device_t dev)
352{
353 struct usb2_attach_arg *uaa = device_get_ivars(dev);
354 struct ufoma_softc *sc = device_get_softc(dev);
355 struct usb2_config_descriptor *cd;
356 struct usb2_interface_descriptor *id;
357 struct sysctl_ctx_list *sctx;
358 struct sysctl_oid *soid;
359
360 usb2_mcpc_acm_descriptor *mad;
361 uint8_t elements;
362 int32_t error;
363
364 sc->sc_udev = uaa->device;
365 sc->sc_dev = dev;
366 sc->sc_unit = device_get_unit(dev);
367
368 usb2_cv_init(&sc->sc_cv, "CWAIT");
369
370 device_set_usb2_desc(dev);
371
372 snprintf(sc->sc_name, sizeof(sc->sc_name),
373 "%s", device_get_nameunit(dev));
374
375 DPRINTF("\n");
376
377 /* setup control transfers */
378
379 cd = usb2_get_config_descriptor(uaa->device);
380 id = usb2_get_interface_descriptor(uaa->iface);
381 sc->sc_ctrl_iface_no = id->bInterfaceNumber;
382 sc->sc_ctrl_iface_index = uaa->info.bIfaceIndex;
383
384 error = usb2_transfer_setup(uaa->device,
385 &sc->sc_ctrl_iface_index, sc->sc_ctrl_xfer,
386 ufoma_ctrl_config, UFOMA_CTRL_ENDPT_MAX, sc, &Giant);
387
388 if (error) {
389 device_printf(dev, "allocating control USB "
390 "transfers failed!\n");
391 goto detach;
392 }
393 mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM);
394 if (mad == NULL) {
395 goto detach;
396 }
397 if (mad->bFunctionLength < sizeof(*mad)) {
398 device_printf(dev, "invalid MAD descriptor\n");
399 goto detach;
400 }
401 if ((mad->bType == UMCPC_ACM_TYPE_AB5) ||
402 (mad->bType == UMCPC_ACM_TYPE_AB6)) {
403 sc->sc_nobulk = 1;
404 } else {
405 sc->sc_nobulk = 0;
406 if (ufoma_modem_setup(dev, sc, uaa)) {
407 goto detach;
408 }
409 }
410
411 elements = (mad->bFunctionLength - sizeof(*mad) + 1);
412
413 /* initialize mode variables */
414
415 sc->sc_modetable = malloc(elements + 1, M_USBDEV, M_WAITOK);
416
417 if (sc->sc_modetable == NULL) {
418 goto detach;
419 }
420 sc->sc_modetable[0] = (elements + 1);
421 bcopy(mad->bMode, &sc->sc_modetable[1], elements);
422
423 sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED;
424 sc->sc_modetoactivate = mad->bMode[0];
425
472 /* clear stall at first run */
473 sc->sc_flags |= (UFOMA_FLAG_BULK_WRITE_STALL |
474 UFOMA_FLAG_BULK_READ_STALL);
426 /* clear stall at first run, if any */
427 usb2_transfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
428 usb2_transfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
475
476 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
477 &ufoma_callback, &Giant);
478 if (error) {
479 DPRINTF("usb2_com_attach failed\n");
480 goto detach;
481 }
482 /*Sysctls*/
483 sctx = device_get_sysctl_ctx(dev);
484 soid = device_get_sysctl_tree(dev);
485
486 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "supportmode",
487 CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_support,
488 "A", "Supporting port role");
489
490 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "currentmode",
491 CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_current,
492 "A", "Current port role");
493
494 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "openmode",
495 CTLFLAG_RW|CTLTYPE_STRING, sc, 0, ufoma_sysctl_open,
496 "A", "Mode to transit when port is opened");
497 SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "comunit",
498 CTLFLAG_RD, &(sc->sc_ucom.sc_unit), 0,
499 "Unit number as USB serial");
500
501 return (0); /* success */
502
503detach:
504 ufoma_detach(dev);
505 return (ENXIO); /* failure */
506}
507
508static int
509ufoma_detach(device_t dev)
510{
511 struct ufoma_softc *sc = device_get_softc(dev);
512
513 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
514
515 usb2_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX);
516
517 usb2_transfer_unsetup(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX);
518
519 if (sc->sc_modetable) {
520 free(sc->sc_modetable, M_USBDEV);
521 }
522 usb2_cv_destroy(&sc->sc_cv);
523
524 return (0);
525}
526
429
430 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
431 &ufoma_callback, &Giant);
432 if (error) {
433 DPRINTF("usb2_com_attach failed\n");
434 goto detach;
435 }
436 /*Sysctls*/
437 sctx = device_get_sysctl_ctx(dev);
438 soid = device_get_sysctl_tree(dev);
439
440 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "supportmode",
441 CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_support,
442 "A", "Supporting port role");
443
444 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "currentmode",
445 CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_current,
446 "A", "Current port role");
447
448 SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "openmode",
449 CTLFLAG_RW|CTLTYPE_STRING, sc, 0, ufoma_sysctl_open,
450 "A", "Mode to transit when port is opened");
451 SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "comunit",
452 CTLFLAG_RD, &(sc->sc_ucom.sc_unit), 0,
453 "Unit number as USB serial");
454
455 return (0); /* success */
456
457detach:
458 ufoma_detach(dev);
459 return (ENXIO); /* failure */
460}
461
462static int
463ufoma_detach(device_t dev)
464{
465 struct ufoma_softc *sc = device_get_softc(dev);
466
467 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
468
469 usb2_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX);
470
471 usb2_transfer_unsetup(sc->sc_bulk_xfer, UFOMA_BULK_ENDPT_MAX);
472
473 if (sc->sc_modetable) {
474 free(sc->sc_modetable, M_USBDEV);
475 }
476 usb2_cv_destroy(&sc->sc_cv);
477
478 return (0);
479}
480
527static void
528ufoma_cfg_do_request(struct ufoma_softc *sc, struct usb2_device_request *req,
529 void *data)
530{
531 uint16_t length;
532 usb2_error_t err;
533
534 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) {
535 goto error;
536 }
537 err = usb2_do_request_flags
538 (sc->sc_udev, &Giant, req, data, 0, NULL, 1000);
539
540 if (err) {
541
542 DPRINTFN(0, "device request failed, err=%s "
543 "(ignored)\n", usb2_errstr(err));
544
545error:
546 length = UGETW(req->wLength);
547
548 if ((req->bmRequestType & UT_READ) && length) {
549 bzero(data, length);
550 }
551 }
552}
553
554static void *
555ufoma_get_intconf(struct usb2_config_descriptor *cd, struct usb2_interface_descriptor *id,
556 uint8_t type, uint8_t subtype)
557{
558 struct usb2_descriptor *desc = (void *)id;
559
560 while ((desc = usb2_desc_foreach(cd, desc))) {
561
562 if (desc->bDescriptorType == UDESC_INTERFACE) {
563 return (NULL);
564 }
565 if ((desc->bDescriptorType == type) &&
566 (desc->bDescriptorSubtype == subtype)) {
567 break;
568 }
569 }
570 return (desc);
571}
572
573static void
574ufoma_cfg_link_state(struct ufoma_softc *sc)
575{
576 struct usb2_device_request req;
577 int32_t error;
578
579 req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
580 req.bRequest = UMCPC_SET_LINK;
581 USETW(req.wValue, UMCPC_CM_MOBILE_ACM);
582 USETW(req.wIndex, sc->sc_ctrl_iface_no);
583 USETW(req.wLength, sc->sc_modetable[0]);
584
481static void *
482ufoma_get_intconf(struct usb2_config_descriptor *cd, struct usb2_interface_descriptor *id,
483 uint8_t type, uint8_t subtype)
484{
485 struct usb2_descriptor *desc = (void *)id;
486
487 while ((desc = usb2_desc_foreach(cd, desc))) {
488
489 if (desc->bDescriptorType == UDESC_INTERFACE) {
490 return (NULL);
491 }
492 if ((desc->bDescriptorType == type) &&
493 (desc->bDescriptorSubtype == subtype)) {
494 break;
495 }
496 }
497 return (desc);
498}
499
500static void
501ufoma_cfg_link_state(struct ufoma_softc *sc)
502{
503 struct usb2_device_request req;
504 int32_t error;
505
506 req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
507 req.bRequest = UMCPC_SET_LINK;
508 USETW(req.wValue, UMCPC_CM_MOBILE_ACM);
509 USETW(req.wIndex, sc->sc_ctrl_iface_no);
510 USETW(req.wLength, sc->sc_modetable[0]);
511
585 ufoma_cfg_do_request(sc, &req, sc->sc_modetable);
512 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
513 &req, sc->sc_modetable, 0, 1000);
586
587 error = usb2_cv_timedwait(&sc->sc_cv, &Giant, hz);
588
589 if (error) {
590 DPRINTF("NO response\n");
591 }
592}
593
594static void
595ufoma_cfg_activate_state(struct ufoma_softc *sc, uint16_t state)
596{
597 struct usb2_device_request req;
598 int32_t error;
599
600 req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
601 req.bRequest = UMCPC_ACTIVATE_MODE;
602 USETW(req.wValue, state);
603 USETW(req.wIndex, sc->sc_ctrl_iface_no);
604 USETW(req.wLength, 0);
605
514
515 error = usb2_cv_timedwait(&sc->sc_cv, &Giant, hz);
516
517 if (error) {
518 DPRINTF("NO response\n");
519 }
520}
521
522static void
523ufoma_cfg_activate_state(struct ufoma_softc *sc, uint16_t state)
524{
525 struct usb2_device_request req;
526 int32_t error;
527
528 req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
529 req.bRequest = UMCPC_ACTIVATE_MODE;
530 USETW(req.wValue, state);
531 USETW(req.wIndex, sc->sc_ctrl_iface_no);
532 USETW(req.wLength, 0);
533
606 ufoma_cfg_do_request(sc, &req, NULL);
534 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
535 &req, NULL, 0, 1000);
607
608 error = usb2_cv_timedwait(&sc->sc_cv, &Giant,
609 (UFOMA_MAX_TIMEOUT * hz));
610 if (error) {
611 DPRINTF("No response\n");
612 }
613}
614
615static void
616ufoma_ctrl_read_callback(struct usb2_xfer *xfer)
617{
618 struct ufoma_softc *sc = xfer->priv_sc;
619 struct usb2_device_request req;
620
621 switch (USB_GET_STATE(xfer)) {
622 case USB_ST_TRANSFERRED:
623tr_transferred:
624 if (xfer->aframes != xfer->nframes) {
625 goto tr_setup;
626 }
627 if (xfer->frlengths[1] > 0) {
628 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers + 1,
629 0, xfer->frlengths[1]);
630 }
631 case USB_ST_SETUP:
632tr_setup:
633 if (sc->sc_num_msg) {
634 sc->sc_num_msg--;
635
636 req.bmRequestType = UT_READ_CLASS_INTERFACE;
637 req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
638 USETW(req.wIndex, sc->sc_ctrl_iface_no);
639 USETW(req.wValue, 0);
640 USETW(req.wLength, UFOMA_CMD_BUF_SIZE);
641
642 usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
643
644 xfer->frlengths[0] = sizeof(req);
645 xfer->frlengths[1] = UFOMA_CMD_BUF_SIZE;
646 xfer->nframes = 2;
647 usb2_start_hardware(xfer);
648 }
649 return;
650
651 default: /* Error */
652 DPRINTF("error = %s\n",
653 usb2_errstr(xfer->error));
654
655 if (xfer->error == USB_ERR_CANCELLED) {
656 return;
657 } else {
658 goto tr_setup;
659 }
660
661 goto tr_transferred;
662 }
663}
664
665static void
666ufoma_ctrl_write_callback(struct usb2_xfer *xfer)
667{
668 struct ufoma_softc *sc = xfer->priv_sc;
669 struct usb2_device_request req;
670 uint32_t actlen;
671
672 switch (USB_GET_STATE(xfer)) {
673 case USB_ST_TRANSFERRED:
674tr_transferred:
675 case USB_ST_SETUP:
676tr_setup:
677 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers + 1,
678 0, 1, &actlen)) {
679
680 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
681 req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
682 USETW(req.wIndex, sc->sc_ctrl_iface_no);
683 USETW(req.wValue, 0);
684 USETW(req.wLength, 1);
685
686 usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
687
688 xfer->frlengths[0] = sizeof(req);
689 xfer->frlengths[1] = 1;
690 xfer->nframes = 2;
691
692 usb2_start_hardware(xfer);
693 }
694 return;
695
696 default: /* Error */
697 DPRINTF("error = %s\n",
698 usb2_errstr(xfer->error));
699
700 if (xfer->error == USB_ERR_CANCELLED) {
701 return;
702 } else {
703 goto tr_setup;
704 }
705
706 goto tr_transferred;
707 }
708}
709
710static void
536
537 error = usb2_cv_timedwait(&sc->sc_cv, &Giant,
538 (UFOMA_MAX_TIMEOUT * hz));
539 if (error) {
540 DPRINTF("No response\n");
541 }
542}
543
544static void
545ufoma_ctrl_read_callback(struct usb2_xfer *xfer)
546{
547 struct ufoma_softc *sc = xfer->priv_sc;
548 struct usb2_device_request req;
549
550 switch (USB_GET_STATE(xfer)) {
551 case USB_ST_TRANSFERRED:
552tr_transferred:
553 if (xfer->aframes != xfer->nframes) {
554 goto tr_setup;
555 }
556 if (xfer->frlengths[1] > 0) {
557 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers + 1,
558 0, xfer->frlengths[1]);
559 }
560 case USB_ST_SETUP:
561tr_setup:
562 if (sc->sc_num_msg) {
563 sc->sc_num_msg--;
564
565 req.bmRequestType = UT_READ_CLASS_INTERFACE;
566 req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
567 USETW(req.wIndex, sc->sc_ctrl_iface_no);
568 USETW(req.wValue, 0);
569 USETW(req.wLength, UFOMA_CMD_BUF_SIZE);
570
571 usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
572
573 xfer->frlengths[0] = sizeof(req);
574 xfer->frlengths[1] = UFOMA_CMD_BUF_SIZE;
575 xfer->nframes = 2;
576 usb2_start_hardware(xfer);
577 }
578 return;
579
580 default: /* Error */
581 DPRINTF("error = %s\n",
582 usb2_errstr(xfer->error));
583
584 if (xfer->error == USB_ERR_CANCELLED) {
585 return;
586 } else {
587 goto tr_setup;
588 }
589
590 goto tr_transferred;
591 }
592}
593
594static void
595ufoma_ctrl_write_callback(struct usb2_xfer *xfer)
596{
597 struct ufoma_softc *sc = xfer->priv_sc;
598 struct usb2_device_request req;
599 uint32_t actlen;
600
601 switch (USB_GET_STATE(xfer)) {
602 case USB_ST_TRANSFERRED:
603tr_transferred:
604 case USB_ST_SETUP:
605tr_setup:
606 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers + 1,
607 0, 1, &actlen)) {
608
609 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
610 req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
611 USETW(req.wIndex, sc->sc_ctrl_iface_no);
612 USETW(req.wValue, 0);
613 USETW(req.wLength, 1);
614
615 usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
616
617 xfer->frlengths[0] = sizeof(req);
618 xfer->frlengths[1] = 1;
619 xfer->nframes = 2;
620
621 usb2_start_hardware(xfer);
622 }
623 return;
624
625 default: /* Error */
626 DPRINTF("error = %s\n",
627 usb2_errstr(xfer->error));
628
629 if (xfer->error == USB_ERR_CANCELLED) {
630 return;
631 } else {
632 goto tr_setup;
633 }
634
635 goto tr_transferred;
636 }
637}
638
639static void
711ufoma_intr_clear_stall_callback(struct usb2_xfer *xfer)
712{
713 struct ufoma_softc *sc = xfer->priv_sc;
714 struct usb2_xfer *xfer_other = sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR];
715
716 if (usb2_clear_stall_callback(xfer, xfer_other)) {
717 DPRINTF("stall cleared\n");
718 sc->sc_flags &= ~UFOMA_FLAG_INTR_STALL;
719 usb2_transfer_start(xfer_other);
720 }
721}
722
723static void
724ufoma_intr_callback(struct usb2_xfer *xfer)
725{
726 struct ufoma_softc *sc = xfer->priv_sc;
727 struct usb2_cdc_notification pkt;
728 uint16_t wLen;
729 uint16_t temp;
730 uint8_t mstatus;
731
732 switch (USB_GET_STATE(xfer)) {
733 case USB_ST_TRANSFERRED:
734 if (xfer->actlen < 8) {
735 DPRINTF("too short message\n");
736 goto tr_setup;
737 }
738 if (xfer->actlen > sizeof(pkt)) {
739 DPRINTF("truncating message\n");
740 xfer->actlen = sizeof(pkt);
741 }
742 usb2_copy_out(xfer->frbuffers, 0, &pkt, xfer->actlen);
743
744 xfer->actlen -= 8;
745
746 wLen = UGETW(pkt.wLength);
747 if (xfer->actlen > wLen) {
748 xfer->actlen = wLen;
749 }
750 if ((pkt.bmRequestType == UT_READ_VENDOR_INTERFACE) &&
751 (pkt.bNotification == UMCPC_REQUEST_ACKNOWLEDGE)) {
752 temp = UGETW(pkt.wValue);
753 sc->sc_currentmode = (temp >> 8);
754 if (!(temp & 0xff)) {
755 DPRINTF("Mode change failed!\n");
756 }
757 usb2_cv_signal(&sc->sc_cv);
758 }
759 if (pkt.bmRequestType != UCDC_NOTIFICATION) {
760 goto tr_setup;
761 }
762 switch (pkt.bNotification) {
763 case UCDC_N_RESPONSE_AVAILABLE:
764 if (!(sc->sc_nobulk)) {
765 DPRINTF("Wrong serial state!\n");
766 break;
767 }
768 if (sc->sc_num_msg != 0xFF) {
769 sc->sc_num_msg++;
770 }
771 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
772 break;
773
774 case UCDC_N_SERIAL_STATE:
775 if (sc->sc_nobulk) {
776 DPRINTF("Wrong serial state!\n");
777 break;
778 }
779 /*
780 * Set the serial state in ucom driver based on
781 * the bits from the notify message
782 */
783 if (xfer->actlen < 2) {
784 DPRINTF("invalid notification "
785 "length, %d bytes!\n", xfer->actlen);
786 break;
787 }
788 DPRINTF("notify bytes = 0x%02x, 0x%02x\n",
789 pkt.data[0], pkt.data[1]);
790
791 /* currently, lsr is always zero. */
792 sc->sc_lsr = 0;
793 sc->sc_msr = 0;
794
795 mstatus = pkt.data[0];
796
797 if (mstatus & UCDC_N_SERIAL_RI) {
798 sc->sc_msr |= SER_RI;
799 }
800 if (mstatus & UCDC_N_SERIAL_DSR) {
801 sc->sc_msr |= SER_DSR;
802 }
803 if (mstatus & UCDC_N_SERIAL_DCD) {
804 sc->sc_msr |= SER_DCD;
805 }
806 usb2_com_status_change(&sc->sc_ucom);
807 break;
808
809 default:
810 break;
811 }
812
813 case USB_ST_SETUP:
814tr_setup:
640ufoma_intr_callback(struct usb2_xfer *xfer)
641{
642 struct ufoma_softc *sc = xfer->priv_sc;
643 struct usb2_cdc_notification pkt;
644 uint16_t wLen;
645 uint16_t temp;
646 uint8_t mstatus;
647
648 switch (USB_GET_STATE(xfer)) {
649 case USB_ST_TRANSFERRED:
650 if (xfer->actlen < 8) {
651 DPRINTF("too short message\n");
652 goto tr_setup;
653 }
654 if (xfer->actlen > sizeof(pkt)) {
655 DPRINTF("truncating message\n");
656 xfer->actlen = sizeof(pkt);
657 }
658 usb2_copy_out(xfer->frbuffers, 0, &pkt, xfer->actlen);
659
660 xfer->actlen -= 8;
661
662 wLen = UGETW(pkt.wLength);
663 if (xfer->actlen > wLen) {
664 xfer->actlen = wLen;
665 }
666 if ((pkt.bmRequestType == UT_READ_VENDOR_INTERFACE) &&
667 (pkt.bNotification == UMCPC_REQUEST_ACKNOWLEDGE)) {
668 temp = UGETW(pkt.wValue);
669 sc->sc_currentmode = (temp >> 8);
670 if (!(temp & 0xff)) {
671 DPRINTF("Mode change failed!\n");
672 }
673 usb2_cv_signal(&sc->sc_cv);
674 }
675 if (pkt.bmRequestType != UCDC_NOTIFICATION) {
676 goto tr_setup;
677 }
678 switch (pkt.bNotification) {
679 case UCDC_N_RESPONSE_AVAILABLE:
680 if (!(sc->sc_nobulk)) {
681 DPRINTF("Wrong serial state!\n");
682 break;
683 }
684 if (sc->sc_num_msg != 0xFF) {
685 sc->sc_num_msg++;
686 }
687 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
688 break;
689
690 case UCDC_N_SERIAL_STATE:
691 if (sc->sc_nobulk) {
692 DPRINTF("Wrong serial state!\n");
693 break;
694 }
695 /*
696 * Set the serial state in ucom driver based on
697 * the bits from the notify message
698 */
699 if (xfer->actlen < 2) {
700 DPRINTF("invalid notification "
701 "length, %d bytes!\n", xfer->actlen);
702 break;
703 }
704 DPRINTF("notify bytes = 0x%02x, 0x%02x\n",
705 pkt.data[0], pkt.data[1]);
706
707 /* currently, lsr is always zero. */
708 sc->sc_lsr = 0;
709 sc->sc_msr = 0;
710
711 mstatus = pkt.data[0];
712
713 if (mstatus & UCDC_N_SERIAL_RI) {
714 sc->sc_msr |= SER_RI;
715 }
716 if (mstatus & UCDC_N_SERIAL_DSR) {
717 sc->sc_msr |= SER_DSR;
718 }
719 if (mstatus & UCDC_N_SERIAL_DCD) {
720 sc->sc_msr |= SER_DCD;
721 }
722 usb2_com_status_change(&sc->sc_ucom);
723 break;
724
725 default:
726 break;
727 }
728
729 case USB_ST_SETUP:
730tr_setup:
815 if (sc->sc_flags & UFOMA_FLAG_INTR_STALL) {
816 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR_CLEAR]);
817 } else {
818 xfer->frlengths[0] = xfer->max_data_length;
819 usb2_start_hardware(xfer);
820 }
731 xfer->frlengths[0] = xfer->max_data_length;
732 usb2_start_hardware(xfer);
821 return;
822
823 default: /* Error */
824 if (xfer->error != USB_ERR_CANCELLED) {
733 return;
734
735 default: /* Error */
736 if (xfer->error != USB_ERR_CANCELLED) {
825 /* start clear stall */
826 sc->sc_flags |= UFOMA_FLAG_INTR_STALL;
827 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR_CLEAR]);
737 /* try to clear stall first */
738 xfer->flags.stall_pipe = 1;
739 goto tr_setup;
828 }
829 return;
740 }
741 return;
830
831 }
832}
833
834static void
835ufoma_bulk_write_callback(struct usb2_xfer *xfer)
836{
837 struct ufoma_softc *sc = xfer->priv_sc;
838 uint32_t actlen;
839
840 switch (USB_GET_STATE(xfer)) {
841 case USB_ST_SETUP:
842 case USB_ST_TRANSFERRED:
742 }
743}
744
745static void
746ufoma_bulk_write_callback(struct usb2_xfer *xfer)
747{
748 struct ufoma_softc *sc = xfer->priv_sc;
749 uint32_t actlen;
750
751 switch (USB_GET_STATE(xfer)) {
752 case USB_ST_SETUP:
753 case USB_ST_TRANSFERRED:
843 if (sc->sc_flags & UFOMA_FLAG_BULK_WRITE_STALL) {
844 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE_CLEAR]);
845 return;
846 }
754tr_setup:
847 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
848 UFOMA_BULK_BUF_SIZE, &actlen)) {
849 xfer->frlengths[0] = actlen;
850 usb2_start_hardware(xfer);
851 }
852 return;
853
854 default: /* Error */
855 if (xfer->error != USB_ERR_CANCELLED) {
755 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
756 UFOMA_BULK_BUF_SIZE, &actlen)) {
757 xfer->frlengths[0] = actlen;
758 usb2_start_hardware(xfer);
759 }
760 return;
761
762 default: /* Error */
763 if (xfer->error != USB_ERR_CANCELLED) {
856 sc->sc_flags |= UFOMA_FLAG_BULK_WRITE_STALL;
857 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE_CLEAR]);
764 /* try to clear stall first */
765 xfer->flags.stall_pipe = 1;
766 goto tr_setup;
858 }
859 return;
767 }
768 return;
860
861 }
862}
863
864static void
769 }
770}
771
772static void
865ufoma_bulk_write_clear_stall_callback(struct usb2_xfer *xfer)
866{
867 struct ufoma_softc *sc = xfer->priv_sc;
868 struct usb2_xfer *xfer_other = sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE];
869
870 if (usb2_clear_stall_callback(xfer, xfer_other)) {
871 DPRINTF("stall cleared\n");
872 sc->sc_flags &= ~UFOMA_FLAG_BULK_WRITE_STALL;
873 usb2_transfer_start(xfer_other);
874 }
875}
876
877static void
878ufoma_bulk_read_callback(struct usb2_xfer *xfer)
879{
880 struct ufoma_softc *sc = xfer->priv_sc;
881
882 switch (USB_GET_STATE(xfer)) {
883 case USB_ST_TRANSFERRED:
884 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0,
885 xfer->actlen);
886
887 case USB_ST_SETUP:
773ufoma_bulk_read_callback(struct usb2_xfer *xfer)
774{
775 struct ufoma_softc *sc = xfer->priv_sc;
776
777 switch (USB_GET_STATE(xfer)) {
778 case USB_ST_TRANSFERRED:
779 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0,
780 xfer->actlen);
781
782 case USB_ST_SETUP:
888 if (sc->sc_flags & UFOMA_FLAG_BULK_READ_STALL) {
889 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ_CLEAR]);
890 } else {
891 xfer->frlengths[0] = xfer->max_data_length;
892 usb2_start_hardware(xfer);
893 }
783tr_setup:
784 xfer->frlengths[0] = xfer->max_data_length;
785 usb2_start_hardware(xfer);
894 return;
895
896 default: /* Error */
897 if (xfer->error != USB_ERR_CANCELLED) {
786 return;
787
788 default: /* Error */
789 if (xfer->error != USB_ERR_CANCELLED) {
898 sc->sc_flags |= UFOMA_FLAG_BULK_READ_STALL;
899 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ_CLEAR]);
790 /* try to clear stall first */
791 xfer->flags.stall_pipe = 1;
792 goto tr_setup;
900 }
901 return;
793 }
794 return;
902
903 }
904}
905
906static void
795 }
796}
797
798static void
907ufoma_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
908{
909 struct ufoma_softc *sc = xfer->priv_sc;
910 struct usb2_xfer *xfer_other = sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ];
911
912 if (usb2_clear_stall_callback(xfer, xfer_other)) {
913 DPRINTF("stall cleared\n");
914 sc->sc_flags &= ~UFOMA_FLAG_BULK_READ_STALL;
915 usb2_transfer_start(xfer_other);
916 }
917}
918
919static void
920ufoma_cfg_open(struct usb2_com_softc *ucom)
921{
922 struct ufoma_softc *sc = ucom->sc_parent;
923
924 /* empty input queue */
925
926 if (sc->sc_num_msg != 0xFF) {
927 sc->sc_num_msg++;
928 }
929 if (sc->sc_currentmode == UMCPC_ACM_MODE_UNLINKED) {
930 ufoma_cfg_link_state(sc);
931 }
932 if (sc->sc_currentmode == UMCPC_ACM_MODE_DEACTIVATED) {
933 ufoma_cfg_activate_state(sc, sc->sc_modetoactivate);
934 }
935}
936
937static void
938ufoma_cfg_close(struct usb2_com_softc *ucom)
939{
940 struct ufoma_softc *sc = ucom->sc_parent;
941
942 ufoma_cfg_activate_state(sc, UMCPC_ACM_MODE_DEACTIVATED);
943}
944
945static void
946ufoma_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
947{
948 struct ufoma_softc *sc = ucom->sc_parent;
949 struct usb2_device_request req;
950 uint16_t wValue;
951
952 if (sc->sc_nobulk ||
953 (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
954 return;
955 }
956 if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) {
957 return;
958 }
959 wValue = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF;
960
961 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
962 req.bRequest = UCDC_SEND_BREAK;
963 USETW(req.wValue, wValue);
964 req.wIndex[0] = sc->sc_ctrl_iface_no;
965 req.wIndex[1] = 0;
966 USETW(req.wLength, 0);
967
799ufoma_cfg_open(struct usb2_com_softc *ucom)
800{
801 struct ufoma_softc *sc = ucom->sc_parent;
802
803 /* empty input queue */
804
805 if (sc->sc_num_msg != 0xFF) {
806 sc->sc_num_msg++;
807 }
808 if (sc->sc_currentmode == UMCPC_ACM_MODE_UNLINKED) {
809 ufoma_cfg_link_state(sc);
810 }
811 if (sc->sc_currentmode == UMCPC_ACM_MODE_DEACTIVATED) {
812 ufoma_cfg_activate_state(sc, sc->sc_modetoactivate);
813 }
814}
815
816static void
817ufoma_cfg_close(struct usb2_com_softc *ucom)
818{
819 struct ufoma_softc *sc = ucom->sc_parent;
820
821 ufoma_cfg_activate_state(sc, UMCPC_ACM_MODE_DEACTIVATED);
822}
823
824static void
825ufoma_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
826{
827 struct ufoma_softc *sc = ucom->sc_parent;
828 struct usb2_device_request req;
829 uint16_t wValue;
830
831 if (sc->sc_nobulk ||
832 (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
833 return;
834 }
835 if (!(sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK)) {
836 return;
837 }
838 wValue = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF;
839
840 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
841 req.bRequest = UCDC_SEND_BREAK;
842 USETW(req.wValue, wValue);
843 req.wIndex[0] = sc->sc_ctrl_iface_no;
844 req.wIndex[1] = 0;
845 USETW(req.wLength, 0);
846
968 ufoma_cfg_do_request(sc, &req, 0);
847 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
848 &req, NULL, 0, 1000);
969}
970
971static void
972ufoma_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
973{
974 struct ufoma_softc *sc = ucom->sc_parent;
975
976 *lsr = sc->sc_lsr;
977 *msr = sc->sc_msr;
978}
979
980static void
981ufoma_cfg_set_line_state(struct ufoma_softc *sc)
982{
983 struct usb2_device_request req;
984
985 /* Don't send line state emulation request for OBEX port */
986 if (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX) {
987 return;
988 }
989 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
990 req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
991 USETW(req.wValue, sc->sc_line);
992 req.wIndex[0] = sc->sc_ctrl_iface_no;
993 req.wIndex[1] = 0;
994 USETW(req.wLength, 0);
995
849}
850
851static void
852ufoma_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
853{
854 struct ufoma_softc *sc = ucom->sc_parent;
855
856 *lsr = sc->sc_lsr;
857 *msr = sc->sc_msr;
858}
859
860static void
861ufoma_cfg_set_line_state(struct ufoma_softc *sc)
862{
863 struct usb2_device_request req;
864
865 /* Don't send line state emulation request for OBEX port */
866 if (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX) {
867 return;
868 }
869 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
870 req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
871 USETW(req.wValue, sc->sc_line);
872 req.wIndex[0] = sc->sc_ctrl_iface_no;
873 req.wIndex[1] = 0;
874 USETW(req.wLength, 0);
875
996 ufoma_cfg_do_request(sc, &req, 0);
876 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
877 &req, NULL, 0, 1000);
997}
998
999static void
1000ufoma_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
1001{
1002 struct ufoma_softc *sc = ucom->sc_parent;
1003
1004 if (sc->sc_nobulk) {
1005 return;
1006 }
1007 if (onoff)
1008 sc->sc_line |= UCDC_LINE_DTR;
1009 else
1010 sc->sc_line &= ~UCDC_LINE_DTR;
1011
1012 ufoma_cfg_set_line_state(sc);
1013}
1014
1015static void
1016ufoma_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
1017{
1018 struct ufoma_softc *sc = ucom->sc_parent;
1019
1020 if (sc->sc_nobulk) {
1021 return;
1022 }
1023 if (onoff)
1024 sc->sc_line |= UCDC_LINE_RTS;
1025 else
1026 sc->sc_line &= ~UCDC_LINE_RTS;
1027
1028 ufoma_cfg_set_line_state(sc);
1029}
1030
1031static int
1032ufoma_pre_param(struct usb2_com_softc *ucom, struct termios *t)
1033{
1034 return (0); /* we accept anything */
1035}
1036
1037static void
1038ufoma_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
1039{
1040 struct ufoma_softc *sc = ucom->sc_parent;
1041 struct usb2_device_request req;
1042 struct usb2_cdc_line_state ls;
1043
1044 if (sc->sc_nobulk ||
1045 (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
1046 return;
1047 }
1048 DPRINTF("\n");
1049
1050 bzero(&ls, sizeof(ls));
1051
1052 USETDW(ls.dwDTERate, t->c_ospeed);
1053
1054 if (t->c_cflag & CSTOPB) {
1055 ls.bCharFormat = UCDC_STOP_BIT_2;
1056 } else {
1057 ls.bCharFormat = UCDC_STOP_BIT_1;
1058 }
1059
1060 if (t->c_cflag & PARENB) {
1061 if (t->c_cflag & PARODD) {
1062 ls.bParityType = UCDC_PARITY_ODD;
1063 } else {
1064 ls.bParityType = UCDC_PARITY_EVEN;
1065 }
1066 } else {
1067 ls.bParityType = UCDC_PARITY_NONE;
1068 }
1069
1070 switch (t->c_cflag & CSIZE) {
1071 case CS5:
1072 ls.bDataBits = 5;
1073 break;
1074 case CS6:
1075 ls.bDataBits = 6;
1076 break;
1077 case CS7:
1078 ls.bDataBits = 7;
1079 break;
1080 case CS8:
1081 ls.bDataBits = 8;
1082 break;
1083 }
1084
1085 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1086 req.bRequest = UCDC_SET_LINE_CODING;
1087 USETW(req.wValue, 0);
1088 req.wIndex[0] = sc->sc_ctrl_iface_no;
1089 req.wIndex[1] = 0;
1090 USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
1091
878}
879
880static void
881ufoma_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
882{
883 struct ufoma_softc *sc = ucom->sc_parent;
884
885 if (sc->sc_nobulk) {
886 return;
887 }
888 if (onoff)
889 sc->sc_line |= UCDC_LINE_DTR;
890 else
891 sc->sc_line &= ~UCDC_LINE_DTR;
892
893 ufoma_cfg_set_line_state(sc);
894}
895
896static void
897ufoma_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
898{
899 struct ufoma_softc *sc = ucom->sc_parent;
900
901 if (sc->sc_nobulk) {
902 return;
903 }
904 if (onoff)
905 sc->sc_line |= UCDC_LINE_RTS;
906 else
907 sc->sc_line &= ~UCDC_LINE_RTS;
908
909 ufoma_cfg_set_line_state(sc);
910}
911
912static int
913ufoma_pre_param(struct usb2_com_softc *ucom, struct termios *t)
914{
915 return (0); /* we accept anything */
916}
917
918static void
919ufoma_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
920{
921 struct ufoma_softc *sc = ucom->sc_parent;
922 struct usb2_device_request req;
923 struct usb2_cdc_line_state ls;
924
925 if (sc->sc_nobulk ||
926 (sc->sc_currentmode == UMCPC_ACM_MODE_OBEX)) {
927 return;
928 }
929 DPRINTF("\n");
930
931 bzero(&ls, sizeof(ls));
932
933 USETDW(ls.dwDTERate, t->c_ospeed);
934
935 if (t->c_cflag & CSTOPB) {
936 ls.bCharFormat = UCDC_STOP_BIT_2;
937 } else {
938 ls.bCharFormat = UCDC_STOP_BIT_1;
939 }
940
941 if (t->c_cflag & PARENB) {
942 if (t->c_cflag & PARODD) {
943 ls.bParityType = UCDC_PARITY_ODD;
944 } else {
945 ls.bParityType = UCDC_PARITY_EVEN;
946 }
947 } else {
948 ls.bParityType = UCDC_PARITY_NONE;
949 }
950
951 switch (t->c_cflag & CSIZE) {
952 case CS5:
953 ls.bDataBits = 5;
954 break;
955 case CS6:
956 ls.bDataBits = 6;
957 break;
958 case CS7:
959 ls.bDataBits = 7;
960 break;
961 case CS8:
962 ls.bDataBits = 8;
963 break;
964 }
965
966 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
967 req.bRequest = UCDC_SET_LINE_CODING;
968 USETW(req.wValue, 0);
969 req.wIndex[0] = sc->sc_ctrl_iface_no;
970 req.wIndex[1] = 0;
971 USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
972
1092 ufoma_cfg_do_request(sc, &req, &ls);
973 usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
974 &req, &ls, 0, 1000);
1093}
1094
1095static int
1096ufoma_modem_setup(device_t dev, struct ufoma_softc *sc,
1097 struct usb2_attach_arg *uaa)
1098{
1099 struct usb2_config_descriptor *cd;
1100 struct usb2_cdc_acm_descriptor *acm;
1101 struct usb2_cdc_cm_descriptor *cmd;
1102 struct usb2_interface_descriptor *id;
1103 struct usb2_interface *iface;
1104 uint8_t i;
1105 int32_t error;
1106
1107 cd = usb2_get_config_descriptor(uaa->device);
1108 id = usb2_get_interface_descriptor(uaa->iface);
1109
1110 cmd = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM);
1111
1112 if ((cmd == NULL) ||
1113 (cmd->bLength < sizeof(*cmd))) {
1114 return (EINVAL);
1115 }
1116 sc->sc_cm_cap = cmd->bmCapabilities;
1117 sc->sc_data_iface_no = cmd->bDataInterface;
1118
1119 acm = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM);
1120
1121 if ((acm == NULL) ||
1122 (acm->bLength < sizeof(*acm))) {
1123 return (EINVAL);
1124 }
1125 sc->sc_acm_cap = acm->bmCapabilities;
1126
1127 device_printf(dev, "data interface %d, has %sCM over data, "
1128 "has %sbreak\n",
1129 sc->sc_data_iface_no,
1130 sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
1131 sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");
1132
1133 /* get the data interface too */
1134
1135 for (i = 0;; i++) {
1136
1137 iface = usb2_get_iface(uaa->device, i);
1138
1139 if (iface) {
1140
1141 id = usb2_get_interface_descriptor(iface);
1142
1143 if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) {
1144 sc->sc_data_iface_index = i;
1145 usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
1146 break;
1147 }
1148 } else {
1149 device_printf(dev, "no data interface!\n");
1150 return (EINVAL);
1151 }
1152 }
1153
1154 error = usb2_transfer_setup(uaa->device,
1155 &sc->sc_data_iface_index, sc->sc_bulk_xfer,
1156 ufoma_bulk_config, UFOMA_BULK_ENDPT_MAX, sc, &Giant);
1157
1158 if (error) {
1159 device_printf(dev, "allocating BULK USB "
1160 "transfers failed!\n");
1161 return (EINVAL);
1162 }
1163 return (0);
1164}
1165
1166static void
1167ufoma_start_read(struct usb2_com_softc *ucom)
1168{
1169 struct ufoma_softc *sc = ucom->sc_parent;
1170
1171 /* start interrupt transfer */
1172 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]);
1173
1174 /* start data transfer */
1175 if (sc->sc_nobulk) {
1176 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
1177 } else {
1178 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
1179 }
1180}
1181
1182static void
1183ufoma_stop_read(struct usb2_com_softc *ucom)
1184{
1185 struct ufoma_softc *sc = ucom->sc_parent;
1186
1187 /* stop interrupt transfer */
1188 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]);
975}
976
977static int
978ufoma_modem_setup(device_t dev, struct ufoma_softc *sc,
979 struct usb2_attach_arg *uaa)
980{
981 struct usb2_config_descriptor *cd;
982 struct usb2_cdc_acm_descriptor *acm;
983 struct usb2_cdc_cm_descriptor *cmd;
984 struct usb2_interface_descriptor *id;
985 struct usb2_interface *iface;
986 uint8_t i;
987 int32_t error;
988
989 cd = usb2_get_config_descriptor(uaa->device);
990 id = usb2_get_interface_descriptor(uaa->iface);
991
992 cmd = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_CM);
993
994 if ((cmd == NULL) ||
995 (cmd->bLength < sizeof(*cmd))) {
996 return (EINVAL);
997 }
998 sc->sc_cm_cap = cmd->bmCapabilities;
999 sc->sc_data_iface_no = cmd->bDataInterface;
1000
1001 acm = ufoma_get_intconf(cd, id, UDESC_CS_INTERFACE, UDESCSUB_CDC_ACM);
1002
1003 if ((acm == NULL) ||
1004 (acm->bLength < sizeof(*acm))) {
1005 return (EINVAL);
1006 }
1007 sc->sc_acm_cap = acm->bmCapabilities;
1008
1009 device_printf(dev, "data interface %d, has %sCM over data, "
1010 "has %sbreak\n",
1011 sc->sc_data_iface_no,
1012 sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
1013 sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");
1014
1015 /* get the data interface too */
1016
1017 for (i = 0;; i++) {
1018
1019 iface = usb2_get_iface(uaa->device, i);
1020
1021 if (iface) {
1022
1023 id = usb2_get_interface_descriptor(iface);
1024
1025 if (id && (id->bInterfaceNumber == sc->sc_data_iface_no)) {
1026 sc->sc_data_iface_index = i;
1027 usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
1028 break;
1029 }
1030 } else {
1031 device_printf(dev, "no data interface!\n");
1032 return (EINVAL);
1033 }
1034 }
1035
1036 error = usb2_transfer_setup(uaa->device,
1037 &sc->sc_data_iface_index, sc->sc_bulk_xfer,
1038 ufoma_bulk_config, UFOMA_BULK_ENDPT_MAX, sc, &Giant);
1039
1040 if (error) {
1041 device_printf(dev, "allocating BULK USB "
1042 "transfers failed!\n");
1043 return (EINVAL);
1044 }
1045 return (0);
1046}
1047
1048static void
1049ufoma_start_read(struct usb2_com_softc *ucom)
1050{
1051 struct ufoma_softc *sc = ucom->sc_parent;
1052
1053 /* start interrupt transfer */
1054 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]);
1055
1056 /* start data transfer */
1057 if (sc->sc_nobulk) {
1058 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
1059 } else {
1060 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
1061 }
1062}
1063
1064static void
1065ufoma_stop_read(struct usb2_com_softc *ucom)
1066{
1067 struct ufoma_softc *sc = ucom->sc_parent;
1068
1069 /* stop interrupt transfer */
1070 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR]);
1189 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_INTR_CLEAR]);
1190
1191 /* stop data transfer */
1192 if (sc->sc_nobulk) {
1193 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
1194 } else {
1071
1072 /* stop data transfer */
1073 if (sc->sc_nobulk) {
1074 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_READ]);
1075 } else {
1195 usb2_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ_CLEAR]);
1196 usb2_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
1197 }
1198}
1199
1200static void
1201ufoma_start_write(struct usb2_com_softc *ucom)
1202{
1203 struct ufoma_softc *sc = ucom->sc_parent;
1204
1205 if (sc->sc_nobulk) {
1206 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]);
1207 } else {
1208 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
1209 }
1210}
1211
1212static void
1213ufoma_stop_write(struct usb2_com_softc *ucom)
1214{
1215 struct ufoma_softc *sc = ucom->sc_parent;
1216
1217 if (sc->sc_nobulk) {
1218 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]);
1219 } else {
1076 usb2_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]);
1077 }
1078}
1079
1080static void
1081ufoma_start_write(struct usb2_com_softc *ucom)
1082{
1083 struct ufoma_softc *sc = ucom->sc_parent;
1084
1085 if (sc->sc_nobulk) {
1086 usb2_transfer_start(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]);
1087 } else {
1088 usb2_transfer_start(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
1089 }
1090}
1091
1092static void
1093ufoma_stop_write(struct usb2_com_softc *ucom)
1094{
1095 struct ufoma_softc *sc = ucom->sc_parent;
1096
1097 if (sc->sc_nobulk) {
1098 usb2_transfer_stop(sc->sc_ctrl_xfer[UFOMA_CTRL_ENDPT_WRITE]);
1099 } else {
1220 usb2_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE_CLEAR]);
1221 usb2_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
1222 }
1223}
1224
1225struct umcpc_modetostr_tab{
1226 int mode;
1227 char *str;
1228}umcpc_modetostr_tab[]={
1229 {UMCPC_ACM_MODE_DEACTIVATED, "deactivated"},
1230 {UMCPC_ACM_MODE_MODEM, "modem"},
1231 {UMCPC_ACM_MODE_ATCOMMAND, "handsfree"},
1232 {UMCPC_ACM_MODE_OBEX, "obex"},
1233 {UMCPC_ACM_MODE_VENDOR1, "vendor1"},
1234 {UMCPC_ACM_MODE_VENDOR2, "vendor2"},
1235 {UMCPC_ACM_MODE_UNLINKED, "unlinked"},
1236 {0, NULL}
1237};
1238
1239static char *ufoma_mode_to_str(int mode)
1240{
1241 int i;
1242 for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){
1243 if(umcpc_modetostr_tab[i].mode == mode){
1244 return umcpc_modetostr_tab[i].str;
1245 }
1246 }
1247 return NULL;
1248}
1249
1250static int ufoma_str_to_mode(char *str)
1251{
1252 int i;
1253 for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){
1254 if(strcmp(str, umcpc_modetostr_tab[i].str)==0){
1255 return umcpc_modetostr_tab[i].mode;
1256 }
1257 }
1258 return -1;
1259}
1260
1261static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS)
1262{
1263 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
1264 struct sbuf sb;
1265 int i;
1266 char *mode;
1267
1268 sbuf_new(&sb, NULL, 1, SBUF_AUTOEXTEND);
1269 for(i = 1; i < sc->sc_modetable[0]; i++){
1270 mode = ufoma_mode_to_str(sc->sc_modetable[i]);
1271 if(mode !=NULL){
1272 sbuf_cat(&sb, mode);
1273 }else{
1274 sbuf_printf(&sb, "(%02x)", sc->sc_modetable[i]);
1275 }
1276 if(i < (sc->sc_modetable[0]-1))
1277 sbuf_cat(&sb, ",");
1278 }
1279 sbuf_trim(&sb);
1280 sbuf_finish(&sb);
1281 sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
1282 sbuf_delete(&sb);
1283
1284 return 0;
1285}
1286static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS)
1287{
1288 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
1289 char *mode;
1290 char subbuf[]="(XXX)";
1291 mode = ufoma_mode_to_str(sc->sc_currentmode);
1292 if(!mode){
1293 mode = subbuf;
1294 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_currentmode);
1295 }
1296 sysctl_handle_string(oidp, mode, strlen(mode), req);
1297
1298 return 0;
1299
1300}
1301static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS)
1302{
1303 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
1304 char *mode;
1305 char subbuf[40];
1306 int newmode;
1307 int error;
1308 int i;
1309
1310 mode = ufoma_mode_to_str(sc->sc_modetoactivate);
1311 if(mode){
1312 strncpy(subbuf, mode, sizeof(subbuf));
1313 }else{
1314 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_modetoactivate);
1315 }
1316 error = sysctl_handle_string(oidp, subbuf, sizeof(subbuf), req);
1317 if(error != 0 || req->newptr == NULL){
1318 return error;
1319 }
1320
1321 if((newmode = ufoma_str_to_mode(subbuf)) == -1){
1322 return EINVAL;
1323 }
1324
1325 for(i = 1 ; i < sc->sc_modetable[0] ; i++){
1326 if(sc->sc_modetable[i] == newmode){
1327 sc->sc_modetoactivate = newmode;
1328 return 0;
1329 }
1330 }
1331
1332 return EINVAL;
1333}
1100 usb2_transfer_stop(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]);
1101 }
1102}
1103
1104struct umcpc_modetostr_tab{
1105 int mode;
1106 char *str;
1107}umcpc_modetostr_tab[]={
1108 {UMCPC_ACM_MODE_DEACTIVATED, "deactivated"},
1109 {UMCPC_ACM_MODE_MODEM, "modem"},
1110 {UMCPC_ACM_MODE_ATCOMMAND, "handsfree"},
1111 {UMCPC_ACM_MODE_OBEX, "obex"},
1112 {UMCPC_ACM_MODE_VENDOR1, "vendor1"},
1113 {UMCPC_ACM_MODE_VENDOR2, "vendor2"},
1114 {UMCPC_ACM_MODE_UNLINKED, "unlinked"},
1115 {0, NULL}
1116};
1117
1118static char *ufoma_mode_to_str(int mode)
1119{
1120 int i;
1121 for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){
1122 if(umcpc_modetostr_tab[i].mode == mode){
1123 return umcpc_modetostr_tab[i].str;
1124 }
1125 }
1126 return NULL;
1127}
1128
1129static int ufoma_str_to_mode(char *str)
1130{
1131 int i;
1132 for(i = 0 ;umcpc_modetostr_tab[i].str != NULL; i++){
1133 if(strcmp(str, umcpc_modetostr_tab[i].str)==0){
1134 return umcpc_modetostr_tab[i].mode;
1135 }
1136 }
1137 return -1;
1138}
1139
1140static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS)
1141{
1142 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
1143 struct sbuf sb;
1144 int i;
1145 char *mode;
1146
1147 sbuf_new(&sb, NULL, 1, SBUF_AUTOEXTEND);
1148 for(i = 1; i < sc->sc_modetable[0]; i++){
1149 mode = ufoma_mode_to_str(sc->sc_modetable[i]);
1150 if(mode !=NULL){
1151 sbuf_cat(&sb, mode);
1152 }else{
1153 sbuf_printf(&sb, "(%02x)", sc->sc_modetable[i]);
1154 }
1155 if(i < (sc->sc_modetable[0]-1))
1156 sbuf_cat(&sb, ",");
1157 }
1158 sbuf_trim(&sb);
1159 sbuf_finish(&sb);
1160 sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
1161 sbuf_delete(&sb);
1162
1163 return 0;
1164}
1165static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS)
1166{
1167 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
1168 char *mode;
1169 char subbuf[]="(XXX)";
1170 mode = ufoma_mode_to_str(sc->sc_currentmode);
1171 if(!mode){
1172 mode = subbuf;
1173 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_currentmode);
1174 }
1175 sysctl_handle_string(oidp, mode, strlen(mode), req);
1176
1177 return 0;
1178
1179}
1180static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS)
1181{
1182 struct ufoma_softc *sc = (struct ufoma_softc *)oidp->oid_arg1;
1183 char *mode;
1184 char subbuf[40];
1185 int newmode;
1186 int error;
1187 int i;
1188
1189 mode = ufoma_mode_to_str(sc->sc_modetoactivate);
1190 if(mode){
1191 strncpy(subbuf, mode, sizeof(subbuf));
1192 }else{
1193 snprintf(subbuf, sizeof(subbuf), "(%02x)", sc->sc_modetoactivate);
1194 }
1195 error = sysctl_handle_string(oidp, subbuf, sizeof(subbuf), req);
1196 if(error != 0 || req->newptr == NULL){
1197 return error;
1198 }
1199
1200 if((newmode = ufoma_str_to_mode(subbuf)) == -1){
1201 return EINVAL;
1202 }
1203
1204 for(i = 1 ; i < sc->sc_modetable[0] ; i++){
1205 if(sc->sc_modetable[i] == newmode){
1206 sc->sc_modetoactivate = newmode;
1207 return 0;
1208 }
1209 }
1210
1211 return EINVAL;
1212}