uftdi.c revision 187176
1112158Sdas/*	$NetBSD: uftdi.c,v 1.13 2002/09/23 05:51:23 simonb Exp $	*/
2112158Sdas
3112158Sdas/*-
4112158Sdas * Copyright (c) 2000 The NetBSD Foundation, Inc.
5112158Sdas * All rights reserved.
6112158Sdas *
7112158Sdas * This code is derived from software contributed to The NetBSD Foundation
8112158Sdas * by Lennart Augustsson (lennart@augustsson.net).
9112158Sdas *
10112158Sdas * Redistribution and use in source and binary forms, with or without
11112158Sdas * modification, are permitted provided that the following conditions
12112158Sdas * are met:
13112158Sdas * 1. Redistributions of source code must retain the above copyright
14112158Sdas *    notice, this list of conditions and the following disclaimer.
15112158Sdas * 2. Redistributions in binary form must reproduce the above copyright
16112158Sdas *    notice, this list of conditions and the following disclaimer in the
17112158Sdas *    documentation and/or other materials provided with the distribution.
18112158Sdas * 3. All advertising materials mentioning features or use of this software
19112158Sdas *    must display the following acknowledgement:
20112158Sdas *        This product includes software developed by the NetBSD
21112158Sdas *        Foundation, Inc. and its contributors.
22112158Sdas * 4. Neither the name of The NetBSD Foundation nor the names of its
23112158Sdas *    contributors may be used to endorse or promote products derived
24112158Sdas *    from this software without specific prior written permission.
25112158Sdas *
26112158Sdas * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27112158Sdas * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28112158Sdas * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29165743Sdas * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30165743Sdas * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31112158Sdas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32112158Sdas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33112158Sdas * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34112158Sdas * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35112158Sdas * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36112158Sdas * POSSIBILITY OF SUCH DAMAGE.
37112158Sdas */
38112158Sdas
39112158Sdas#include <sys/cdefs.h>
40112158Sdas__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/uftdi2.c 187176 2009-01-13 19:03:47Z thompsa $");
41112158Sdas
42112158Sdas/*
43112158Sdas * NOTE: all function names beginning like "uftdi_cfg_" can only
44112158Sdas * be called from within the config thread function !
45112158Sdas */
46112158Sdas
47112158Sdas/*
48112158Sdas * FTDI FT8U100AX serial adapter driver
49112158Sdas */
50112158Sdas
51112158Sdas#include <dev/usb2/include/usb2_devid.h>
52112158Sdas#include <dev/usb2/include/usb2_standard.h>
53112158Sdas#include <dev/usb2/include/usb2_mfunc.h>
54112158Sdas#include <dev/usb2/include/usb2_error.h>
55112158Sdas#include <dev/usb2/include/usb2_cdc.h>
56112158Sdas
57112158Sdas#define	USB_DEBUG_VAR uftdi_debug
58112158Sdas
59112158Sdas#include <dev/usb2/core/usb2_core.h>
60112158Sdas#include <dev/usb2/core/usb2_debug.h>
61112158Sdas#include <dev/usb2/core/usb2_process.h>
62112158Sdas#include <dev/usb2/core/usb2_request.h>
63112158Sdas#include <dev/usb2/core/usb2_lookup.h>
64112158Sdas#include <dev/usb2/core/usb2_util.h>
65112158Sdas#include <dev/usb2/core/usb2_busdma.h>
66112158Sdas
67165743Sdas#include <dev/usb2/serial/usb2_serial.h>
68165743Sdas#include <dev/usb2/serial/uftdi2_reg.h>
69165743Sdas
70165743Sdas#if USB_DEBUG
71112158Sdasstatic int uftdi_debug = 0;
72112158Sdas
73165743SdasSYSCTL_NODE(_hw_usb2, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi");
74165743SdasSYSCTL_INT(_hw_usb2_uftdi, OID_AUTO, debug, CTLFLAG_RW,
75112158Sdas    &uftdi_debug, 0, "Debug level");
76112158Sdas#endif
77112158Sdas
78112158Sdas#define	UFTDI_CONFIG_INDEX	0
79112158Sdas#define	UFTDI_IFACE_INDEX	0
80112158Sdas#define	UFTDI_ENDPT_MAX		4
81112158Sdas
82112158Sdas#define	UFTDI_IBUFSIZE 64		/* bytes, maximum number of bytes per
83112158Sdas					 * frame */
84112158Sdas#define	UFTDI_OBUFSIZE 64		/* bytes, cannot be increased due to
85112158Sdas					 * do size encoding */
86112158Sdas
87165743Sdasstruct uftdi_softc {
88165743Sdas	struct usb2_com_super_softc sc_super_ucom;
89165743Sdas	struct usb2_com_softc sc_ucom;
90165743Sdas
91165743Sdas	struct usb2_device *sc_udev;
92112158Sdas	struct usb2_xfer *sc_xfer[UFTDI_ENDPT_MAX];
93112158Sdas	device_t sc_dev;
94112158Sdas
95112158Sdas	uint32_t sc_unit;
96112158Sdas	enum uftdi_type sc_type;
97112158Sdas
98112158Sdas	uint16_t sc_last_lcr;
99112158Sdas
100112158Sdas	uint8_t	sc_iface_index;
101112158Sdas	uint8_t	sc_hdrlen;
102112158Sdas
103112158Sdas	uint8_t	sc_msr;
104112158Sdas	uint8_t	sc_lsr;
105112158Sdas
106112158Sdas	uint8_t	sc_flag;
107112158Sdas#define	UFTDI_FLAG_WRITE_STALL  0x01
108112158Sdas#define	UFTDI_FLAG_READ_STALL   0x02
109112158Sdas
110112158Sdas	uint8_t	sc_name[16];
111112158Sdas};
112112158Sdas
113112158Sdasstruct uftdi_param_config {
114112158Sdas	uint16_t rate;
115112158Sdas	uint16_t lcr;
116112158Sdas	uint8_t	v_start;
117112158Sdas	uint8_t	v_stop;
118112158Sdas	uint8_t	v_flow;
119112158Sdas};
120
121/* prototypes */
122
123static device_probe_t uftdi_probe;
124static device_attach_t uftdi_attach;
125static device_detach_t uftdi_detach;
126
127static usb2_callback_t uftdi_write_callback;
128static usb2_callback_t uftdi_write_clear_stall_callback;
129static usb2_callback_t uftdi_read_callback;
130static usb2_callback_t uftdi_read_clear_stall_callback;
131
132static void	uftdi_cfg_do_request(struct uftdi_softc *,
133		    struct usb2_device_request *, void *);
134static void	uftdi_cfg_open(struct usb2_com_softc *);
135static void	uftdi_cfg_set_dtr(struct usb2_com_softc *, uint8_t);
136static void	uftdi_cfg_set_rts(struct usb2_com_softc *, uint8_t);
137static void	uftdi_cfg_set_break(struct usb2_com_softc *, uint8_t);
138static int	uftdi_set_parm_soft(struct termios *,
139		    struct uftdi_param_config *, uint8_t);
140static int	uftdi_pre_param(struct usb2_com_softc *, struct termios *);
141static void	uftdi_cfg_param(struct usb2_com_softc *, struct termios *);
142static void	uftdi_cfg_get_status(struct usb2_com_softc *, uint8_t *,
143		    uint8_t *);
144static void	uftdi_start_read(struct usb2_com_softc *);
145static void	uftdi_stop_read(struct usb2_com_softc *);
146static void	uftdi_start_write(struct usb2_com_softc *);
147static void	uftdi_stop_write(struct usb2_com_softc *);
148static uint8_t	uftdi_8u232am_getrate(uint32_t, uint16_t *);
149
150static const struct usb2_config uftdi_config[UFTDI_ENDPT_MAX] = {
151
152	[0] = {
153		.type = UE_BULK,
154		.endpoint = UE_ADDR_ANY,
155		.direction = UE_DIR_OUT,
156		.mh.bufsize = UFTDI_OBUFSIZE,
157		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
158		.mh.callback = &uftdi_write_callback,
159	},
160
161	[1] = {
162		.type = UE_BULK,
163		.endpoint = UE_ADDR_ANY,
164		.direction = UE_DIR_IN,
165		.mh.bufsize = UFTDI_IBUFSIZE,
166		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
167		.mh.callback = &uftdi_read_callback,
168	},
169
170	[2] = {
171		.type = UE_CONTROL,
172		.endpoint = 0x00,	/* Control pipe */
173		.direction = UE_DIR_ANY,
174		.mh.bufsize = sizeof(struct usb2_device_request),
175		.mh.flags = {},
176		.mh.callback = &uftdi_write_clear_stall_callback,
177		.mh.timeout = 1000,	/* 1 second */
178		.mh.interval = 50,	/* 50ms */
179	},
180
181	[3] = {
182		.type = UE_CONTROL,
183		.endpoint = 0x00,	/* Control pipe */
184		.direction = UE_DIR_ANY,
185		.mh.bufsize = sizeof(struct usb2_device_request),
186		.mh.flags = {},
187		.mh.callback = &uftdi_read_clear_stall_callback,
188		.mh.timeout = 1000,	/* 1 second */
189		.mh.interval = 50,	/* 50ms */
190	},
191};
192
193static const struct usb2_com_callback uftdi_callback = {
194	.usb2_com_cfg_get_status = &uftdi_cfg_get_status,
195	.usb2_com_cfg_set_dtr = &uftdi_cfg_set_dtr,
196	.usb2_com_cfg_set_rts = &uftdi_cfg_set_rts,
197	.usb2_com_cfg_set_break = &uftdi_cfg_set_break,
198	.usb2_com_cfg_param = &uftdi_cfg_param,
199	.usb2_com_cfg_open = &uftdi_cfg_open,
200	.usb2_com_pre_param = &uftdi_pre_param,
201	.usb2_com_start_read = &uftdi_start_read,
202	.usb2_com_stop_read = &uftdi_stop_read,
203	.usb2_com_start_write = &uftdi_start_write,
204	.usb2_com_stop_write = &uftdi_stop_write,
205};
206
207static device_method_t uftdi_methods[] = {
208	/* Device interface */
209	DEVMETHOD(device_probe, uftdi_probe),
210	DEVMETHOD(device_attach, uftdi_attach),
211	DEVMETHOD(device_detach, uftdi_detach),
212
213	{0, 0}
214};
215
216static devclass_t uftdi_devclass;
217
218static driver_t uftdi_driver = {
219	.name = "uftdi",
220	.methods = uftdi_methods,
221	.size = sizeof(struct uftdi_softc),
222};
223
224DRIVER_MODULE(uftdi, ushub, uftdi_driver, uftdi_devclass, NULL, 0);
225MODULE_DEPEND(uftdi, usb2_serial, 1, 1, 1);
226MODULE_DEPEND(uftdi, usb2_core, 1, 1, 1);
227
228static struct usb2_device_id uftdi_devs[] = {
229	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U100AX, UFTDI_TYPE_SIO)},
230	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_2232C, UFTDI_TYPE_8U232AM)},
231	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SERIAL_8U232AM, UFTDI_TYPE_8U232AM)},
232	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_SEMC_DSS20, UFTDI_TYPE_8U232AM)},
233	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_631, UFTDI_TYPE_8U232AM)},
234	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_632, UFTDI_TYPE_8U232AM)},
235	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_633, UFTDI_TYPE_8U232AM)},
236	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_634, UFTDI_TYPE_8U232AM)},
237	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_CFA_635, UFTDI_TYPE_8U232AM)},
238	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_USBSERIAL, UFTDI_TYPE_8U232AM)},
239	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX2_3, UFTDI_TYPE_8U232AM)},
240	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MX4_5, UFTDI_TYPE_8U232AM)},
241	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK202, UFTDI_TYPE_8U232AM)},
242	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_LK204, UFTDI_TYPE_8U232AM)},
243	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13M, UFTDI_TYPE_8U232AM)},
244	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13S, UFTDI_TYPE_8U232AM)},
245	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13U, UFTDI_TYPE_8U232AM)},
246	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EISCOU, UFTDI_TYPE_8U232AM)},
247	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_UOPTBR, UFTDI_TYPE_8U232AM)},
248	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2D, UFTDI_TYPE_8U232AM)},
249	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_PCMSFU, UFTDI_TYPE_8U232AM)},
250	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_EMCU2H, UFTDI_TYPE_8U232AM)},
251	{USB_VPI(USB_VENDOR_FTDI, USB_PRODUCT_FTDI_MAXSTREAM, UFTDI_TYPE_8U232AM)},
252	{USB_VPI(USB_VENDOR_SIIG2, USB_PRODUCT_SIIG2_US2308, UFTDI_TYPE_8U232AM)},
253	{USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_VALUECAN, UFTDI_TYPE_8U232AM)},
254	{USB_VPI(USB_VENDOR_INTREPIDCS, USB_PRODUCT_INTREPIDCS_NEOVI, UFTDI_TYPE_8U232AM)},
255	{USB_VPI(USB_VENDOR_BBELECTRONICS, USB_PRODUCT_BBELECTRONICS_USOTL4, UFTDI_TYPE_8U232AM)},
256	{USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_PCOPRS1, UFTDI_TYPE_8U232AM)},
257};
258
259static int
260uftdi_probe(device_t dev)
261{
262	struct usb2_attach_arg *uaa = device_get_ivars(dev);
263
264	if (uaa->usb2_mode != USB_MODE_HOST) {
265		return (ENXIO);
266	}
267	if (uaa->info.bConfigIndex != UFTDI_CONFIG_INDEX) {
268		return (ENXIO);
269	}
270	/* attach to all present interfaces */
271
272	return (usb2_lookup_id_by_uaa(uftdi_devs, sizeof(uftdi_devs), uaa));
273}
274
275static int
276uftdi_attach(device_t dev)
277{
278	struct usb2_attach_arg *uaa = device_get_ivars(dev);
279	struct uftdi_softc *sc = device_get_softc(dev);
280	int error;
281
282	if (sc == NULL) {
283		return (ENOMEM);
284	}
285	sc->sc_udev = uaa->device;
286	sc->sc_dev = dev;
287	sc->sc_unit = device_get_unit(dev);
288
289	device_set_usb2_desc(dev);
290
291	snprintf(sc->sc_name, sizeof(sc->sc_name),
292	    "%s", device_get_nameunit(dev));
293
294	DPRINTF("\n");
295
296	sc->sc_iface_index = uaa->info.bIfaceIndex;
297	sc->sc_type = USB_GET_DRIVER_INFO(uaa);
298
299	switch (sc->sc_type) {
300	case UFTDI_TYPE_SIO:
301		sc->sc_hdrlen = 1;
302		break;
303	case UFTDI_TYPE_8U232AM:
304	default:
305		sc->sc_hdrlen = 0;
306		break;
307	}
308
309	error = usb2_transfer_setup(uaa->device,
310	    &sc->sc_iface_index, sc->sc_xfer, uftdi_config,
311	    UFTDI_ENDPT_MAX, sc, &Giant);
312
313	if (error) {
314		device_printf(dev, "allocating USB "
315		    "transfers failed!\n");
316		goto detach;
317	}
318	sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum;
319
320	/* clear stall at first run */
321
322	sc->sc_flag |= (UFTDI_FLAG_WRITE_STALL |
323	    UFTDI_FLAG_READ_STALL);
324
325	/* set a valid "lcr" value */
326
327	sc->sc_last_lcr =
328	    (FTDI_SIO_SET_DATA_STOP_BITS_2 |
329	    FTDI_SIO_SET_DATA_PARITY_NONE |
330	    FTDI_SIO_SET_DATA_BITS(8));
331
332	error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
333	    &uftdi_callback, &Giant);
334	if (error) {
335		goto detach;
336	}
337	return (0);			/* success */
338
339detach:
340	uftdi_detach(dev);
341	return (ENXIO);
342}
343
344static int
345uftdi_detach(device_t dev)
346{
347	struct uftdi_softc *sc = device_get_softc(dev);
348
349	usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
350
351	usb2_transfer_unsetup(sc->sc_xfer, UFTDI_ENDPT_MAX);
352
353	return (0);
354}
355
356static void
357uftdi_cfg_do_request(struct uftdi_softc *sc, struct usb2_device_request *req,
358    void *data)
359{
360	uint16_t length;
361	usb2_error_t err;
362
363	if (usb2_com_cfg_is_gone(&sc->sc_ucom)) {
364		goto error;
365	}
366	err = usb2_do_request_flags
367	    (sc->sc_udev, &Giant, req, data, 0, NULL, 1000);
368
369	if (err) {
370
371		DPRINTFN(0, "device request failed, err=%s "
372		    "(ignored)\n", usb2_errstr(err));
373
374error:
375		length = UGETW(req->wLength);
376
377		if ((req->bmRequestType & UT_READ) && length) {
378			bzero(data, length);
379		}
380	}
381}
382
383static void
384uftdi_cfg_open(struct usb2_com_softc *ucom)
385{
386	struct uftdi_softc *sc = ucom->sc_parent;
387	uint16_t wIndex = ucom->sc_portno;
388	struct usb2_device_request req;
389
390	DPRINTF("");
391
392	/* perform a full reset on the device */
393
394	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
395	req.bRequest = FTDI_SIO_RESET;
396	USETW(req.wValue, FTDI_SIO_RESET_SIO);
397	USETW(req.wIndex, wIndex);
398	USETW(req.wLength, 0);
399	uftdi_cfg_do_request(sc, &req, NULL);
400
401	/* turn on RTS/CTS flow control */
402
403	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
404	req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
405	USETW(req.wValue, 0);
406	USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, wIndex);
407	USETW(req.wLength, 0);
408	uftdi_cfg_do_request(sc, &req, NULL);
409
410	/*
411	 * NOTE: with the new UCOM layer there will always be a
412	 * "uftdi_cfg_param()" call after "open()", so there is no need for
413	 * "open()" to configure anything
414	 */
415}
416
417static void
418uftdi_write_callback(struct usb2_xfer *xfer)
419{
420	struct uftdi_softc *sc = xfer->priv_sc;
421	uint32_t actlen;
422	uint8_t buf[1];
423
424	switch (USB_GET_STATE(xfer)) {
425	case USB_ST_SETUP:
426	case USB_ST_TRANSFERRED:
427		if (sc->sc_flag & UFTDI_FLAG_WRITE_STALL) {
428			usb2_transfer_start(sc->sc_xfer[2]);
429			return;
430		}
431		if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers,
432		    sc->sc_hdrlen, UFTDI_OBUFSIZE - sc->sc_hdrlen,
433		    &actlen)) {
434
435			if (sc->sc_hdrlen > 0) {
436				buf[0] =
437				    FTDI_OUT_TAG(actlen, sc->sc_ucom.sc_portno);
438				usb2_copy_in(xfer->frbuffers, 0, buf, 1);
439			}
440			xfer->frlengths[0] = actlen + sc->sc_hdrlen;
441			usb2_start_hardware(xfer);
442		}
443		return;
444
445	default:			/* Error */
446		if (xfer->error != USB_ERR_CANCELLED) {
447			sc->sc_flag |= UFTDI_FLAG_WRITE_STALL;
448			usb2_transfer_start(sc->sc_xfer[2]);
449		}
450		return;
451
452	}
453}
454
455static void
456uftdi_write_clear_stall_callback(struct usb2_xfer *xfer)
457{
458	struct uftdi_softc *sc = xfer->priv_sc;
459	struct usb2_xfer *xfer_other = sc->sc_xfer[0];
460
461	if (usb2_clear_stall_callback(xfer, xfer_other)) {
462		DPRINTF("stall cleared\n");
463		sc->sc_flag &= ~UFTDI_FLAG_WRITE_STALL;
464		usb2_transfer_start(xfer_other);
465	}
466}
467
468static void
469uftdi_read_callback(struct usb2_xfer *xfer)
470{
471	struct uftdi_softc *sc = xfer->priv_sc;
472	uint8_t buf[2];
473	uint8_t ftdi_msr;
474	uint8_t msr;
475	uint8_t lsr;
476
477	switch (USB_GET_STATE(xfer)) {
478	case USB_ST_TRANSFERRED:
479
480		if (xfer->actlen < 2) {
481			goto tr_setup;
482		}
483		usb2_copy_out(xfer->frbuffers, 0, buf, 2);
484
485		ftdi_msr = FTDI_GET_MSR(buf);
486		lsr = FTDI_GET_LSR(buf);
487
488		msr = 0;
489		if (ftdi_msr & FTDI_SIO_CTS_MASK)
490			msr |= SER_CTS;
491		if (ftdi_msr & FTDI_SIO_DSR_MASK)
492			msr |= SER_DSR;
493		if (ftdi_msr & FTDI_SIO_RI_MASK)
494			msr |= SER_RI;
495		if (ftdi_msr & FTDI_SIO_RLSD_MASK)
496			msr |= SER_DCD;
497
498		if ((sc->sc_msr != msr) ||
499		    ((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) {
500			DPRINTF("status change msr=0x%02x (0x%02x) "
501			    "lsr=0x%02x (0x%02x)\n", msr, sc->sc_msr,
502			    lsr, sc->sc_lsr);
503
504			sc->sc_msr = msr;
505			sc->sc_lsr = lsr;
506
507			usb2_com_status_change(&sc->sc_ucom);
508		}
509		xfer->actlen -= 2;
510
511		if (xfer->actlen > 0) {
512			usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 2,
513			    xfer->actlen);
514		}
515	case USB_ST_SETUP:
516tr_setup:
517		if (sc->sc_flag & UFTDI_FLAG_READ_STALL) {
518			usb2_transfer_start(sc->sc_xfer[3]);
519		} else {
520			xfer->frlengths[0] = xfer->max_data_length;
521			usb2_start_hardware(xfer);
522		}
523		return;
524
525	default:			/* Error */
526		if (xfer->error != USB_ERR_CANCELLED) {
527			sc->sc_flag |= UFTDI_FLAG_READ_STALL;
528			usb2_transfer_start(sc->sc_xfer[3]);
529		}
530		return;
531
532	}
533}
534
535static void
536uftdi_read_clear_stall_callback(struct usb2_xfer *xfer)
537{
538	struct uftdi_softc *sc = xfer->priv_sc;
539	struct usb2_xfer *xfer_other = sc->sc_xfer[1];
540
541	if (usb2_clear_stall_callback(xfer, xfer_other)) {
542		DPRINTF("stall cleared\n");
543		sc->sc_flag &= ~UFTDI_FLAG_READ_STALL;
544		usb2_transfer_start(xfer_other);
545	}
546}
547
548static void
549uftdi_cfg_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
550{
551	struct uftdi_softc *sc = ucom->sc_parent;
552	uint16_t wIndex = ucom->sc_portno;
553	uint16_t wValue;
554	struct usb2_device_request req;
555
556	wValue = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW;
557
558	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
559	req.bRequest = FTDI_SIO_MODEM_CTRL;
560	USETW(req.wValue, wValue);
561	USETW(req.wIndex, wIndex);
562	USETW(req.wLength, 0);
563	uftdi_cfg_do_request(sc, &req, NULL);
564}
565
566static void
567uftdi_cfg_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
568{
569	struct uftdi_softc *sc = ucom->sc_parent;
570	uint16_t wIndex = ucom->sc_portno;
571	uint16_t wValue;
572	struct usb2_device_request req;
573
574	wValue = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
575
576	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
577	req.bRequest = FTDI_SIO_MODEM_CTRL;
578	USETW(req.wValue, wValue);
579	USETW(req.wIndex, wIndex);
580	USETW(req.wLength, 0);
581	uftdi_cfg_do_request(sc, &req, NULL);
582}
583
584static void
585uftdi_cfg_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
586{
587	struct uftdi_softc *sc = ucom->sc_parent;
588	uint16_t wIndex = ucom->sc_portno;
589	uint16_t wValue;
590	struct usb2_device_request req;
591
592	if (onoff) {
593		sc->sc_last_lcr |= FTDI_SIO_SET_BREAK;
594	} else {
595		sc->sc_last_lcr &= ~FTDI_SIO_SET_BREAK;
596	}
597
598	wValue = sc->sc_last_lcr;
599
600	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
601	req.bRequest = FTDI_SIO_SET_DATA;
602	USETW(req.wValue, wValue);
603	USETW(req.wIndex, wIndex);
604	USETW(req.wLength, 0);
605	uftdi_cfg_do_request(sc, &req, NULL);
606}
607
608static int
609uftdi_set_parm_soft(struct termios *t,
610    struct uftdi_param_config *cfg, uint8_t type)
611{
612	bzero(cfg, sizeof(*cfg));
613
614	switch (type) {
615	case UFTDI_TYPE_SIO:
616		switch (t->c_ospeed) {
617		case 300:
618			cfg->rate = ftdi_sio_b300;
619			break;
620		case 600:
621			cfg->rate = ftdi_sio_b600;
622			break;
623		case 1200:
624			cfg->rate = ftdi_sio_b1200;
625			break;
626		case 2400:
627			cfg->rate = ftdi_sio_b2400;
628			break;
629		case 4800:
630			cfg->rate = ftdi_sio_b4800;
631			break;
632		case 9600:
633			cfg->rate = ftdi_sio_b9600;
634			break;
635		case 19200:
636			cfg->rate = ftdi_sio_b19200;
637			break;
638		case 38400:
639			cfg->rate = ftdi_sio_b38400;
640			break;
641		case 57600:
642			cfg->rate = ftdi_sio_b57600;
643			break;
644		case 115200:
645			cfg->rate = ftdi_sio_b115200;
646			break;
647		default:
648			return (EINVAL);
649		}
650		break;
651
652	case UFTDI_TYPE_8U232AM:
653		if (uftdi_8u232am_getrate(t->c_ospeed, &cfg->rate)) {
654			return (EINVAL);
655		}
656		break;
657	}
658
659	if (t->c_cflag & CSTOPB)
660		cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_2;
661	else
662		cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_1;
663
664	if (t->c_cflag & PARENB) {
665		if (t->c_cflag & PARODD) {
666			cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_ODD;
667		} else {
668			cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_EVEN;
669		}
670	} else {
671		cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_NONE;
672	}
673
674	switch (t->c_cflag & CSIZE) {
675	case CS5:
676		cfg->lcr |= FTDI_SIO_SET_DATA_BITS(5);
677		break;
678
679	case CS6:
680		cfg->lcr |= FTDI_SIO_SET_DATA_BITS(6);
681		break;
682
683	case CS7:
684		cfg->lcr |= FTDI_SIO_SET_DATA_BITS(7);
685		break;
686
687	case CS8:
688		cfg->lcr |= FTDI_SIO_SET_DATA_BITS(8);
689		break;
690	}
691
692	if (t->c_cflag & CRTSCTS) {
693		cfg->v_flow = FTDI_SIO_RTS_CTS_HS;
694	} else if (t->c_iflag & (IXON | IXOFF)) {
695		cfg->v_flow = FTDI_SIO_XON_XOFF_HS;
696		cfg->v_start = t->c_cc[VSTART];
697		cfg->v_stop = t->c_cc[VSTOP];
698	} else {
699		cfg->v_flow = FTDI_SIO_DISABLE_FLOW_CTRL;
700	}
701
702	return (0);
703}
704
705static int
706uftdi_pre_param(struct usb2_com_softc *ucom, struct termios *t)
707{
708	struct uftdi_softc *sc = ucom->sc_parent;
709	struct uftdi_param_config cfg;
710
711	DPRINTF("\n");
712
713	return (uftdi_set_parm_soft(t, &cfg, sc->sc_type));
714}
715
716static void
717uftdi_cfg_param(struct usb2_com_softc *ucom, struct termios *t)
718{
719	struct uftdi_softc *sc = ucom->sc_parent;
720	uint16_t wIndex = ucom->sc_portno;
721	struct uftdi_param_config cfg;
722	struct usb2_device_request req;
723
724	if (uftdi_set_parm_soft(t, &cfg, sc->sc_type)) {
725		/* should not happen */
726		return;
727	}
728	sc->sc_last_lcr = cfg.lcr;
729
730	DPRINTF("\n");
731
732	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
733	req.bRequest = FTDI_SIO_SET_BAUD_RATE;
734	USETW(req.wValue, cfg.rate);
735	USETW(req.wIndex, wIndex);
736	USETW(req.wLength, 0);
737	uftdi_cfg_do_request(sc, &req, NULL);
738
739	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
740	req.bRequest = FTDI_SIO_SET_DATA;
741	USETW(req.wValue, cfg.lcr);
742	USETW(req.wIndex, wIndex);
743	USETW(req.wLength, 0);
744	uftdi_cfg_do_request(sc, &req, NULL);
745
746	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
747	req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
748	USETW2(req.wValue, cfg.v_stop, cfg.v_start);
749	USETW2(req.wIndex, cfg.v_flow, wIndex);
750	USETW(req.wLength, 0);
751	uftdi_cfg_do_request(sc, &req, NULL);
752}
753
754static void
755uftdi_cfg_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
756{
757	struct uftdi_softc *sc = ucom->sc_parent;
758
759	DPRINTF("msr=0x%02x lsr=0x%02x\n",
760	    sc->sc_msr, sc->sc_lsr);
761
762	*msr = sc->sc_msr;
763	*lsr = sc->sc_lsr;
764}
765
766static void
767uftdi_start_read(struct usb2_com_softc *ucom)
768{
769	struct uftdi_softc *sc = ucom->sc_parent;
770
771	usb2_transfer_start(sc->sc_xfer[1]);
772}
773
774static void
775uftdi_stop_read(struct usb2_com_softc *ucom)
776{
777	struct uftdi_softc *sc = ucom->sc_parent;
778
779	usb2_transfer_stop(sc->sc_xfer[3]);
780	usb2_transfer_stop(sc->sc_xfer[1]);
781}
782
783static void
784uftdi_start_write(struct usb2_com_softc *ucom)
785{
786	struct uftdi_softc *sc = ucom->sc_parent;
787
788	usb2_transfer_start(sc->sc_xfer[0]);
789}
790
791static void
792uftdi_stop_write(struct usb2_com_softc *ucom)
793{
794	struct uftdi_softc *sc = ucom->sc_parent;
795
796	usb2_transfer_stop(sc->sc_xfer[2]);
797	usb2_transfer_stop(sc->sc_xfer[0]);
798}
799
800/*------------------------------------------------------------------------*
801 *	uftdi_8u232am_getrate
802 *
803 * Return values:
804 *    0: Success
805 * Else: Failure
806 *------------------------------------------------------------------------*/
807static uint8_t
808uftdi_8u232am_getrate(uint32_t speed, uint16_t *rate)
809{
810	/* Table of the nearest even powers-of-2 for values 0..15. */
811	static const uint8_t roundoff[16] = {
812		0, 2, 2, 4, 4, 4, 8, 8,
813		8, 8, 8, 8, 16, 16, 16, 16,
814	};
815	uint32_t d;
816	uint32_t freq;
817	uint16_t result;
818
819	if ((speed < 178) || (speed > ((3000000 * 100) / 97)))
820		return (1);		/* prevent numerical overflow */
821
822	/* Special cases for 2M and 3M. */
823	if ((speed >= ((3000000 * 100) / 103)) &&
824	    (speed <= ((3000000 * 100) / 97))) {
825		result = 0;
826		goto done;
827	}
828	if ((speed >= ((2000000 * 100) / 103)) &&
829	    (speed <= ((2000000 * 100) / 97))) {
830		result = 1;
831		goto done;
832	}
833	d = (FTDI_8U232AM_FREQ << 4) / speed;
834	d = (d & ~15) + roundoff[d & 15];
835
836	if (d < FTDI_8U232AM_MIN_DIV)
837		d = FTDI_8U232AM_MIN_DIV;
838	else if (d > FTDI_8U232AM_MAX_DIV)
839		d = FTDI_8U232AM_MAX_DIV;
840
841	/*
842	 * Calculate the frequency needed for "d" to exactly divide down to
843	 * our target "speed", and check that the actual frequency is within
844	 * 3% of this.
845	 */
846	freq = (speed * d);
847	if ((freq < ((FTDI_8U232AM_FREQ * 1600ULL) / 103)) ||
848	    (freq > ((FTDI_8U232AM_FREQ * 1600ULL) / 97)))
849		return (1);
850
851	/*
852	 * Pack the divisor into the resultant value.  The lower 14-bits
853	 * hold the integral part, while the upper 2 bits encode the
854	 * fractional component: either 0, 0.5, 0.25, or 0.125.
855	 */
856	result = (d >> 4);
857	if (d & 8)
858		result |= 0x4000;
859	else if (d & 4)
860		result |= 0x8000;
861	else if (d & 2)
862		result |= 0xc000;
863
864done:
865	*rate = result;
866	return (0);
867}
868