xref: /freebsd/sys/dev/usb/serial/uftdi.c (revision b3aaa0cc21c63d388230c7ef2a80abd631ff20d5)
1 /*	$NetBSD: uftdi.c,v 1.13 2002/09/23 05:51:23 simonb Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Lennart Augustsson (lennart@augustsson.net).
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41 
42 /*
43  * NOTE: all function names beginning like "uftdi_cfg_" can only
44  * be called from within the config thread function !
45  */
46 
47 /*
48  * FTDI FT8U100AX serial adapter driver
49  */
50 
51 #include "usbdevs.h"
52 #include <dev/usb/usb.h>
53 #include <dev/usb/usb_mfunc.h>
54 #include <dev/usb/usb_error.h>
55 #include <dev/usb/usb_cdc.h>
56 
57 #define	USB_DEBUG_VAR uftdi_debug
58 
59 #include <dev/usb/usb_core.h>
60 #include <dev/usb/usb_debug.h>
61 #include <dev/usb/usb_process.h>
62 #include <dev/usb/usb_request.h>
63 #include <dev/usb/usb_lookup.h>
64 #include <dev/usb/usb_util.h>
65 #include <dev/usb/usb_busdma.h>
66 
67 #include <dev/usb/serial/usb_serial.h>
68 #include <dev/usb/serial/uftdi_reg.h>
69 
70 #if USB_DEBUG
71 static int uftdi_debug = 0;
72 
73 SYSCTL_NODE(_hw_usb2, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi");
74 SYSCTL_INT(_hw_usb2_uftdi, OID_AUTO, debug, CTLFLAG_RW,
75     &uftdi_debug, 0, "Debug level");
76 #endif
77 
78 #define	UFTDI_CONFIG_INDEX	0
79 #define	UFTDI_IFACE_INDEX	0
80 
81 #define	UFTDI_IBUFSIZE 64		/* bytes, maximum number of bytes per
82 					 * frame */
83 #define	UFTDI_OBUFSIZE 64		/* bytes, cannot be increased due to
84 					 * do size encoding */
85 
86 enum {
87 	UFTDI_BULK_DT_WR,
88 	UFTDI_BULK_DT_RD,
89 	UFTDI_N_TRANSFER,
90 };
91 
92 struct uftdi_softc {
93 	struct usb2_com_super_softc sc_super_ucom;
94 	struct usb2_com_softc sc_ucom;
95 
96 	struct usb2_device *sc_udev;
97 	struct usb2_xfer *sc_xfer[UFTDI_N_TRANSFER];
98 	device_t sc_dev;
99 
100 	uint32_t sc_unit;
101 	enum uftdi_type sc_type;
102 
103 	uint16_t sc_last_lcr;
104 
105 	uint8_t	sc_iface_index;
106 	uint8_t	sc_hdrlen;
107 	uint8_t	sc_msr;
108 	uint8_t	sc_lsr;
109 
110 	uint8_t	sc_name[16];
111 };
112 
113 struct uftdi_param_config {
114 	uint16_t rate;
115 	uint16_t lcr;
116 	uint8_t	v_start;
117 	uint8_t	v_stop;
118 	uint8_t	v_flow;
119 };
120 
121 /* prototypes */
122 
123 static device_probe_t uftdi_probe;
124 static device_attach_t uftdi_attach;
125 static device_detach_t uftdi_detach;
126 
127 static usb2_callback_t uftdi_write_callback;
128 static usb2_callback_t uftdi_read_callback;
129 
130 static void	uftdi_cfg_open(struct usb2_com_softc *);
131 static void	uftdi_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
132 static void	uftdi_cfg_set_rts(struct usb2_com_softc *, uint8_t);
133 static void	uftdi_cfg_set_break(struct usb2_com_softc *, uint8_t);
134 static int	uftdi_set_parm_soft(struct termios *,
135 		    struct uftdi_param_config *, uint8_t);
136 static int	uftdi_pre_param(struct usb2_com_softc *, struct termios *);
137 static void	uftdi_cfg_param(struct usb2_com_softc *, struct termios *);
138 static void	uftdi_cfg_get_status(struct usb2_com_softc *, uint8_t *,
139 		    uint8_t *);
140 static void	uftdi_start_read(struct usb2_com_softc *);
141 static void	uftdi_stop_read(struct usb2_com_softc *);
142 static void	uftdi_start_write(struct usb2_com_softc *);
143 static void	uftdi_stop_write(struct usb2_com_softc *);
144 static uint8_t	uftdi_8u232am_getrate(uint32_t, uint16_t *);
145 
146 static const struct usb2_config uftdi_config[UFTDI_N_TRANSFER] = {
147 
148 	[UFTDI_BULK_DT_WR] = {
149 		.type = UE_BULK,
150 		.endpoint = UE_ADDR_ANY,
151 		.direction = UE_DIR_OUT,
152 		.mh.bufsize = UFTDI_OBUFSIZE,
153 		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
154 		.mh.callback = &uftdi_write_callback,
155 	},
156 
157 	[UFTDI_BULK_DT_RD] = {
158 		.type = UE_BULK,
159 		.endpoint = UE_ADDR_ANY,
160 		.direction = UE_DIR_IN,
161 		.mh.bufsize = UFTDI_IBUFSIZE,
162 		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
163 		.mh.callback = &uftdi_read_callback,
164 	},
165 };
166 
167 static const struct usb2_com_callback uftdi_callback = {
168 	.usb2_com_cfg_get_status = &uftdi_cfg_get_status,
169 	.usb2_com_cfg_set_dtr = &uftdi_cfg_set_dtr,
170 	.usb2_com_cfg_set_rts = &uftdi_cfg_set_rts,
171 	.usb2_com_cfg_set_break = &uftdi_cfg_set_break,
172 	.usb2_com_cfg_param = &uftdi_cfg_param,
173 	.usb2_com_cfg_open = &uftdi_cfg_open,
174 	.usb2_com_pre_param = &uftdi_pre_param,
175 	.usb2_com_start_read = &uftdi_start_read,
176 	.usb2_com_stop_read = &uftdi_stop_read,
177 	.usb2_com_start_write = &uftdi_start_write,
178 	.usb2_com_stop_write = &uftdi_stop_write,
179 };
180 
181 static device_method_t uftdi_methods[] = {
182 	/* Device interface */
183 	DEVMETHOD(device_probe, uftdi_probe),
184 	DEVMETHOD(device_attach, uftdi_attach),
185 	DEVMETHOD(device_detach, uftdi_detach),
186 
187 	{0, 0}
188 };
189 
190 static devclass_t uftdi_devclass;
191 
192 static driver_t uftdi_driver = {
193 	.name = "uftdi",
194 	.methods = uftdi_methods,
195 	.size = sizeof(struct uftdi_softc),
196 };
197 
198 DRIVER_MODULE(uftdi, ushub, uftdi_driver, uftdi_devclass, NULL, 0);
199 MODULE_DEPEND(uftdi, ucom, 1, 1, 1);
200 MODULE_DEPEND(uftdi, usb, 1, 1, 1);
201 
202 static struct usb2_device_id uftdi_devs[] = {
203 	{USB_VPI(USB_VENDOR_DRESDENELEKTRONIK, USB_PRODUCT_DRESDENELEKTRONIK_SENSORTERMINALBOARD, UFTDI_TYPE_8U232AM)},
204 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U100AX, UFTDI_TYPE_SIO)},
205 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_2232C, UFTDI_TYPE_8U232AM)},
206 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U232AM, UFTDI_TYPE_8U232AM)},
207 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SEMC_DSS20, UFTDI_TYPE_8U232AM)},
208 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_631, UFTDI_TYPE_8U232AM)},
209 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_632, UFTDI_TYPE_8U232AM)},
210 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_633, UFTDI_TYPE_8U232AM)},
211 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_634, UFTDI_TYPE_8U232AM)},
212 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_635, UFTDI_TYPE_8U232AM)},
213 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_USBSERIAL, UFTDI_TYPE_8U232AM)},
214 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX2_3, UFTDI_TYPE_8U232AM)},
215 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX4_5, UFTDI_TYPE_8U232AM)},
216 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK202, UFTDI_TYPE_8U232AM)},
217 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK204, UFTDI_TYPE_8U232AM)},
218 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13M, UFTDI_TYPE_8U232AM)},
219 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13S, UFTDI_TYPE_8U232AM)},
220 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13U, UFTDI_TYPE_8U232AM)},
221 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EISCOU, UFTDI_TYPE_8U232AM)},
222 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_UOPTBR, UFTDI_TYPE_8U232AM)},
223 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2D, UFTDI_TYPE_8U232AM)},
224 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_PCMSFU, UFTDI_TYPE_8U232AM)},
225 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2H, UFTDI_TYPE_8U232AM)},
226 	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MAXSTREAM, UFTDI_TYPE_8U232AM)},
227 	{USB_VPI(USB_VENDOR_SIIG2, USB_PRODUCT_SIIG2_US2308, UFTDI_TYPE_8U232AM)},
228 	{USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_VALUECAN, UFTDI_TYPE_8U232AM)},
229 	{USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_NEOVI, UFTDI_TYPE_8U232AM)},
230 	{USB_VPI(USB_VENDOR_BBELECTRONICS, USB_PRODUCT_BBELECTRONICS_USOTL4, UFTDI_TYPE_8U232AM)},
231 	{USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_PCOPRS1, UFTDI_TYPE_8U232AM)},
232 };
233 
234 static int
235 uftdi_probe(device_t dev)
236 {
237 	struct usb2_attach_arg *uaa = device_get_ivars(dev);
238 
239 	if (uaa->usb2_mode != USB_MODE_HOST) {
240 		return (ENXIO);
241 	}
242 	if (uaa->info.bConfigIndex != UFTDI_CONFIG_INDEX) {
243 		return (ENXIO);
244 	}
245 	/* attach to all present interfaces */
246 
247 	return (usb2_lookup_id_by_uaa(uftdi_devs, sizeof(uftdi_devs), uaa));
248 }
249 
250 static int
251 uftdi_attach(device_t dev)
252 {
253 	struct usb2_attach_arg *uaa = device_get_ivars(dev);
254 	struct uftdi_softc *sc = device_get_softc(dev);
255 	int error;
256 
257 	sc->sc_udev = uaa->device;
258 	sc->sc_dev = dev;
259 	sc->sc_unit = device_get_unit(dev);
260 
261 	device_set_usb2_desc(dev);
262 
263 	snprintf(sc->sc_name, sizeof(sc->sc_name),
264 	    "%s", device_get_nameunit(dev));
265 
266 	DPRINTF("\n");
267 
268 	sc->sc_iface_index = uaa->info.bIfaceIndex;
269 	sc->sc_type = USB_GET_DRIVER_INFO(uaa);
270 
271 	switch (sc->sc_type) {
272 	case UFTDI_TYPE_SIO:
273 		sc->sc_hdrlen = 1;
274 		break;
275 	case UFTDI_TYPE_8U232AM:
276 	default:
277 		sc->sc_hdrlen = 0;
278 		break;
279 	}
280 
281 	error = usb2_transfer_setup(uaa->device,
282 	    &sc->sc_iface_index, sc->sc_xfer, uftdi_config,
283 	    UFTDI_N_TRANSFER, sc, &Giant);
284 
285 	if (error) {
286 		device_printf(dev, "allocating USB "
287 		    "transfers failed!\n");
288 		goto detach;
289 	}
290 	sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum;
291 
292 	/* clear stall at first run */
293 	usb2_transfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_WR]);
294 	usb2_transfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_RD]);
295 
296 	/* set a valid "lcr" value */
297 
298 	sc->sc_last_lcr =
299 	    (FTDI_SIO_SET_DATA_STOP_BITS_2 |
300 	    FTDI_SIO_SET_DATA_PARITY_NONE |
301 	    FTDI_SIO_SET_DATA_BITS(8));
302 
303 	error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
304 	    &uftdi_callback, &Giant);
305 	if (error) {
306 		goto detach;
307 	}
308 	return (0);			/* success */
309 
310 detach:
311 	uftdi_detach(dev);
312 	return (ENXIO);
313 }
314 
315 static int
316 uftdi_detach(device_t dev)
317 {
318 	struct uftdi_softc *sc = device_get_softc(dev);
319 
320 	usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
321 
322 	usb2_transfer_unsetup(sc->sc_xfer, UFTDI_N_TRANSFER);
323 
324 	return (0);
325 }
326 
327 static void
328 uftdi_cfg_open(struct usb2_com_softc *ucom)
329 {
330 	struct uftdi_softc *sc = ucom->sc_parent;
331 	uint16_t wIndex = ucom->sc_portno;
332 	struct usb2_device_request req;
333 
334 	DPRINTF("");
335 
336 	/* perform a full reset on the device */
337 
338 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
339 	req.bRequest = FTDI_SIO_RESET;
340 	USETW(req.wValue, FTDI_SIO_RESET_SIO);
341 	USETW(req.wIndex, wIndex);
342 	USETW(req.wLength, 0);
343 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
344 	    &req, NULL, 0, 1000);
345 
346 	/* turn on RTS/CTS flow control */
347 
348 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
349 	req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
350 	USETW(req.wValue, 0);
351 	USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, wIndex);
352 	USETW(req.wLength, 0);
353 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
354 	    &req, NULL, 0, 1000);
355 
356 	/*
357 	 * NOTE: with the new UCOM layer there will always be a
358 	 * "uftdi_cfg_param()" call after "open()", so there is no need for
359 	 * "open()" to configure anything
360 	 */
361 }
362 
363 static void
364 uftdi_write_callback(struct usb2_xfer *xfer)
365 {
366 	struct uftdi_softc *sc = xfer->priv_sc;
367 	uint32_t actlen;
368 	uint8_t buf[1];
369 
370 	switch (USB_GET_STATE(xfer)) {
371 	case USB_ST_SETUP:
372 	case USB_ST_TRANSFERRED:
373 tr_setup:
374 		if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers,
375 		    sc->sc_hdrlen, UFTDI_OBUFSIZE - sc->sc_hdrlen,
376 		    &actlen)) {
377 
378 			if (sc->sc_hdrlen > 0) {
379 				buf[0] =
380 				    FTDI_OUT_TAG(actlen, sc->sc_ucom.sc_portno);
381 				usb2_copy_in(xfer->frbuffers, 0, buf, 1);
382 			}
383 			xfer->frlengths[0] = actlen + sc->sc_hdrlen;
384 			usb2_start_hardware(xfer);
385 		}
386 		return;
387 
388 	default:			/* Error */
389 		if (xfer->error != USB_ERR_CANCELLED) {
390 			/* try to clear stall first */
391 			xfer->flags.stall_pipe = 1;
392 			goto tr_setup;
393 		}
394 		return;
395 	}
396 }
397 
398 static void
399 uftdi_read_callback(struct usb2_xfer *xfer)
400 {
401 	struct uftdi_softc *sc = xfer->priv_sc;
402 	uint8_t buf[2];
403 	uint8_t ftdi_msr;
404 	uint8_t msr;
405 	uint8_t lsr;
406 
407 	switch (USB_GET_STATE(xfer)) {
408 	case USB_ST_TRANSFERRED:
409 
410 		if (xfer->actlen < 2) {
411 			goto tr_setup;
412 		}
413 		usb2_copy_out(xfer->frbuffers, 0, buf, 2);
414 
415 		ftdi_msr = FTDI_GET_MSR(buf);
416 		lsr = FTDI_GET_LSR(buf);
417 
418 		msr = 0;
419 		if (ftdi_msr & FTDI_SIO_CTS_MASK)
420 			msr |= SER_CTS;
421 		if (ftdi_msr & FTDI_SIO_DSR_MASK)
422 			msr |= SER_DSR;
423 		if (ftdi_msr & FTDI_SIO_RI_MASK)
424 			msr |= SER_RI;
425 		if (ftdi_msr & FTDI_SIO_RLSD_MASK)
426 			msr |= SER_DCD;
427 
428 		if ((sc->sc_msr != msr) ||
429 		    ((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) {
430 			DPRINTF("status change msr=0x%02x (0x%02x) "
431 			    "lsr=0x%02x (0x%02x)\n", msr, sc->sc_msr,
432 			    lsr, sc->sc_lsr);
433 
434 			sc->sc_msr = msr;
435 			sc->sc_lsr = lsr;
436 
437 			usb2_com_status_change(&sc->sc_ucom);
438 		}
439 		xfer->actlen -= 2;
440 
441 		if (xfer->actlen > 0) {
442 			usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 2,
443 			    xfer->actlen);
444 		}
445 	case USB_ST_SETUP:
446 tr_setup:
447 		xfer->frlengths[0] = xfer->max_data_length;
448 		usb2_start_hardware(xfer);
449 		return;
450 
451 	default:			/* Error */
452 		if (xfer->error != USB_ERR_CANCELLED) {
453 			/* try to clear stall first */
454 			xfer->flags.stall_pipe = 1;
455 			goto tr_setup;
456 		}
457 		return;
458 	}
459 }
460 
461 static void
462 uftdi_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
463 {
464 	struct uftdi_softc *sc = ucom->sc_parent;
465 	uint16_t wIndex = ucom->sc_portno;
466 	uint16_t wValue;
467 	struct usb2_device_request req;
468 
469 	wValue = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW;
470 
471 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
472 	req.bRequest = FTDI_SIO_MODEM_CTRL;
473 	USETW(req.wValue, wValue);
474 	USETW(req.wIndex, wIndex);
475 	USETW(req.wLength, 0);
476 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
477 	    &req, NULL, 0, 1000);
478 }
479 
480 static void
481 uftdi_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
482 {
483 	struct uftdi_softc *sc = ucom->sc_parent;
484 	uint16_t wIndex = ucom->sc_portno;
485 	uint16_t wValue;
486 	struct usb2_device_request req;
487 
488 	wValue = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
489 
490 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
491 	req.bRequest = FTDI_SIO_MODEM_CTRL;
492 	USETW(req.wValue, wValue);
493 	USETW(req.wIndex, wIndex);
494 	USETW(req.wLength, 0);
495 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
496 	    &req, NULL, 0, 1000);
497 }
498 
499 static void
500 uftdi_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
501 {
502 	struct uftdi_softc *sc = ucom->sc_parent;
503 	uint16_t wIndex = ucom->sc_portno;
504 	uint16_t wValue;
505 	struct usb2_device_request req;
506 
507 	if (onoff) {
508 		sc->sc_last_lcr |= FTDI_SIO_SET_BREAK;
509 	} else {
510 		sc->sc_last_lcr &= ~FTDI_SIO_SET_BREAK;
511 	}
512 
513 	wValue = sc->sc_last_lcr;
514 
515 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
516 	req.bRequest = FTDI_SIO_SET_DATA;
517 	USETW(req.wValue, wValue);
518 	USETW(req.wIndex, wIndex);
519 	USETW(req.wLength, 0);
520 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
521 	    &req, NULL, 0, 1000);
522 }
523 
524 static int
525 uftdi_set_parm_soft(struct termios *t,
526     struct uftdi_param_config *cfg, uint8_t type)
527 {
528 	bzero(cfg, sizeof(*cfg));
529 
530 	switch (type) {
531 	case UFTDI_TYPE_SIO:
532 		switch (t->c_ospeed) {
533 		case 300:
534 			cfg->rate = ftdi_sio_b300;
535 			break;
536 		case 600:
537 			cfg->rate = ftdi_sio_b600;
538 			break;
539 		case 1200:
540 			cfg->rate = ftdi_sio_b1200;
541 			break;
542 		case 2400:
543 			cfg->rate = ftdi_sio_b2400;
544 			break;
545 		case 4800:
546 			cfg->rate = ftdi_sio_b4800;
547 			break;
548 		case 9600:
549 			cfg->rate = ftdi_sio_b9600;
550 			break;
551 		case 19200:
552 			cfg->rate = ftdi_sio_b19200;
553 			break;
554 		case 38400:
555 			cfg->rate = ftdi_sio_b38400;
556 			break;
557 		case 57600:
558 			cfg->rate = ftdi_sio_b57600;
559 			break;
560 		case 115200:
561 			cfg->rate = ftdi_sio_b115200;
562 			break;
563 		default:
564 			return (EINVAL);
565 		}
566 		break;
567 
568 	case UFTDI_TYPE_8U232AM:
569 		if (uftdi_8u232am_getrate(t->c_ospeed, &cfg->rate)) {
570 			return (EINVAL);
571 		}
572 		break;
573 	}
574 
575 	if (t->c_cflag & CSTOPB)
576 		cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_2;
577 	else
578 		cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_1;
579 
580 	if (t->c_cflag & PARENB) {
581 		if (t->c_cflag & PARODD) {
582 			cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_ODD;
583 		} else {
584 			cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_EVEN;
585 		}
586 	} else {
587 		cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_NONE;
588 	}
589 
590 	switch (t->c_cflag & CSIZE) {
591 	case CS5:
592 		cfg->lcr |= FTDI_SIO_SET_DATA_BITS(5);
593 		break;
594 
595 	case CS6:
596 		cfg->lcr |= FTDI_SIO_SET_DATA_BITS(6);
597 		break;
598 
599 	case CS7:
600 		cfg->lcr |= FTDI_SIO_SET_DATA_BITS(7);
601 		break;
602 
603 	case CS8:
604 		cfg->lcr |= FTDI_SIO_SET_DATA_BITS(8);
605 		break;
606 	}
607 
608 	if (t->c_cflag & CRTSCTS) {
609 		cfg->v_flow = FTDI_SIO_RTS_CTS_HS;
610 	} else if (t->c_iflag & (IXON | IXOFF)) {
611 		cfg->v_flow = FTDI_SIO_XON_XOFF_HS;
612 		cfg->v_start = t->c_cc[VSTART];
613 		cfg->v_stop = t->c_cc[VSTOP];
614 	} else {
615 		cfg->v_flow = FTDI_SIO_DISABLE_FLOW_CTRL;
616 	}
617 
618 	return (0);
619 }
620 
621 static int
622 uftdi_pre_param(struct usb2_com_softc *ucom, struct termios *t)
623 {
624 	struct uftdi_softc *sc = ucom->sc_parent;
625 	struct uftdi_param_config cfg;
626 
627 	DPRINTF("\n");
628 
629 	return (uftdi_set_parm_soft(t, &cfg, sc->sc_type));
630 }
631 
632 static void
633 uftdi_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
634 {
635 	struct uftdi_softc *sc = ucom->sc_parent;
636 	uint16_t wIndex = ucom->sc_portno;
637 	struct uftdi_param_config cfg;
638 	struct usb2_device_request req;
639 
640 	if (uftdi_set_parm_soft(t, &cfg, sc->sc_type)) {
641 		/* should not happen */
642 		return;
643 	}
644 	sc->sc_last_lcr = cfg.lcr;
645 
646 	DPRINTF("\n");
647 
648 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
649 	req.bRequest = FTDI_SIO_SET_BAUD_RATE;
650 	USETW(req.wValue, cfg.rate);
651 	USETW(req.wIndex, wIndex);
652 	USETW(req.wLength, 0);
653 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
654 	    &req, NULL, 0, 1000);
655 
656 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
657 	req.bRequest = FTDI_SIO_SET_DATA;
658 	USETW(req.wValue, cfg.lcr);
659 	USETW(req.wIndex, wIndex);
660 	USETW(req.wLength, 0);
661 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
662 	    &req, NULL, 0, 1000);
663 
664 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
665 	req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
666 	USETW2(req.wValue, cfg.v_stop, cfg.v_start);
667 	USETW2(req.wIndex, cfg.v_flow, wIndex);
668 	USETW(req.wLength, 0);
669 	usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
670 	    &req, NULL, 0, 1000);
671 }
672 
673 static void
674 uftdi_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
675 {
676 	struct uftdi_softc *sc = ucom->sc_parent;
677 
678 	DPRINTF("msr=0x%02x lsr=0x%02x\n",
679 	    sc->sc_msr, sc->sc_lsr);
680 
681 	*msr = sc->sc_msr;
682 	*lsr = sc->sc_lsr;
683 }
684 
685 static void
686 uftdi_start_read(struct usb2_com_softc *ucom)
687 {
688 	struct uftdi_softc *sc = ucom->sc_parent;
689 
690 	usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_RD]);
691 }
692 
693 static void
694 uftdi_stop_read(struct usb2_com_softc *ucom)
695 {
696 	struct uftdi_softc *sc = ucom->sc_parent;
697 
698 	usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_RD]);
699 }
700 
701 static void
702 uftdi_start_write(struct usb2_com_softc *ucom)
703 {
704 	struct uftdi_softc *sc = ucom->sc_parent;
705 
706 	usb2_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_WR]);
707 }
708 
709 static void
710 uftdi_stop_write(struct usb2_com_softc *ucom)
711 {
712 	struct uftdi_softc *sc = ucom->sc_parent;
713 
714 	usb2_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_WR]);
715 }
716 
717 /*------------------------------------------------------------------------*
718  *	uftdi_8u232am_getrate
719  *
720  * Return values:
721  *    0: Success
722  * Else: Failure
723  *------------------------------------------------------------------------*/
724 static uint8_t
725 uftdi_8u232am_getrate(uint32_t speed, uint16_t *rate)
726 {
727 	/* Table of the nearest even powers-of-2 for values 0..15. */
728 	static const uint8_t roundoff[16] = {
729 		0, 2, 2, 4, 4, 4, 8, 8,
730 		8, 8, 8, 8, 16, 16, 16, 16,
731 	};
732 	uint32_t d;
733 	uint32_t freq;
734 	uint16_t result;
735 
736 	if ((speed < 178) || (speed > ((3000000 * 100) / 97)))
737 		return (1);		/* prevent numerical overflow */
738 
739 	/* Special cases for 2M and 3M. */
740 	if ((speed >= ((3000000 * 100) / 103)) &&
741 	    (speed <= ((3000000 * 100) / 97))) {
742 		result = 0;
743 		goto done;
744 	}
745 	if ((speed >= ((2000000 * 100) / 103)) &&
746 	    (speed <= ((2000000 * 100) / 97))) {
747 		result = 1;
748 		goto done;
749 	}
750 	d = (FTDI_8U232AM_FREQ << 4) / speed;
751 	d = (d & ~15) + roundoff[d & 15];
752 
753 	if (d < FTDI_8U232AM_MIN_DIV)
754 		d = FTDI_8U232AM_MIN_DIV;
755 	else if (d > FTDI_8U232AM_MAX_DIV)
756 		d = FTDI_8U232AM_MAX_DIV;
757 
758 	/*
759 	 * Calculate the frequency needed for "d" to exactly divide down to
760 	 * our target "speed", and check that the actual frequency is within
761 	 * 3% of this.
762 	 */
763 	freq = (speed * d);
764 	if ((freq < ((FTDI_8U232AM_FREQ * 1600ULL) / 103)) ||
765 	    (freq > ((FTDI_8U232AM_FREQ * 1600ULL) / 97)))
766 		return (1);
767 
768 	/*
769 	 * Pack the divisor into the resultant value.  The lower 14-bits
770 	 * hold the integral part, while the upper 2 bits encode the
771 	 * fractional component: either 0, 0.5, 0.25, or 0.125.
772 	 */
773 	result = (d >> 4);
774 	if (d & 8)
775 		result |= 0x4000;
776 	else if (d & 4)
777 		result |= 0x8000;
778 	else if (d & 2)
779 		result |= 0xc000;
780 
781 done:
782 	*rate = result;
783 	return (0);
784 }
785