uslcom.c revision 188746
160786Sps/*	$OpenBSD: uslcom.c,v 1.17 2007/11/24 10:52:12 jsg Exp $	*/
260786Sps
360786Sps#include <sys/cdefs.h>
460786Sps__FBSDID("$FreeBSD: head/sys/dev/usb2/serial/uslcom2.c 188746 2009-02-18 06:33:10Z thompsa $");
560786Sps
660786Sps/*
760786Sps * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
860786Sps *
960786Sps * Permission to use, copy, modify, and distribute this software for any
1060786Sps * purpose with or without fee is hereby granted, provided that the above
1160786Sps * copyright notice and this permission notice appear in all copies.
1260786Sps *
1360786Sps * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1460786Sps * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1560786Sps * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1660786Sps * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1760786Sps * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1860786Sps * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1960786Sps * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2060786Sps */
2160786Sps
2260786Sps#include "usbdevs.h"
2360786Sps#include <dev/usb2/include/usb2_standard.h>
2460786Sps#include <dev/usb2/include/usb2_mfunc.h>
2560786Sps#include <dev/usb2/include/usb2_error.h>
2660786Sps
2760786Sps#define	USB_DEBUG_VAR uslcom_debug
2860786Sps
2960786Sps#include <dev/usb2/core/usb2_core.h>
3060786Sps#include <dev/usb2/core/usb2_debug.h>
3160786Sps#include <dev/usb2/core/usb2_process.h>
3260786Sps#include <dev/usb2/core/usb2_request.h>
3360786Sps#include <dev/usb2/core/usb2_lookup.h>
3460786Sps#include <dev/usb2/core/usb2_util.h>
3560786Sps#include <dev/usb2/core/usb2_busdma.h>
3660786Sps
3760786Sps#include <dev/usb2/serial/usb2_serial.h>
3860786Sps
3960786Sps#if USB_DEBUG
4060786Spsstatic int uslcom_debug = 0;
4160786Sps
4260786SpsSYSCTL_NODE(_hw_usb2, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom");
4360786SpsSYSCTL_INT(_hw_usb2_uslcom, OID_AUTO, debug, CTLFLAG_RW,
4460786Sps    &uslcom_debug, 0, "Debug level");
4560786Sps#endif
4660786Sps
4760786Sps#define	USLCOM_BULK_BUF_SIZE		1024
4860786Sps#define	USLCOM_CONFIG_INDEX	0
4960786Sps#define	USLCOM_IFACE_INDEX	0
5060786Sps
5160786Sps#define	USLCOM_SET_DATA_BITS(x)	((x) << 8)
5260786Sps
5360786Sps#define	USLCOM_WRITE		0x41
5460786Sps#define	USLCOM_READ		0xc1
5560786Sps
5660786Sps#define	USLCOM_UART		0x00
5760786Sps#define	USLCOM_BAUD_RATE	0x01
5860786Sps#define	USLCOM_DATA		0x03
5960786Sps#define	USLCOM_BREAK		0x05
6060786Sps#define	USLCOM_CTRL		0x07
6160786Sps
6260786Sps#define	USLCOM_UART_DISABLE	0x00
6360786Sps#define	USLCOM_UART_ENABLE	0x01
6460786Sps
6560786Sps#define	USLCOM_CTRL_DTR_ON	0x0001
6660786Sps#define	USLCOM_CTRL_DTR_SET	0x0100
6760786Sps#define	USLCOM_CTRL_RTS_ON	0x0002
6860786Sps#define	USLCOM_CTRL_RTS_SET	0x0200
6960786Sps#define	USLCOM_CTRL_CTS		0x0010
7060786Sps#define	USLCOM_CTRL_DSR		0x0020
7160786Sps#define	USLCOM_CTRL_DCD		0x0080
7260786Sps
7360786Sps#define	USLCOM_BAUD_REF		0x384000
7460786Sps
7560786Sps#define	USLCOM_STOP_BITS_1	0x00
7660786Sps#define	USLCOM_STOP_BITS_2	0x02
7760786Sps
7860786Sps#define	USLCOM_PARITY_NONE	0x00
7960786Sps#define	USLCOM_PARITY_ODD	0x10
8060786Sps#define	USLCOM_PARITY_EVEN	0x20
8160786Sps
8260786Sps#define	USLCOM_PORT_NO		0xFFFF /* XXX think this should be 0 --hps */
8360786Sps
8460786Sps#define	USLCOM_BREAK_OFF	0x00
8560786Sps#define	USLCOM_BREAK_ON		0x01
8660786Sps
8760786Spsenum {
8860786Sps	USLCOM_BULK_DT_WR,
8960786Sps	USLCOM_BULK_DT_RD,
9060786Sps	USLCOM_N_TRANSFER,
9160786Sps};
9260786Sps
9360786Spsstruct uslcom_softc {
9460786Sps	struct usb2_com_super_softc sc_super_ucom;
9560786Sps	struct usb2_com_softc sc_ucom;
9660786Sps
9760786Sps	struct usb2_xfer *sc_xfer[USLCOM_N_TRANSFER];
9860786Sps	struct usb2_device *sc_udev;
9960786Sps
10060786Sps	uint8_t		 sc_msr;
10160786Sps	uint8_t		 sc_lsr;
10260786Sps};
10360786Sps
10460786Spsstatic device_probe_t uslcom_probe;
10560786Spsstatic device_attach_t uslcom_attach;
10660786Spsstatic device_detach_t uslcom_detach;
10760786Sps
10860786Spsstatic usb2_callback_t uslcom_write_callback;
10960786Spsstatic usb2_callback_t uslcom_read_callback;
11060786Sps
11160786Spsstatic void uslcom_open(struct usb2_com_softc *);
11260786Spsstatic void uslcom_close(struct usb2_com_softc *);
11360786Spsstatic void uslcom_set_dtr(struct usb2_com_softc *, uint8_t);
11460786Spsstatic void uslcom_set_rts(struct usb2_com_softc *, uint8_t);
11560786Spsstatic void uslcom_set_break(struct usb2_com_softc *, uint8_t);
11660786Spsstatic int uslcom_pre_param(struct usb2_com_softc *, struct termios *);
11760786Spsstatic void uslcom_param(struct usb2_com_softc *, struct termios *);
11860786Spsstatic void uslcom_get_status(struct usb2_com_softc *, uint8_t *, uint8_t *);
11960786Spsstatic void uslcom_start_read(struct usb2_com_softc *);
12060786Spsstatic void uslcom_stop_read(struct usb2_com_softc *);
12160786Spsstatic void uslcom_start_write(struct usb2_com_softc *);
12260786Spsstatic void uslcom_stop_write(struct usb2_com_softc *);
12360786Sps
12460786Spsstatic const struct usb2_config uslcom_config[USLCOM_N_TRANSFER] = {
12560786Sps
12660786Sps	[USLCOM_BULK_DT_WR] = {
12760786Sps		.type = UE_BULK,
12860786Sps		.endpoint = UE_ADDR_ANY,
12960786Sps		.direction = UE_DIR_OUT,
13060786Sps		.mh.bufsize = USLCOM_BULK_BUF_SIZE,
13160786Sps		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
13260786Sps		.mh.callback = &uslcom_write_callback,
13360786Sps	},
13460786Sps
13560786Sps	[USLCOM_BULK_DT_RD] = {
13660786Sps		.type = UE_BULK,
13760786Sps		.endpoint = UE_ADDR_ANY,
13860786Sps		.direction = UE_DIR_IN,
13960786Sps		.mh.bufsize = USLCOM_BULK_BUF_SIZE,
14060786Sps		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
14160786Sps		.mh.callback = &uslcom_read_callback,
14260786Sps	},
14360786Sps};
14460786Sps
14560786Spsstruct usb2_com_callback uslcom_callback = {
14660786Sps	.usb2_com_cfg_open = &uslcom_open,
14760786Sps	.usb2_com_cfg_close = &uslcom_close,
14860786Sps	.usb2_com_cfg_get_status = &uslcom_get_status,
14960786Sps	.usb2_com_cfg_set_dtr = &uslcom_set_dtr,
15060786Sps	.usb2_com_cfg_set_rts = &uslcom_set_rts,
15160786Sps	.usb2_com_cfg_set_break = &uslcom_set_break,
15260786Sps	.usb2_com_cfg_param = &uslcom_param,
15360786Sps	.usb2_com_pre_param = &uslcom_pre_param,
15460786Sps	.usb2_com_start_read = &uslcom_start_read,
15560786Sps	.usb2_com_stop_read = &uslcom_stop_read,
15660786Sps	.usb2_com_start_write = &uslcom_start_write,
15760786Sps	.usb2_com_stop_write = &uslcom_stop_write,
15860786Sps};
15960786Sps
16060786Spsstatic const struct usb2_device_id uslcom_devs[] = {
16160786Sps    { USB_VPI(USB_VENDOR_BALTECH,	USB_PRODUCT_BALTECH_CARDREADER, 0) },
16260786Sps    { USB_VPI(USB_VENDOR_DYNASTREAM,	USB_PRODUCT_DYNASTREAM_ANTDEVBOARD, 0) },
16360786Sps    { USB_VPI(USB_VENDOR_JABLOTRON,	USB_PRODUCT_JABLOTRON_PC60B, 0) },
16460786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_ARGUSISP, 0) },
16560786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_CRUMB128, 0) },
16660786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_DEGREE, 0) },
16760786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_BURNSIDE, 0) },
16860786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_HELICOM, 0) },
16960786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_LIPOWSKY_HARP, 0) },
17060786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_LIPOWSKY_JTAG, 0) },
17160786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_LIPOWSKY_LIN, 0) },
17260786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_POLOLU, 0) },
17360786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_CP2102, 0) },
17460786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_CP210X_2, 0) },
17560786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_SUUNTO, 0) },
17660786Sps    { USB_VPI(USB_VENDOR_SILABS,	USB_PRODUCT_SILABS_TRAQMATE, 0) },
17760786Sps    { USB_VPI(USB_VENDOR_SILABS2,	USB_PRODUCT_SILABS2_DCU11CLONE, 0) },
17860786Sps    { USB_VPI(USB_VENDOR_USI,		USB_PRODUCT_USI_MC60, 0) },
17960786Sps};
18060786Sps
18160786Spsstatic device_method_t uslcom_methods[] = {
18260786Sps	DEVMETHOD(device_probe, uslcom_probe),
18360786Sps	DEVMETHOD(device_attach, uslcom_attach),
18460786Sps	DEVMETHOD(device_detach, uslcom_detach),
18560786Sps	{0, 0}
18660786Sps};
18760786Sps
18860786Spsstatic devclass_t uslcom_devclass;
18960786Sps
19060786Spsstatic driver_t uslcom_driver = {
19160786Sps	.name = "uslcom",
19260786Sps	.methods = uslcom_methods,
19360786Sps	.size = sizeof(struct uslcom_softc),
19460786Sps};
19560786Sps
19660786SpsDRIVER_MODULE(uslcom, ushub, uslcom_driver, uslcom_devclass, NULL, 0);
19760786SpsMODULE_DEPEND(uslcom, usb2_serial, 1, 1, 1);
19860786SpsMODULE_DEPEND(uslcom, usb2_core, 1, 1, 1);
19960786SpsMODULE_VERSION(uslcom, 1);
20060786Sps
20160786Spsstatic int
20260786Spsuslcom_probe(device_t dev)
20360786Sps{
20460786Sps	struct usb2_attach_arg *uaa = device_get_ivars(dev);
20560786Sps
20660786Sps	DPRINTFN(11, "\n");
20760786Sps
20860786Sps	if (uaa->usb2_mode != USB_MODE_HOST) {
20960786Sps		return (ENXIO);
21060786Sps	}
21160786Sps	if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) {
21260786Sps		return (ENXIO);
21360786Sps	}
21460786Sps	if (uaa->info.bIfaceIndex != USLCOM_IFACE_INDEX) {
21560786Sps		return (ENXIO);
21660786Sps	}
21760786Sps	return (usb2_lookup_id_by_uaa(uslcom_devs, sizeof(uslcom_devs), uaa));
21860786Sps}
21960786Sps
22060786Spsstatic int
22160786Spsuslcom_attach(device_t dev)
22260786Sps{
22360786Sps	struct usb2_attach_arg *uaa = device_get_ivars(dev);
22460786Sps	struct uslcom_softc *sc = device_get_softc(dev);
22560786Sps	int error;
22660786Sps
22760786Sps	DPRINTFN(11, "\n");
22860786Sps
22960786Sps	device_set_usb2_desc(dev);
23060786Sps
23160786Sps	sc->sc_udev = uaa->device;
23260786Sps
23360786Sps	error = usb2_transfer_setup(uaa->device,
23460786Sps	    &uaa->info.bIfaceIndex, sc->sc_xfer, uslcom_config,
23560786Sps	    USLCOM_N_TRANSFER, sc, &Giant);
23660786Sps	if (error) {
23760786Sps		DPRINTF("one or more missing USB endpoints, "
23860786Sps		    "error=%s\n", usb2_errstr(error));
23960786Sps		goto detach;
24060786Sps	}
24160786Sps	/* clear stall at first run */
24260786Sps	usb2_transfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_WR]);
24360786Sps	usb2_transfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]);
24460786Sps
24560786Sps	error = usb2_com_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
24660786Sps	    &uslcom_callback, &Giant);
24760786Sps	if (error) {
24860786Sps		goto detach;
24960786Sps	}
25060786Sps	return (0);
25160786Sps
25260786Spsdetach:
25360786Sps	uslcom_detach(dev);
25460786Sps	return (ENXIO);
25560786Sps}
25660786Sps
25760786Spsstatic int
25860786Spsuslcom_detach(device_t dev)
25960786Sps{
26060786Sps	struct uslcom_softc *sc = device_get_softc(dev);
26160786Sps
26260786Sps	DPRINTF("sc=%p\n", sc);
26360786Sps
26460786Sps	usb2_com_detach(&sc->sc_super_ucom, &sc->sc_ucom, 1);
26560786Sps
26660786Sps	usb2_transfer_unsetup(sc->sc_xfer, USLCOM_N_TRANSFER);
26760786Sps
26860786Sps	return (0);
26960786Sps}
27060786Sps
27160786Spsstatic void
27260786Spsuslcom_open(struct usb2_com_softc *ucom)
27360786Sps{
27460786Sps	struct uslcom_softc *sc = ucom->sc_parent;
27560786Sps	struct usb2_device_request req;
27660786Sps
27760786Sps	req.bmRequestType = USLCOM_WRITE;
27860786Sps	req.bRequest = USLCOM_UART;
27960786Sps	USETW(req.wValue, USLCOM_UART_ENABLE);
28060786Sps	USETW(req.wIndex, USLCOM_PORT_NO);
28160786Sps	USETW(req.wLength, 0);
28260786Sps
28360786Sps        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
28460786Sps	    &req, NULL, 0, 1000)) {
28560786Sps		DPRINTF("UART enable failed (ignored)\n");
28660786Sps	}
28760786Sps}
28860786Sps
28960786Spsstatic void
29060786Spsuslcom_close(struct usb2_com_softc *ucom)
29160786Sps{
29260786Sps	struct uslcom_softc *sc = ucom->sc_parent;
29360786Sps	struct usb2_device_request req;
29460786Sps
29560786Sps	req.bmRequestType = USLCOM_WRITE;
29660786Sps	req.bRequest = USLCOM_UART;
29760786Sps	USETW(req.wValue, USLCOM_UART_DISABLE);
29860786Sps	USETW(req.wIndex, USLCOM_PORT_NO);
29960786Sps	USETW(req.wLength, 0);
30060786Sps
30160786Sps        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
30260786Sps	    &req, NULL, 0, 1000)) {
30360786Sps		DPRINTF("UART disable failed (ignored)\n");
30460786Sps	}
30560786Sps}
30660786Sps
30760786Spsstatic void
30860786Spsuslcom_set_dtr(struct usb2_com_softc *ucom, uint8_t onoff)
30960786Sps{
31060786Sps        struct uslcom_softc *sc = ucom->sc_parent;
31160786Sps	struct usb2_device_request req;
31260786Sps	uint16_t ctl;
31360786Sps
31460786Sps        DPRINTF("onoff = %d\n", onoff);
31560786Sps
31660786Sps	ctl = onoff ? USLCOM_CTRL_DTR_ON : 0;
31760786Sps	ctl |= USLCOM_CTRL_DTR_SET;
31860786Sps
31960786Sps	req.bmRequestType = USLCOM_WRITE;
32060786Sps	req.bRequest = USLCOM_CTRL;
32160786Sps	USETW(req.wValue, ctl);
32260786Sps	USETW(req.wIndex, USLCOM_PORT_NO);
32360786Sps	USETW(req.wLength, 0);
32460786Sps
32560786Sps        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
32660786Sps	    &req, NULL, 0, 1000)) {
32760786Sps		DPRINTF("Setting DTR failed (ignored)\n");
32860786Sps	}
32960786Sps}
33060786Sps
33160786Spsstatic void
33260786Spsuslcom_set_rts(struct usb2_com_softc *ucom, uint8_t onoff)
33360786Sps{
33460786Sps        struct uslcom_softc *sc = ucom->sc_parent;
33560786Sps	struct usb2_device_request req;
33660786Sps	uint16_t ctl;
33760786Sps
33860786Sps        DPRINTF("onoff = %d\n", onoff);
33960786Sps
34060786Sps	ctl = onoff ? USLCOM_CTRL_RTS_ON : 0;
34160786Sps	ctl |= USLCOM_CTRL_RTS_SET;
34260786Sps
34360786Sps	req.bmRequestType = USLCOM_WRITE;
34460786Sps	req.bRequest = USLCOM_CTRL;
34560786Sps	USETW(req.wValue, ctl);
34660786Sps	USETW(req.wIndex, USLCOM_PORT_NO);
34760786Sps	USETW(req.wLength, 0);
34860786Sps
34960786Sps        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
35060786Sps	    &req, NULL, 0, 1000)) {
35160786Sps		DPRINTF("Setting DTR failed (ignored)\n");
35260786Sps	}
35360786Sps}
35460786Sps
35560786Spsstatic int
35660786Spsuslcom_pre_param(struct usb2_com_softc *ucom, struct termios *t)
35760786Sps{
35860786Sps	if (t->c_ospeed <= 0 || t->c_ospeed > 921600)
35960786Sps		return (EINVAL);
36060786Sps	return (0);
36160786Sps}
36260786Sps
36360786Spsstatic void
36460786Spsuslcom_param(struct usb2_com_softc *ucom, struct termios *t)
36560786Sps{
36660786Sps	struct uslcom_softc *sc = ucom->sc_parent;
36760786Sps	struct usb2_device_request req;
36860786Sps	uint16_t data;
36960786Sps
37060786Sps	DPRINTF("\n");
37160786Sps
37260786Sps	req.bmRequestType = USLCOM_WRITE;
37360786Sps	req.bRequest = USLCOM_BAUD_RATE;
37460786Sps	USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed);
37560786Sps	USETW(req.wIndex, USLCOM_PORT_NO);
37660786Sps	USETW(req.wLength, 0);
37760786Sps
37860786Sps        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
37960786Sps	    &req, NULL, 0, 1000)) {
38060786Sps		DPRINTF("Set baudrate failed (ignored)\n");
38160786Sps	}
38260786Sps
38360786Sps	if (t->c_cflag & CSTOPB)
38460786Sps		data = USLCOM_STOP_BITS_2;
38560786Sps	else
38660786Sps		data = USLCOM_STOP_BITS_1;
38760786Sps	if (t->c_cflag & PARENB) {
38860786Sps		if (t->c_cflag & PARODD)
38960786Sps			data |= USLCOM_PARITY_ODD;
39060786Sps		else
39160786Sps			data |= USLCOM_PARITY_EVEN;
39260786Sps	} else
39360786Sps		data |= USLCOM_PARITY_NONE;
39460786Sps	switch (t->c_cflag & CSIZE) {
39560786Sps	case CS5:
39660786Sps		data |= USLCOM_SET_DATA_BITS(5);
39760786Sps		break;
39860786Sps	case CS6:
39960786Sps		data |= USLCOM_SET_DATA_BITS(6);
40060786Sps		break;
40160786Sps	case CS7:
40260786Sps		data |= USLCOM_SET_DATA_BITS(7);
40360786Sps		break;
40460786Sps	case CS8:
40560786Sps		data |= USLCOM_SET_DATA_BITS(8);
40660786Sps		break;
40760786Sps	}
40860786Sps
40960786Sps	req.bmRequestType = USLCOM_WRITE;
41060786Sps	req.bRequest = USLCOM_DATA;
41160786Sps	USETW(req.wValue, data);
41260786Sps	USETW(req.wIndex, USLCOM_PORT_NO);
41360786Sps	USETW(req.wLength, 0);
41460786Sps
41560786Sps        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
41660786Sps	    &req, NULL, 0, 1000)) {
41760786Sps		DPRINTF("Set format failed (ignored)\n");
41860786Sps	}
41960786Sps	return;
42060786Sps}
42160786Sps
42260786Spsstatic void
42360786Spsuslcom_get_status(struct usb2_com_softc *ucom, uint8_t *lsr, uint8_t *msr)
42460786Sps{
42560786Sps	struct uslcom_softc *sc = ucom->sc_parent;
42660786Sps
42760786Sps	DPRINTF("\n");
42860786Sps
42960786Sps	*lsr = sc->sc_lsr;
43060786Sps	*msr = sc->sc_msr;
43160786Sps}
43260786Sps
43360786Spsstatic void
43460786Spsuslcom_set_break(struct usb2_com_softc *ucom, uint8_t onoff)
43560786Sps{
43660786Sps        struct uslcom_softc *sc = ucom->sc_parent;
43760786Sps	struct usb2_device_request req;
43860786Sps	uint16_t brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF;
43960786Sps
44060786Sps	req.bmRequestType = USLCOM_WRITE;
44160786Sps	req.bRequest = USLCOM_BREAK;
44260786Sps	USETW(req.wValue, brk);
44360786Sps	USETW(req.wIndex, USLCOM_PORT_NO);
44460786Sps	USETW(req.wLength, 0);
44560786Sps
44660786Sps        if (usb2_com_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
44760786Sps	    &req, NULL, 0, 1000)) {
44860786Sps		DPRINTF("Set BREAK failed (ignored)\n");
44960786Sps	}
45060786Sps}
45160786Sps
45260786Spsstatic void
45360786Spsuslcom_write_callback(struct usb2_xfer *xfer)
45460786Sps{
45560786Sps	struct uslcom_softc *sc = xfer->priv_sc;
45660786Sps	uint32_t actlen;
45760786Sps
45860786Sps	switch (USB_GET_STATE(xfer)) {
45960786Sps	case USB_ST_SETUP:
46060786Sps	case USB_ST_TRANSFERRED:
46160786Spstr_setup:
46260786Sps		if (usb2_com_get_data(&sc->sc_ucom, xfer->frbuffers, 0,
46360786Sps		    USLCOM_BULK_BUF_SIZE, &actlen)) {
46460786Sps
46560786Sps			DPRINTF("actlen = %d\n", actlen);
46660786Sps
46760786Sps			xfer->frlengths[0] = actlen;
46860786Sps			usb2_start_hardware(xfer);
46960786Sps		}
47060786Sps		return;
47160786Sps
47260786Sps	default:			/* Error */
47360786Sps		if (xfer->error != USB_ERR_CANCELLED) {
47460786Sps			/* try to clear stall first */
47560786Sps			xfer->flags.stall_pipe = 1;
47660786Sps			goto tr_setup;
47760786Sps		}
47860786Sps		return;
47960786Sps	}
48060786Sps}
48160786Sps
48260786Spsstatic void
48360786Spsuslcom_read_callback(struct usb2_xfer *xfer)
48460786Sps{
48560786Sps	struct uslcom_softc *sc = xfer->priv_sc;
48660786Sps
48760786Sps	switch (USB_GET_STATE(xfer)) {
48860786Sps	case USB_ST_TRANSFERRED:
48960786Sps		usb2_com_put_data(&sc->sc_ucom, xfer->frbuffers, 0, xfer->actlen);
49060786Sps
49160786Sps	case USB_ST_SETUP:
49260786Spstr_setup:
49360786Sps		xfer->frlengths[0] = xfer->max_data_length;
49460786Sps		usb2_start_hardware(xfer);
49560786Sps		return;
49660786Sps
49760786Sps	default:			/* Error */
49860786Sps		if (xfer->error != USB_ERR_CANCELLED) {
49960786Sps			/* try to clear stall first */
50060786Sps			xfer->flags.stall_pipe = 1;
50160786Sps			goto tr_setup;
50260786Sps		}
50360786Sps		return;
50460786Sps	}
50560786Sps}
50660786Sps
50760786Spsstatic void
50860786Spsuslcom_start_read(struct usb2_com_softc *ucom)
50960786Sps{
51060786Sps	struct uslcom_softc *sc = ucom->sc_parent;
51160786Sps
51260786Sps	/* start read endpoint */
51360786Sps	usb2_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_RD]);
51460786Sps}
51560786Sps
51660786Spsstatic void
51760786Spsuslcom_stop_read(struct usb2_com_softc *ucom)
51860786Sps{
51960786Sps	struct uslcom_softc *sc = ucom->sc_parent;
52060786Sps
52160786Sps	/* stop read endpoint */
52260786Sps	usb2_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_RD]);
52360786Sps}
52460786Sps
52560786Spsstatic void
52660786Spsuslcom_start_write(struct usb2_com_softc *ucom)
52760786Sps{
52860786Sps	struct uslcom_softc *sc = ucom->sc_parent;
52960786Sps
53060786Sps	usb2_transfer_start(sc->sc_xfer[USLCOM_BULK_DT_WR]);
53160786Sps}
53260786Sps
53360786Spsstatic void
53460786Spsuslcom_stop_write(struct usb2_com_softc *ucom)
53560786Sps{
53660786Sps	struct uslcom_softc *sc = ucom->sc_parent;
53760786Sps
53860786Sps	usb2_transfer_stop(sc->sc_xfer[USLCOM_BULK_DT_WR]);
53960786Sps}
54060786Sps