Deleted Added
full compact
umct.c (187970) umct.c (188413)
1#include <sys/cdefs.h>
1#include <sys/cdefs.h>
2__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/umct2.c 187970 2009-02-01 00:51:25Z thompsa $");
2__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/umct2.c 188413 2009-02-09 22:05:25Z thompsa $");
3
4/*-
5 * Copyright (c) 2003 Scott Long
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31/*
32 * Driver for the MCT (Magic Control Technology) USB-RS232 Converter.
33 * Based on the superb documentation from the linux mct_u232 driver by
34 * Wolfgang Grandeggar <wolfgang@cec.ch>.
35 * This device smells a lot like the Belkin F5U103, except that it has
36 * suffered some mild brain-damage. This driver is based off of the ubsa.c
37 * driver from Alexander Kabaev <kan@freebsd.org>. Merging the two together
38 * might be useful, though the subtle differences might lead to lots of
39 * #ifdef's.
40 */
41
42/*
43 * NOTE: all function names beginning like "umct_cfg_" can only
44 * be called from within the config thread function !
45 */
46
47#include <dev/usb2/include/usb2_devid.h>
48#include <dev/usb2/include/usb2_standard.h>
49#include <dev/usb2/include/usb2_mfunc.h>
50#include <dev/usb2/include/usb2_error.h>
51#include <dev/usb2/include/usb2_cdc.h>
52#include <dev/usb2/include/usb2_defs.h>
53
54#define USB_DEBUG_VAR usb2_debug
55
56#include <dev/usb2/core/usb2_core.h>
57#include <dev/usb2/core/usb2_debug.h>
58#include <dev/usb2/core/usb2_process.h>
59#include <dev/usb2/core/usb2_request.h>
60#include <dev/usb2/core/usb2_lookup.h>
61#include <dev/usb2/core/usb2_util.h>
62#include <dev/usb2/core/usb2_busdma.h>
63#include <dev/usb2/core/usb2_device.h>
64
65#include <dev/usb2/serial/usb2_serial.h>
66
67/* The UMCT advertises the standard 8250 UART registers */
68#define UMCT_GET_MSR 2 /* Get Modem Status Register */
69#define UMCT_GET_MSR_SIZE 1
70#define UMCT_GET_LCR 6 /* Get Line Control Register */
71#define UMCT_GET_LCR_SIZE 1
72#define UMCT_SET_BAUD 5 /* Set the Baud Rate Divisor */
73#define UMCT_SET_BAUD_SIZE 4
74#define UMCT_SET_LCR 7 /* Set Line Control Register */
75#define UMCT_SET_LCR_SIZE 1
76#define UMCT_SET_MCR 10 /* Set Modem Control Register */
77#define UMCT_SET_MCR_SIZE 1
78
79#define UMCT_INTR_INTERVAL 100
80#define UMCT_IFACE_INDEX 0
81#define UMCT_CONFIG_INDEX 1
82
83enum {
84 UMCT_BULK_DT_WR,
85 UMCT_BULK_DT_RD,
3
4/*-
5 * Copyright (c) 2003 Scott Long
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31/*
32 * Driver for the MCT (Magic Control Technology) USB-RS232 Converter.
33 * Based on the superb documentation from the linux mct_u232 driver by
34 * Wolfgang Grandeggar <wolfgang@cec.ch>.
35 * This device smells a lot like the Belkin F5U103, except that it has
36 * suffered some mild brain-damage. This driver is based off of the ubsa.c
37 * driver from Alexander Kabaev <kan@freebsd.org>. Merging the two together
38 * might be useful, though the subtle differences might lead to lots of
39 * #ifdef's.
40 */
41
42/*
43 * NOTE: all function names beginning like "umct_cfg_" can only
44 * be called from within the config thread function !
45 */
46
47#include <dev/usb2/include/usb2_devid.h>
48#include <dev/usb2/include/usb2_standard.h>
49#include <dev/usb2/include/usb2_mfunc.h>
50#include <dev/usb2/include/usb2_error.h>
51#include <dev/usb2/include/usb2_cdc.h>
52#include <dev/usb2/include/usb2_defs.h>
53
54#define USB_DEBUG_VAR usb2_debug
55
56#include <dev/usb2/core/usb2_core.h>
57#include <dev/usb2/core/usb2_debug.h>
58#include <dev/usb2/core/usb2_process.h>
59#include <dev/usb2/core/usb2_request.h>
60#include <dev/usb2/core/usb2_lookup.h>
61#include <dev/usb2/core/usb2_util.h>
62#include <dev/usb2/core/usb2_busdma.h>
63#include <dev/usb2/core/usb2_device.h>
64
65#include <dev/usb2/serial/usb2_serial.h>
66
67/* The UMCT advertises the standard 8250 UART registers */
68#define UMCT_GET_MSR 2 /* Get Modem Status Register */
69#define UMCT_GET_MSR_SIZE 1
70#define UMCT_GET_LCR 6 /* Get Line Control Register */
71#define UMCT_GET_LCR_SIZE 1
72#define UMCT_SET_BAUD 5 /* Set the Baud Rate Divisor */
73#define UMCT_SET_BAUD_SIZE 4
74#define UMCT_SET_LCR 7 /* Set Line Control Register */
75#define UMCT_SET_LCR_SIZE 1
76#define UMCT_SET_MCR 10 /* Set Modem Control Register */
77#define UMCT_SET_MCR_SIZE 1
78
79#define UMCT_INTR_INTERVAL 100
80#define UMCT_IFACE_INDEX 0
81#define UMCT_CONFIG_INDEX 1
82
83enum {
84 UMCT_BULK_DT_WR,
85 UMCT_BULK_DT_RD,
86 UMCT_BULK_CS_WR,
87 UMCT_BULK_CS_RD,
88 UMCT_INTR_DT_RD,
86 UMCT_INTR_DT_RD,
89 UMCT_INTR_CS_RD,
90 UMCT_N_TRANSFER = 6,
87 UMCT_N_TRANSFER,
91};
92
93struct umct_softc {
94 struct usb2_com_super_softc sc_super_ucom;
95 struct usb2_com_softc sc_ucom;
96
97 struct usb2_device *sc_udev;
98 struct usb2_xfer *sc_xfer[UMCT_N_TRANSFER];
99
100 uint32_t sc_unit;
101
102 uint16_t sc_obufsize;
103
104 uint8_t sc_lsr;
105 uint8_t sc_msr;
106 uint8_t sc_lcr;
107 uint8_t sc_mcr;
88};
89
90struct umct_softc {
91 struct usb2_com_super_softc sc_super_ucom;
92 struct usb2_com_softc sc_ucom;
93
94 struct usb2_device *sc_udev;
95 struct usb2_xfer *sc_xfer[UMCT_N_TRANSFER];
96
97 uint32_t sc_unit;
98
99 uint16_t sc_obufsize;
100
101 uint8_t sc_lsr;
102 uint8_t sc_msr;
103 uint8_t sc_lcr;
104 uint8_t sc_mcr;
108
109 uint8_t sc_name[16];
110 uint8_t sc_flags;
111#define UMCT_FLAG_READ_STALL 0x01
112#define UMCT_FLAG_WRITE_STALL 0x02
113#define UMCT_FLAG_INTR_STALL 0x04
114 uint8_t sc_iface_no;
105 uint8_t sc_iface_no;
106 uint8_t sc_name[16];
115};
116
117/* prototypes */
118
119static device_probe_t umct_probe;
120static device_attach_t umct_attach;
121static device_detach_t umct_detach;
122
107};
108
109/* prototypes */
110
111static device_probe_t umct_probe;
112static device_attach_t umct_attach;
113static device_detach_t umct_detach;
114
123static usb2_callback_t umct_intr_clear_stall_callback;
124static usb2_callback_t umct_intr_callback;
125static usb2_callback_t umct_write_callback;
115static usb2_callback_t umct_intr_callback;
116static usb2_callback_t umct_write_callback;
126static usb2_callback_t umct_write_clear_stall_callback;
127static usb2_callback_t umct_read_callback;
117static usb2_callback_t umct_read_callback;
128static usb2_callback_t umct_read_clear_stall_callback;
129
118
130static void umct_cfg_do_request(struct umct_softc *, uint8_t, uint16_t,
131 uint32_t);
119static void umct_cfg_do_request(struct umct_softc *sc, uint8_t request,
120 uint16_t len, uint32_t value);
132static void umct_cfg_get_status(struct usb2_com_softc *, uint8_t *,
133 uint8_t *);
134static void umct_cfg_set_break(struct usb2_com_softc *, uint8_t);
135static void umct_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
136static void umct_cfg_set_rts(struct usb2_com_softc *, uint8_t);
137static uint8_t umct_calc_baud(uint32_t);
138static int umct_pre_param(struct usb2_com_softc *, struct termios *);
139static void umct_cfg_param(struct usb2_com_softc *, struct termios *);
140static void umct_start_read(struct usb2_com_softc *);
141static void umct_stop_read(struct usb2_com_softc *);
142static void umct_start_write(struct usb2_com_softc *);
143static void umct_stop_write(struct usb2_com_softc *);
144
145static const struct usb2_config umct_config[UMCT_N_TRANSFER] = {
146
147 [UMCT_BULK_DT_WR] = {
148 .type = UE_BULK,
149 .endpoint = UE_ADDR_ANY,
150 .direction = UE_DIR_OUT,
151 .mh.bufsize = 0, /* use wMaxPacketSize */
152 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
153 .mh.callback = &umct_write_callback,
154 },
155
156 [UMCT_BULK_DT_RD] = {
157 .type = UE_INTERRUPT,
158 .endpoint = UE_ADDR_ANY,
159 .direction = UE_DIR_IN,
160 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
161 .mh.bufsize = 0, /* use wMaxPacketSize */
162 .mh.callback = &umct_read_callback,
163 .ep_index = 0, /* first interrupt endpoint */
164 },
165
121static void umct_cfg_get_status(struct usb2_com_softc *, uint8_t *,
122 uint8_t *);
123static void umct_cfg_set_break(struct usb2_com_softc *, uint8_t);
124static void umct_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
125static void umct_cfg_set_rts(struct usb2_com_softc *, uint8_t);
126static uint8_t umct_calc_baud(uint32_t);
127static int umct_pre_param(struct usb2_com_softc *, struct termios *);
128static void umct_cfg_param(struct usb2_com_softc *, struct termios *);
129static void umct_start_read(struct usb2_com_softc *);
130static void umct_stop_read(struct usb2_com_softc *);
131static void umct_start_write(struct usb2_com_softc *);
132static void umct_stop_write(struct usb2_com_softc *);
133
134static const struct usb2_config umct_config[UMCT_N_TRANSFER] = {
135
136 [UMCT_BULK_DT_WR] = {
137 .type = UE_BULK,
138 .endpoint = UE_ADDR_ANY,
139 .direction = UE_DIR_OUT,
140 .mh.bufsize = 0, /* use wMaxPacketSize */
141 .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
142 .mh.callback = &umct_write_callback,
143 },
144
145 [UMCT_BULK_DT_RD] = {
146 .type = UE_INTERRUPT,
147 .endpoint = UE_ADDR_ANY,
148 .direction = UE_DIR_IN,
149 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
150 .mh.bufsize = 0, /* use wMaxPacketSize */
151 .mh.callback = &umct_read_callback,
152 .ep_index = 0, /* first interrupt endpoint */
153 },
154
166 [UMCT_BULK_CS_WR] = {
167 .type = UE_CONTROL,
168 .endpoint = 0x00, /* Control pipe */
169 .direction = UE_DIR_ANY,
170 .mh.bufsize = sizeof(struct usb2_device_request),
171 .mh.flags = {},
172 .mh.callback = &umct_write_clear_stall_callback,
173 .mh.timeout = 1000, /* 1 second */
174 .mh.interval = 50, /* 50ms */
175 },
176
177 [UMCT_BULK_CS_RD] = {
178 .type = UE_CONTROL,
179 .endpoint = 0x00, /* Control pipe */
180 .direction = UE_DIR_ANY,
181 .mh.bufsize = sizeof(struct usb2_device_request),
182 .mh.flags = {},
183 .mh.callback = &umct_read_clear_stall_callback,
184 .mh.timeout = 1000, /* 1 second */
185 .mh.interval = 50, /* 50ms */
186 },
187
188 [UMCT_INTR_DT_RD] = {
189 .type = UE_INTERRUPT,
190 .endpoint = UE_ADDR_ANY,
191 .direction = UE_DIR_IN,
192 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
193 .mh.bufsize = 0, /* use wMaxPacketSize */
194 .mh.callback = &umct_intr_callback,
195 .ep_index = 1, /* second interrupt endpoint */
196 },
155 [UMCT_INTR_DT_RD] = {
156 .type = UE_INTERRUPT,
157 .endpoint = UE_ADDR_ANY,
158 .direction = UE_DIR_IN,
159 .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
160 .mh.bufsize = 0, /* use wMaxPacketSize */
161 .mh.callback = &umct_intr_callback,
162 .ep_index = 1, /* second interrupt endpoint */
163 },
197
198 [UMCT_INTR_CS_RD] = {
199 .type = UE_CONTROL,
200 .endpoint = 0x00, /* Control pipe */
201 .direction = UE_DIR_ANY,
202 .mh.bufsize = sizeof(struct usb2_device_request),
203 .mh.flags = {},
204 .mh.callback = &umct_intr_clear_stall_callback,
205 .mh.timeout = 1000, /* 1 second */
206 .mh.interval = 50, /* 50ms */
207 },
208};
209
210static const struct usb2_com_callback umct_callback = {
211 .usb2_com_cfg_get_status = &umct_cfg_get_status,
212 .usb2_com_cfg_set_dtr = &umct_cfg_set_dtr,
213 .usb2_com_cfg_set_rts = &umct_cfg_set_rts,
214 .usb2_com_cfg_set_break = &umct_cfg_set_break,
215 .usb2_com_cfg_param = &umct_cfg_param,
216 .usb2_com_pre_param = &umct_pre_param,
217 .usb2_com_start_read = &umct_start_read,
218 .usb2_com_stop_read = &umct_stop_read,
219 .usb2_com_start_write = &umct_start_write,
220 .usb2_com_stop_write = &umct_stop_write,
221};
222
223static const struct usb2_device_id umct_devs[] = {
224 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0)},
225 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, 0)},
226 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232, 0)},
227 {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U109, 0)},
228 {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U409, 0)},
229};
230
231static device_method_t umct_methods[] = {
232 DEVMETHOD(device_probe, umct_probe),
233 DEVMETHOD(device_attach, umct_attach),
234 DEVMETHOD(device_detach, umct_detach),
235 {0, 0}
236};
237
238static devclass_t umct_devclass;
239
240static driver_t umct_driver = {
241 .name = "umct",
242 .methods = umct_methods,
243 .size = sizeof(struct umct_softc),
244};
245
246DRIVER_MODULE(umct, ushub, umct_driver, umct_devclass, NULL, 0);
247MODULE_DEPEND(umct, usb2_serial, 1, 1, 1);
248MODULE_DEPEND(umct, usb2_core, 1, 1, 1);
249
250static int
251umct_probe(device_t dev)
252{
253 struct usb2_attach_arg *uaa = device_get_ivars(dev);
254
255 if (uaa->usb2_mode != USB_MODE_HOST) {
256 return (ENXIO);
257 }
258 if (uaa->info.bConfigIndex != UMCT_CONFIG_INDEX) {
259 return (ENXIO);
260 }
261 if (uaa->info.bIfaceIndex != UMCT_IFACE_INDEX) {
262 return (ENXIO);
263 }
264 return (usb2_lookup_id_by_uaa(umct_devs, sizeof(umct_devs), uaa));
265}
266
267static int
268umct_attach(device_t dev)
269{
270 struct usb2_attach_arg *uaa = device_get_ivars(dev);
271 struct umct_softc *sc = device_get_softc(dev);
272 int32_t error;
273 uint16_t maxp;
274 uint8_t iface_index;
275
276 sc->sc_udev = uaa->device;
277 sc->sc_unit = device_get_unit(dev);
278
279 device_set_usb2_desc(dev);
280
281 snprintf(sc->sc_name, sizeof(sc->sc_name),
282 "%s", device_get_nameunit(dev));
283
284 sc->sc_iface_no = uaa->info.bIfaceNum;
285
286 iface_index = UMCT_IFACE_INDEX;
287 error = usb2_transfer_setup(uaa->device, &iface_index,
288 sc->sc_xfer, umct_config, UMCT_N_TRANSFER, sc, &Giant);
289
290 if (error) {
291 device_printf(dev, "allocating USB "
292 "transfers failed!\n");
293 goto detach;
294 }
295 /*
296 * The real bulk-in endpoint is also marked as an interrupt.
297 * The only way to differentiate it from the real interrupt
298 * endpoint is to look at the wMaxPacketSize field.
299 */
300 maxp = UGETW(sc->sc_xfer[UMCT_BULK_DT_RD]->pipe->edesc->wMaxPacketSize);
301 if (maxp == 0x2) {
302
303 /* guessed wrong - switch around endpoints */
304
305 struct usb2_xfer *temp = sc->sc_xfer[UMCT_INTR_DT_RD];
306
307 sc->sc_xfer[UMCT_INTR_DT_RD] = sc->sc_xfer[UMCT_BULK_DT_RD];
308 sc->sc_xfer[UMCT_BULK_DT_RD] = temp;
309
310 sc->sc_xfer[UMCT_BULK_DT_RD]->callback = &umct_read_callback;
311 sc->sc_xfer[UMCT_INTR_DT_RD]->callback = &umct_intr_callback;
312 }
313 sc->sc_obufsize = sc->sc_xfer[UMCT_BULK_DT_WR]->max_data_length;
314
315 if (uaa->info.idProduct == USB_PRODUCT_MCT_SITECOM_USB232) {
316 if (sc->sc_obufsize > 16) {
317 sc->sc_obufsize = 16;
318 }
319 }
320 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
321 &umct_callback, &Giant);
322 if (error) {
323 goto detach;
324 }
325 return (0); /* success */
326
327detach:
328 umct_detach(dev);
329 return (ENXIO); /* failure */
330}
331
332static int
333umct_detach(device_t dev)
334{
335 struct umct_softc *sc = device_get_softc(dev);
336
337 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
338
339 usb2_transfer_unsetup(sc->sc_xfer, UMCT_N_TRANSFER);
340
341 return (0);
342}
343
344static void
345umct_cfg_do_request(struct umct_softc *sc, uint8_t request,
346 uint16_t len, uint32_t value)
347{
348 struct usb2_device_request req;
349 usb2_error_t err;
350 uint8_t temp[4];
351
164};
165
166static const struct usb2_com_callback umct_callback = {
167 .usb2_com_cfg_get_status = &umct_cfg_get_status,
168 .usb2_com_cfg_set_dtr = &umct_cfg_set_dtr,
169 .usb2_com_cfg_set_rts = &umct_cfg_set_rts,
170 .usb2_com_cfg_set_break = &umct_cfg_set_break,
171 .usb2_com_cfg_param = &umct_cfg_param,
172 .usb2_com_pre_param = &umct_pre_param,
173 .usb2_com_start_read = &umct_start_read,
174 .usb2_com_stop_read = &umct_stop_read,
175 .usb2_com_start_write = &umct_start_write,
176 .usb2_com_stop_write = &umct_stop_write,
177};
178
179static const struct usb2_device_id umct_devs[] = {
180 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0)},
181 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, 0)},
182 {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232, 0)},
183 {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U109, 0)},
184 {USB_VPI(USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U409, 0)},
185};
186
187static device_method_t umct_methods[] = {
188 DEVMETHOD(device_probe, umct_probe),
189 DEVMETHOD(device_attach, umct_attach),
190 DEVMETHOD(device_detach, umct_detach),
191 {0, 0}
192};
193
194static devclass_t umct_devclass;
195
196static driver_t umct_driver = {
197 .name = "umct",
198 .methods = umct_methods,
199 .size = sizeof(struct umct_softc),
200};
201
202DRIVER_MODULE(umct, ushub, umct_driver, umct_devclass, NULL, 0);
203MODULE_DEPEND(umct, usb2_serial, 1, 1, 1);
204MODULE_DEPEND(umct, usb2_core, 1, 1, 1);
205
206static int
207umct_probe(device_t dev)
208{
209 struct usb2_attach_arg *uaa = device_get_ivars(dev);
210
211 if (uaa->usb2_mode != USB_MODE_HOST) {
212 return (ENXIO);
213 }
214 if (uaa->info.bConfigIndex != UMCT_CONFIG_INDEX) {
215 return (ENXIO);
216 }
217 if (uaa->info.bIfaceIndex != UMCT_IFACE_INDEX) {
218 return (ENXIO);
219 }
220 return (usb2_lookup_id_by_uaa(umct_devs, sizeof(umct_devs), uaa));
221}
222
223static int
224umct_attach(device_t dev)
225{
226 struct usb2_attach_arg *uaa = device_get_ivars(dev);
227 struct umct_softc *sc = device_get_softc(dev);
228 int32_t error;
229 uint16_t maxp;
230 uint8_t iface_index;
231
232 sc->sc_udev = uaa->device;
233 sc->sc_unit = device_get_unit(dev);
234
235 device_set_usb2_desc(dev);
236
237 snprintf(sc->sc_name, sizeof(sc->sc_name),
238 "%s", device_get_nameunit(dev));
239
240 sc->sc_iface_no = uaa->info.bIfaceNum;
241
242 iface_index = UMCT_IFACE_INDEX;
243 error = usb2_transfer_setup(uaa->device, &iface_index,
244 sc->sc_xfer, umct_config, UMCT_N_TRANSFER, sc, &Giant);
245
246 if (error) {
247 device_printf(dev, "allocating USB "
248 "transfers failed!\n");
249 goto detach;
250 }
251 /*
252 * The real bulk-in endpoint is also marked as an interrupt.
253 * The only way to differentiate it from the real interrupt
254 * endpoint is to look at the wMaxPacketSize field.
255 */
256 maxp = UGETW(sc->sc_xfer[UMCT_BULK_DT_RD]->pipe->edesc->wMaxPacketSize);
257 if (maxp == 0x2) {
258
259 /* guessed wrong - switch around endpoints */
260
261 struct usb2_xfer *temp = sc->sc_xfer[UMCT_INTR_DT_RD];
262
263 sc->sc_xfer[UMCT_INTR_DT_RD] = sc->sc_xfer[UMCT_BULK_DT_RD];
264 sc->sc_xfer[UMCT_BULK_DT_RD] = temp;
265
266 sc->sc_xfer[UMCT_BULK_DT_RD]->callback = &umct_read_callback;
267 sc->sc_xfer[UMCT_INTR_DT_RD]->callback = &umct_intr_callback;
268 }
269 sc->sc_obufsize = sc->sc_xfer[UMCT_BULK_DT_WR]->max_data_length;
270
271 if (uaa->info.idProduct == USB_PRODUCT_MCT_SITECOM_USB232) {
272 if (sc->sc_obufsize > 16) {
273 sc->sc_obufsize = 16;
274 }
275 }
276 error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
277 &umct_callback, &Giant);
278 if (error) {
279 goto detach;
280 }
281 return (0); /* success */
282
283detach:
284 umct_detach(dev);
285 return (ENXIO); /* failure */
286}
287
288static int
289umct_detach(device_t dev)
290{
291 struct umct_softc *sc = device_get_softc(dev);
292
293 usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
294
295 usb2_transfer_unsetup(sc->sc_xfer, UMCT_N_TRANSFER);
296
297 return (0);
298}
299
300static void
301umct_cfg_do_request(struct umct_softc *sc, uint8_t request,
302 uint16_t len, uint32_t value)
303{
304 struct usb2_device_request req;
305 usb2_error_t err;
306 uint8_t temp[4];
307
352 if (usb2_com_cfg_is_gone(&sc->sc_ucom)) {
353 goto done;
354 }
355 if (len > 4) {
308 if (len > 4)
356 len = 4;
309 len = 4;
357 }
358 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
359 req.bRequest = request;
360 USETW(req.wValue, 0);
361 req.wIndex[0] = sc->sc_iface_no;
362 req.wIndex[1] = 0;
363 USETW(req.wLength, len);
364 USETDW(temp, value);
365
310 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
311 req.bRequest = request;
312 USETW(req.wValue, 0);
313 req.wIndex[0] = sc->sc_iface_no;
314 req.wIndex[1] = 0;
315 USETW(req.wLength, len);
316 USETDW(temp, value);
317
366 err = usb2_do_request_flags(sc->sc_udev, &Giant, &req,
367 temp, 0, NULL, 1000);
368
318 err = usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
319 &req, temp, 0, 1000);
369 if (err) {
370 DPRINTFN(0, "device request failed, err=%s "
371 "(ignored)\n", usb2_errstr(err));
372 }
320 if (err) {
321 DPRINTFN(0, "device request failed, err=%s "
322 "(ignored)\n", usb2_errstr(err));
323 }
373done:
374 return;
375}
376
377static void
324 return;
325}
326
327static void
378umct_intr_clear_stall_callback(struct usb2_xfer *xfer)
379{
380 struct umct_softc *sc = xfer->priv_sc;
381 struct usb2_xfer *xfer_other = sc->sc_xfer[UMCT_INTR_DT_RD];
382
383 if (usb2_clear_stall_callback(xfer, xfer_other)) {
384 DPRINTF("stall cleared\n");
385 sc->sc_flags &= ~UMCT_FLAG_INTR_STALL;
386 usb2_transfer_start(xfer_other);
387 }
388}
389
390static void
391umct_intr_callback(struct usb2_xfer *xfer)
392{
393 struct umct_softc *sc = xfer->priv_sc;
394 uint8_t buf[2];
395
396 switch (USB_GET_STATE(xfer)) {
397 case USB_ST_TRANSFERRED:
398 if (xfer->actlen < 2) {
399 DPRINTF("too short message\n");
400 goto tr_setup;
401 }
402 usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf));
403
404 sc->sc_msr = buf[0];
405 sc->sc_lsr = buf[1];
406
407 usb2_com_status_change(&sc->sc_ucom);
408
409 case USB_ST_SETUP:
410tr_setup:
328umct_intr_callback(struct usb2_xfer *xfer)
329{
330 struct umct_softc *sc = xfer->priv_sc;
331 uint8_t buf[2];
332
333 switch (USB_GET_STATE(xfer)) {
334 case USB_ST_TRANSFERRED:
335 if (xfer->actlen < 2) {
336 DPRINTF("too short message\n");
337 goto tr_setup;
338 }
339 usb2_copy_out(xfer->frbuffers, 0, buf, sizeof(buf));
340
341 sc->sc_msr = buf[0];
342 sc->sc_lsr = buf[1];
343
344 usb2_com_status_change(&sc->sc_ucom);
345
346 case USB_ST_SETUP:
347tr_setup:
411 if (sc->sc_flags & UMCT_FLAG_INTR_STALL) {
412 usb2_transfer_start(sc->sc_xfer[UMCT_INTR_CS_RD]);
413 } else {
414 xfer->frlengths[0] = xfer->max_data_length;
415 usb2_start_hardware(xfer);
416 }
348 xfer->frlengths[0] = xfer->max_data_length;
349 usb2_start_hardware(xfer);
417 return;
418
419 default: /* Error */
420 if (xfer->error != USB_ERR_CANCELLED) {
350 return;
351
352 default: /* Error */
353 if (xfer->error != USB_ERR_CANCELLED) {
421 /* start clear stall */
422 sc->sc_flags |= UMCT_FLAG_INTR_STALL;
423 usb2_transfer_start(sc->sc_xfer[UMCT_INTR_CS_RD]);
354 /* try to clear stall first */
355 xfer->flags.stall_pipe = 1;
356 goto tr_setup;
424 }
425 return;
357 }
358 return;
426
427 }
428}
429
430static void
431umct_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
432{
433 struct umct_softc *sc = ucom->sc_parent;
434
435 *lsr = sc->sc_lsr;
436 *msr = sc->sc_msr;
437}
438
439static void
440umct_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
441{
442 struct umct_softc *sc = ucom->sc_parent;
443
444 if (onoff)
445 sc->sc_lcr |= 0x40;
446 else
447 sc->sc_lcr &= ~0x40;
448
449 umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, sc->sc_lcr);
450}
451
452static void
453umct_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
454{
455 struct umct_softc *sc = ucom->sc_parent;
456
457 if (onoff)
458 sc->sc_mcr |= 0x01;
459 else
460 sc->sc_mcr &= ~0x01;
461
462 umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr);
463}
464
465static void
466umct_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
467{
468 struct umct_softc *sc = ucom->sc_parent;
469
470 if (onoff)
471 sc->sc_mcr |= 0x02;
472 else
473 sc->sc_mcr &= ~0x02;
474
475 umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr);
476}
477
478static uint8_t
479umct_calc_baud(uint32_t baud)
480{
481 switch (baud) {
482 case B300:return (0x1);
483 case B600:
484 return (0x2);
485 case B1200:
486 return (0x3);
487 case B2400:
488 return (0x4);
489 case B4800:
490 return (0x6);
491 case B9600:
492 return (0x8);
493 case B19200:
494 return (0x9);
495 case B38400:
496 return (0xa);
497 case B57600:
498 return (0xb);
499 case 115200:
500 return (0xc);
501 case B0:
502 default:
503 break;
504 }
505 return (0x0);
506}
507
508static int
509umct_pre_param(struct usb2_com_softc *ucom, struct termios *t)
510{
511 return (0); /* we accept anything */
512}
513
514static void
515umct_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
516{
517 struct umct_softc *sc = ucom->sc_parent;
518 uint32_t value;
519
520 value = umct_calc_baud(t->c_ospeed);
521 umct_cfg_do_request(sc, UMCT_SET_BAUD, UMCT_SET_BAUD_SIZE, value);
522
523 value = (sc->sc_lcr & 0x40);
524
525 switch (t->c_cflag & CSIZE) {
526 case CS5:
527 value |= 0x0;
528 break;
529 case CS6:
530 value |= 0x1;
531 break;
532 case CS7:
533 value |= 0x2;
534 break;
535 default:
536 case CS8:
537 value |= 0x3;
538 break;
539 }
540
541 value |= (t->c_cflag & CSTOPB) ? 0x4 : 0;
542 if (t->c_cflag & PARENB) {
543 value |= 0x8;
544 value |= (t->c_cflag & PARODD) ? 0x0 : 0x10;
545 }
546 /*
547 * XXX There doesn't seem to be a way to tell the device
548 * to use flow control.
549 */
550
551 sc->sc_lcr = value;
552 umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, value);
553}
554
555static void
556umct_start_read(struct usb2_com_softc *ucom)
557{
558 struct umct_softc *sc = ucom->sc_parent;
559
560 /* start interrupt endpoint */
561 usb2_transfer_start(sc->sc_xfer[UMCT_INTR_DT_RD]);
562
563 /* start read endpoint */
564 usb2_transfer_start(sc->sc_xfer[UMCT_BULK_DT_RD]);
565}
566
567static void
568umct_stop_read(struct usb2_com_softc *ucom)
569{
570 struct umct_softc *sc = ucom->sc_parent;
571
572 /* stop interrupt endpoint */
359 }
360}
361
362static void
363umct_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
364{
365 struct umct_softc *sc = ucom->sc_parent;
366
367 *lsr = sc->sc_lsr;
368 *msr = sc->sc_msr;
369}
370
371static void
372umct_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
373{
374 struct umct_softc *sc = ucom->sc_parent;
375
376 if (onoff)
377 sc->sc_lcr |= 0x40;
378 else
379 sc->sc_lcr &= ~0x40;
380
381 umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, sc->sc_lcr);
382}
383
384static void
385umct_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
386{
387 struct umct_softc *sc = ucom->sc_parent;
388
389 if (onoff)
390 sc->sc_mcr |= 0x01;
391 else
392 sc->sc_mcr &= ~0x01;
393
394 umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr);
395}
396
397static void
398umct_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
399{
400 struct umct_softc *sc = ucom->sc_parent;
401
402 if (onoff)
403 sc->sc_mcr |= 0x02;
404 else
405 sc->sc_mcr &= ~0x02;
406
407 umct_cfg_do_request(sc, UMCT_SET_MCR, UMCT_SET_MCR_SIZE, sc->sc_mcr);
408}
409
410static uint8_t
411umct_calc_baud(uint32_t baud)
412{
413 switch (baud) {
414 case B300:return (0x1);
415 case B600:
416 return (0x2);
417 case B1200:
418 return (0x3);
419 case B2400:
420 return (0x4);
421 case B4800:
422 return (0x6);
423 case B9600:
424 return (0x8);
425 case B19200:
426 return (0x9);
427 case B38400:
428 return (0xa);
429 case B57600:
430 return (0xb);
431 case 115200:
432 return (0xc);
433 case B0:
434 default:
435 break;
436 }
437 return (0x0);
438}
439
440static int
441umct_pre_param(struct usb2_com_softc *ucom, struct termios *t)
442{
443 return (0); /* we accept anything */
444}
445
446static void
447umct_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
448{
449 struct umct_softc *sc = ucom->sc_parent;
450 uint32_t value;
451
452 value = umct_calc_baud(t->c_ospeed);
453 umct_cfg_do_request(sc, UMCT_SET_BAUD, UMCT_SET_BAUD_SIZE, value);
454
455 value = (sc->sc_lcr & 0x40);
456
457 switch (t->c_cflag & CSIZE) {
458 case CS5:
459 value |= 0x0;
460 break;
461 case CS6:
462 value |= 0x1;
463 break;
464 case CS7:
465 value |= 0x2;
466 break;
467 default:
468 case CS8:
469 value |= 0x3;
470 break;
471 }
472
473 value |= (t->c_cflag & CSTOPB) ? 0x4 : 0;
474 if (t->c_cflag & PARENB) {
475 value |= 0x8;
476 value |= (t->c_cflag & PARODD) ? 0x0 : 0x10;
477 }
478 /*
479 * XXX There doesn't seem to be a way to tell the device
480 * to use flow control.
481 */
482
483 sc->sc_lcr = value;
484 umct_cfg_do_request(sc, UMCT_SET_LCR, UMCT_SET_LCR_SIZE, value);
485}
486
487static void
488umct_start_read(struct usb2_com_softc *ucom)
489{
490 struct umct_softc *sc = ucom->sc_parent;
491
492 /* start interrupt endpoint */
493 usb2_transfer_start(sc->sc_xfer[UMCT_INTR_DT_RD]);
494
495 /* start read endpoint */
496 usb2_transfer_start(sc->sc_xfer[UMCT_BULK_DT_RD]);
497}
498
499static void
500umct_stop_read(struct usb2_com_softc *ucom)
501{
502 struct umct_softc *sc = ucom->sc_parent;
503
504 /* stop interrupt endpoint */
573 usb2_transfer_stop(sc->sc_xfer[UMCT_INTR_CS_RD]);
574 usb2_transfer_stop(sc->sc_xfer[UMCT_INTR_DT_RD]);
575
576 /* stop read endpoint */
505 usb2_transfer_stop(sc->sc_xfer[UMCT_INTR_DT_RD]);
506
507 /* stop read endpoint */
577 usb2_transfer_stop(sc->sc_xfer[UMCT_BULK_CS_RD]);
578 usb2_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_RD]);
579}
580
581static void
582umct_start_write(struct usb2_com_softc *ucom)
583{
584 struct umct_softc *sc = ucom->sc_parent;
585
586 usb2_transfer_start(sc->sc_xfer[UMCT_BULK_DT_WR]);
587}
588
589static void
590umct_stop_write(struct usb2_com_softc *ucom)
591{
592 struct umct_softc *sc = ucom->sc_parent;
593
508 usb2_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_RD]);
509}
510
511static void
512umct_start_write(struct usb2_com_softc *ucom)
513{
514 struct umct_softc *sc = ucom->sc_parent;
515
516 usb2_transfer_start(sc->sc_xfer[UMCT_BULK_DT_WR]);
517}
518
519static void
520umct_stop_write(struct usb2_com_softc *ucom)
521{
522 struct umct_softc *sc = ucom->sc_parent;
523
594 usb2_transfer_stop(sc->sc_xfer[UMCT_BULK_CS_WR]);
595 usb2_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_WR]);
596}
597
598static void
599umct_write_callback(struct usb2_xfer *xfer)
600{
601 struct umct_softc *sc = xfer->priv_sc;
602 uint32_t actlen;
603
604 switch (USB_GET_STATE(xfer)) {
605 case USB_ST_SETUP:
606 case USB_ST_TRANSFERRED:
524 usb2_transfer_stop(sc->sc_xfer[UMCT_BULK_DT_WR]);
525}
526
527static void
528umct_write_callback(struct usb2_xfer *xfer)
529{
530 struct umct_softc *sc = xfer->priv_sc;
531 uint32_t actlen;
532
533 switch (USB_GET_STATE(xfer)) {
534 case USB_ST_SETUP:
535 case USB_ST_TRANSFERRED:
607 if (sc->sc_flags & UMCT_FLAG_WRITE_STALL) {
608 usb2_transfer_start(sc->sc_xfer[UMCT_BULK_CS_WR]);
609 return;
610 }
536tr_setup:
611 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
612 sc->sc_obufsize, &actlen)) {
613
614 xfer->frlengths[0] = actlen;
615 usb2_start_hardware(xfer);
616 }
617 return;
618
619 default: /* Error */
620 if (xfer->error != USB_ERR_CANCELLED) {
537 if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
538 sc->sc_obufsize, &actlen)) {
539
540 xfer->frlengths[0] = actlen;
541 usb2_start_hardware(xfer);
542 }
543 return;
544
545 default: /* Error */
546 if (xfer->error != USB_ERR_CANCELLED) {
621 sc->sc_flags |= UMCT_FLAG_WRITE_STALL;
622 usb2_transfer_start(sc->sc_xfer[UMCT_BULK_CS_WR]);
547 /* try to clear stall first */
548 xfer->flags.stall_pipe = 1;
549 goto tr_setup;
623 }
624 return;
550 }
551 return;
625
626 }
627}
628
629static void
552 }
553}
554
555static void
630umct_write_clear_stall_callback(struct usb2_xfer *xfer)
631{
632 struct umct_softc *sc = xfer->priv_sc;
633 struct usb2_xfer *xfer_other = sc->sc_xfer[UMCT_BULK_DT_WR];
634
635 if (usb2_clear_stall_callback(xfer, xfer_other)) {
636 DPRINTF("stall cleared\n");
637 sc->sc_flags &= ~UMCT_FLAG_WRITE_STALL;
638 usb2_transfer_start(xfer_other);
639 }
640}
641
642static void
643umct_read_callback(struct usb2_xfer *xfer)
644{
645 struct umct_softc *sc = xfer->priv_sc;
646
647 switch (USB_GET_STATE(xfer)) {
648 case USB_ST_TRANSFERRED:
649 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers,
650 0, xfer->actlen);
651
652 case USB_ST_SETUP:
556umct_read_callback(struct usb2_xfer *xfer)
557{
558 struct umct_softc *sc = xfer->priv_sc;
559
560 switch (USB_GET_STATE(xfer)) {
561 case USB_ST_TRANSFERRED:
562 usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers,
563 0, xfer->actlen);
564
565 case USB_ST_SETUP:
653 if (sc->sc_flags & UMCT_FLAG_READ_STALL) {
654 usb2_transfer_start(sc->sc_xfer[UMCT_BULK_CS_RD]);
655 } else {
656 xfer->frlengths[0] = xfer->max_data_length;
657 usb2_start_hardware(xfer);
658 }
566tr_setup:
567 xfer->frlengths[0] = xfer->max_data_length;
568 usb2_start_hardware(xfer);
659 return;
660
661 default: /* Error */
662 if (xfer->error != USB_ERR_CANCELLED) {
569 return;
570
571 default: /* Error */
572 if (xfer->error != USB_ERR_CANCELLED) {
663 sc->sc_flags |= UMCT_FLAG_READ_STALL;
664 usb2_transfer_start(sc->sc_xfer[UMCT_BULK_CS_RD]);
573 /* try to clear stall first */
574 xfer->flags.stall_pipe = 1;
575 goto tr_setup;
665 }
666 return;
576 }
577 return;
667
668 }
669}
578 }
579}
670
671static void
672umct_read_clear_stall_callback(struct usb2_xfer *xfer)
673{
674 struct umct_softc *sc = xfer->priv_sc;
675 struct usb2_xfer *xfer_other = sc->sc_xfer[UMCT_BULK_DT_RD];
676
677 if (usb2_clear_stall_callback(xfer, xfer_other)) {
678 DPRINTF("stall cleared\n");
679 sc->sc_flags &= ~UMCT_FLAG_READ_STALL;
680 usb2_transfer_start(xfer_other);
681 }
682}