uftdi.c (9f7fef595d2cfa38db0e2608d63e3b6b08f38baf) uftdi.c (a9d84a2ba7b4f96cea914b6142e93ae71373dcb7)
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).

--- 24 unchanged lines hidden (view full) ---

33__FBSDID("$FreeBSD$");
34
35/*
36 * NOTE: all function names beginning like "uftdi_cfg_" can only
37 * be called from within the config thread function !
38 */
39
40/*
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).

--- 24 unchanged lines hidden (view full) ---

33__FBSDID("$FreeBSD$");
34
35/*
36 * NOTE: all function names beginning like "uftdi_cfg_" can only
37 * be called from within the config thread function !
38 */
39
40/*
41 * FTDI FT2232x, FT8U100AX and FT8U232AM serial adapter driver
41 * FTDI FT232x, FT2232x, FT4232x, FT8U100AX and FT8U232xM serial adapters.
42 *
43 * Note that we specifically do not do a reset or otherwise alter the state of
44 * the chip during attach, detach, open, and close, because it could be
45 * pre-initialized (via an attached serial eeprom) to power-on into a mode such
46 * as bitbang in which the pins are being driven to a specific state which we
47 * must not perturb. The device gets reset at power-on, and doesn't need to be
48 * reset again after that to function, except as directed by ioctl() calls.
42 */
43
44#include <sys/stdint.h>
45#include <sys/stddef.h>
46#include <sys/param.h>
47#include <sys/queue.h>
48#include <sys/types.h>
49#include <sys/systm.h>

--- 9 unchanged lines hidden (view full) ---

59#include <sys/callout.h>
60#include <sys/malloc.h>
61#include <sys/priv.h>
62
63#include <dev/usb/usb.h>
64#include <dev/usb/usbdi.h>
65#include <dev/usb/usbdi_util.h>
66#include <dev/usb/usb_core.h>
49 */
50
51#include <sys/stdint.h>
52#include <sys/stddef.h>
53#include <sys/param.h>
54#include <sys/queue.h>
55#include <sys/types.h>
56#include <sys/systm.h>

--- 9 unchanged lines hidden (view full) ---

66#include <sys/callout.h>
67#include <sys/malloc.h>
68#include <sys/priv.h>
69
70#include <dev/usb/usb.h>
71#include <dev/usb/usbdi.h>
72#include <dev/usb/usbdi_util.h>
73#include <dev/usb/usb_core.h>
74#include <dev/usb/usb_ioctl.h>
67#include "usbdevs.h"
68
69#define USB_DEBUG_VAR uftdi_debug
70#include <dev/usb/usb_debug.h>
71#include <dev/usb/usb_process.h>
72
73#include <dev/usb/serial/usb_serial.h>
74#include <dev/usb/serial/uftdi_reg.h>
75#include "usbdevs.h"
76
77#define USB_DEBUG_VAR uftdi_debug
78#include <dev/usb/usb_debug.h>
79#include <dev/usb/usb_process.h>
80
81#include <dev/usb/serial/usb_serial.h>
82#include <dev/usb/serial/uftdi_reg.h>
83#include <dev/usb/uftdiio.h>
75
76#ifdef USB_DEBUG
77static int uftdi_debug = 0;
78
79static SYSCTL_NODE(_hw_usb, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi");
80SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, debug, CTLFLAG_RW,
81 &uftdi_debug, 0, "Debug level");
82#endif

--- 58 unchanged lines hidden (view full) ---

141 struct usb_device *sc_udev;
142 struct usb_xfer *sc_xfer[UFTDI_N_TRANSFER];
143 device_t sc_dev;
144 struct mtx sc_mtx;
145
146 uint32_t sc_unit;
147
148 uint16_t sc_last_lcr;
84
85#ifdef USB_DEBUG
86static int uftdi_debug = 0;
87
88static SYSCTL_NODE(_hw_usb, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi");
89SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, debug, CTLFLAG_RW,
90 &uftdi_debug, 0, "Debug level");
91#endif

--- 58 unchanged lines hidden (view full) ---

150 struct usb_device *sc_udev;
151 struct usb_xfer *sc_xfer[UFTDI_N_TRANSFER];
152 device_t sc_dev;
153 struct mtx sc_mtx;
154
155 uint32_t sc_unit;
156
157 uint16_t sc_last_lcr;
158 uint16_t sc_bcdDevice;
149
150 uint8_t sc_devtype;
151 uint8_t sc_devflags;
152 uint8_t sc_hdrlen;
153 uint8_t sc_msr;
154 uint8_t sc_lsr;
155};
156

--- 13 unchanged lines hidden (view full) ---

170static device_detach_t uftdi_detach;
171static void uftdi_free_softc(struct uftdi_softc *);
172
173static usb_callback_t uftdi_write_callback;
174static usb_callback_t uftdi_read_callback;
175
176static void uftdi_free(struct ucom_softc *);
177static void uftdi_cfg_open(struct ucom_softc *);
159
160 uint8_t sc_devtype;
161 uint8_t sc_devflags;
162 uint8_t sc_hdrlen;
163 uint8_t sc_msr;
164 uint8_t sc_lsr;
165};
166

--- 13 unchanged lines hidden (view full) ---

180static device_detach_t uftdi_detach;
181static void uftdi_free_softc(struct uftdi_softc *);
182
183static usb_callback_t uftdi_write_callback;
184static usb_callback_t uftdi_read_callback;
185
186static void uftdi_free(struct ucom_softc *);
187static void uftdi_cfg_open(struct ucom_softc *);
188static void uftdi_cfg_close(struct ucom_softc *);
178static void uftdi_cfg_set_dtr(struct ucom_softc *, uint8_t);
179static void uftdi_cfg_set_rts(struct ucom_softc *, uint8_t);
180static void uftdi_cfg_set_break(struct ucom_softc *, uint8_t);
181static int uftdi_set_parm_soft(struct ucom_softc *, struct termios *,
182 struct uftdi_param_config *);
183static int uftdi_pre_param(struct ucom_softc *, struct termios *);
184static void uftdi_cfg_param(struct ucom_softc *, struct termios *);
185static void uftdi_cfg_get_status(struct ucom_softc *, uint8_t *,
186 uint8_t *);
189static void uftdi_cfg_set_dtr(struct ucom_softc *, uint8_t);
190static void uftdi_cfg_set_rts(struct ucom_softc *, uint8_t);
191static void uftdi_cfg_set_break(struct ucom_softc *, uint8_t);
192static int uftdi_set_parm_soft(struct ucom_softc *, struct termios *,
193 struct uftdi_param_config *);
194static int uftdi_pre_param(struct ucom_softc *, struct termios *);
195static void uftdi_cfg_param(struct ucom_softc *, struct termios *);
196static void uftdi_cfg_get_status(struct ucom_softc *, uint8_t *,
197 uint8_t *);
198static int uftdi_reset(struct ucom_softc *, int);
199static int uftdi_set_bitmode(struct ucom_softc *, uint8_t, uint8_t);
200static int uftdi_get_bitmode(struct ucom_softc *, uint8_t *);
201static int uftdi_set_latency(struct ucom_softc *, int);
202static int uftdi_get_latency(struct ucom_softc *, int *);
203static int uftdi_set_event_char(struct ucom_softc *, int);
204static int uftdi_set_error_char(struct ucom_softc *, int);
205static int uftdi_ioctl(struct ucom_softc *, uint32_t, caddr_t, int,
206 struct thread *);
187static void uftdi_start_read(struct ucom_softc *);
188static void uftdi_stop_read(struct ucom_softc *);
189static void uftdi_start_write(struct ucom_softc *);
190static void uftdi_stop_write(struct ucom_softc *);
191static void uftdi_poll(struct ucom_softc *ucom);
192
193static const struct usb_config uftdi_config[UFTDI_N_TRANSFER] = {
194

--- 18 unchanged lines hidden (view full) ---

213
214static const struct ucom_callback uftdi_callback = {
215 .ucom_cfg_get_status = &uftdi_cfg_get_status,
216 .ucom_cfg_set_dtr = &uftdi_cfg_set_dtr,
217 .ucom_cfg_set_rts = &uftdi_cfg_set_rts,
218 .ucom_cfg_set_break = &uftdi_cfg_set_break,
219 .ucom_cfg_param = &uftdi_cfg_param,
220 .ucom_cfg_open = &uftdi_cfg_open,
207static void uftdi_start_read(struct ucom_softc *);
208static void uftdi_stop_read(struct ucom_softc *);
209static void uftdi_start_write(struct ucom_softc *);
210static void uftdi_stop_write(struct ucom_softc *);
211static void uftdi_poll(struct ucom_softc *ucom);
212
213static const struct usb_config uftdi_config[UFTDI_N_TRANSFER] = {
214

--- 18 unchanged lines hidden (view full) ---

233
234static const struct ucom_callback uftdi_callback = {
235 .ucom_cfg_get_status = &uftdi_cfg_get_status,
236 .ucom_cfg_set_dtr = &uftdi_cfg_set_dtr,
237 .ucom_cfg_set_rts = &uftdi_cfg_set_rts,
238 .ucom_cfg_set_break = &uftdi_cfg_set_break,
239 .ucom_cfg_param = &uftdi_cfg_param,
240 .ucom_cfg_open = &uftdi_cfg_open,
241 .ucom_cfg_close = &uftdi_cfg_close,
221 .ucom_pre_param = &uftdi_pre_param,
242 .ucom_pre_param = &uftdi_pre_param,
243 .ucom_ioctl = &uftdi_ioctl,
222 .ucom_start_read = &uftdi_start_read,
223 .ucom_stop_read = &uftdi_stop_read,
224 .ucom_start_write = &uftdi_start_write,
225 .ucom_stop_write = &uftdi_stop_write,
226 .ucom_poll = &uftdi_poll,
227 .ucom_free = &uftdi_free,
228};
229

--- 670 unchanged lines hidden (view full) ---

900 * Due to a hardware bug, a 232B chip without an eeprom reports itself as a
901 * 232A, but if the serial number is also zero we know it's really a 232B.
902 */
903static void
904uftdi_devtype_setup(struct uftdi_softc *sc, struct usb_attach_arg *uaa)
905{
906 struct usb_device_descriptor *dd;
907
244 .ucom_start_read = &uftdi_start_read,
245 .ucom_stop_read = &uftdi_stop_read,
246 .ucom_start_write = &uftdi_start_write,
247 .ucom_stop_write = &uftdi_stop_write,
248 .ucom_poll = &uftdi_poll,
249 .ucom_free = &uftdi_free,
250};
251

--- 670 unchanged lines hidden (view full) ---

922 * Due to a hardware bug, a 232B chip without an eeprom reports itself as a
923 * 232A, but if the serial number is also zero we know it's really a 232B.
924 */
925static void
926uftdi_devtype_setup(struct uftdi_softc *sc, struct usb_attach_arg *uaa)
927{
928 struct usb_device_descriptor *dd;
929
930 sc->sc_bcdDevice = uaa->info.bcdDevice;
931
908 switch (uaa->info.bcdDevice) {
909 case 0x200:
910 dd = usbd_get_device_descriptor(sc->sc_udev);
911 if (dd->iSerialNumber == 0) {
912 sc->sc_devtype = DEVT_232B;
913 } else {
914 sc->sc_devtype = DEVT_232A;
915 }

--- 165 unchanged lines hidden (view full) ---

1081uftdi_free(struct ucom_softc *ucom)
1082{
1083 uftdi_free_softc(ucom->sc_parent);
1084}
1085
1086static void
1087uftdi_cfg_open(struct ucom_softc *ucom)
1088{
932 switch (uaa->info.bcdDevice) {
933 case 0x200:
934 dd = usbd_get_device_descriptor(sc->sc_udev);
935 if (dd->iSerialNumber == 0) {
936 sc->sc_devtype = DEVT_232B;
937 } else {
938 sc->sc_devtype = DEVT_232A;
939 }

--- 165 unchanged lines hidden (view full) ---

1105uftdi_free(struct ucom_softc *ucom)
1106{
1107 uftdi_free_softc(ucom->sc_parent);
1108}
1109
1110static void
1111uftdi_cfg_open(struct ucom_softc *ucom)
1112{
1089 struct uftdi_softc *sc = ucom->sc_parent;
1090 uint16_t wIndex = ucom->sc_portno;
1091 struct usb_device_request req;
1092
1113
1114 /*
1115 * This do-nothing open routine exists for the sole purpose of this
1116 * DPRINTF() so that you can see the point at which open gets called
1117 * when debugging is enabled.
1118 */
1093 DPRINTF("");
1119 DPRINTF("");
1120}
1094
1121
1095 /* perform a full reset on the device */
1122static void
1123uftdi_cfg_close(struct ucom_softc *ucom)
1124{
1096
1125
1097 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1098 req.bRequest = FTDI_SIO_RESET;
1099 USETW(req.wValue, FTDI_SIO_RESET_SIO);
1100 USETW(req.wIndex, wIndex);
1101 USETW(req.wLength, 0);
1102 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
1103 &req, NULL, 0, 1000);
1104
1105 /* turn on RTS/CTS flow control */
1106
1107 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1108 req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
1109 USETW(req.wValue, 0);
1110 USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, wIndex);
1111 USETW(req.wLength, 0);
1112 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
1113 &req, NULL, 0, 1000);
1114
1115 /*
1126 /*
1116 * NOTE: with the new UCOM layer there will always be a
1117 * "uftdi_cfg_param()" call after "open()", so there is no need for
1118 * "open()" to configure anything
1127 * This do-nothing close routine exists for the sole purpose of this
1128 * DPRINTF() so that you can see the point at which close gets called
1129 * when debugging is enabled.
1119 */
1130 */
1131 DPRINTF("");
1120}
1121
1122static void
1123uftdi_write_callback(struct usb_xfer *xfer, usb_error_t error)
1124{
1125 struct uftdi_softc *sc = usbd_xfer_softc(xfer);
1126 struct usb_page_cache *pc;
1127 uint32_t pktlen;

--- 450 unchanged lines hidden (view full) ---

1578
1579 DPRINTF("msr=0x%02x lsr=0x%02x\n",
1580 sc->sc_msr, sc->sc_lsr);
1581
1582 *msr = sc->sc_msr;
1583 *lsr = sc->sc_lsr;
1584}
1585
1132}
1133
1134static void
1135uftdi_write_callback(struct usb_xfer *xfer, usb_error_t error)
1136{
1137 struct uftdi_softc *sc = usbd_xfer_softc(xfer);
1138 struct usb_page_cache *pc;
1139 uint32_t pktlen;

--- 450 unchanged lines hidden (view full) ---

1590
1591 DPRINTF("msr=0x%02x lsr=0x%02x\n",
1592 sc->sc_msr, sc->sc_lsr);
1593
1594 *msr = sc->sc_msr;
1595 *lsr = sc->sc_lsr;
1596}
1597
1598static int
1599uftdi_reset(struct ucom_softc *ucom, int reset_type)
1600{
1601 struct uftdi_softc *sc = ucom->sc_parent;
1602 usb_device_request_t req;
1603
1604 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1605 req.bRequest = FTDI_SIO_RESET;
1606
1607 USETW(req.wIndex, sc->sc_ucom.sc_portno);
1608 USETW(req.wLength, 0);
1609 USETW(req.wValue, reset_type);
1610
1611 return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1612}
1613
1614static int
1615uftdi_set_bitmode(struct ucom_softc *ucom, uint8_t bitmode, uint8_t iomask)
1616{
1617 struct uftdi_softc *sc = ucom->sc_parent;
1618 usb_device_request_t req;
1619
1620 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1621 req.bRequest = FTDI_SIO_SET_BITMODE;
1622
1623 USETW(req.wIndex, sc->sc_ucom.sc_portno);
1624 USETW(req.wLength, 0);
1625
1626 if (bitmode == UFTDI_BITMODE_NONE)
1627 USETW2(req.wValue, 0, 0);
1628 else
1629 USETW2(req.wValue, (1 << bitmode), iomask);
1630
1631 return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1632}
1633
1634static int
1635uftdi_get_bitmode(struct ucom_softc *ucom, uint8_t *iomask)
1636{
1637 struct uftdi_softc *sc = ucom->sc_parent;
1638 usb_device_request_t req;
1639
1640 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1641 req.bRequest = FTDI_SIO_GET_BITMODE;
1642
1643 USETW(req.wIndex, sc->sc_ucom.sc_portno);
1644 USETW(req.wLength, 1);
1645 USETW(req.wValue, 0);
1646
1647 return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, iomask));
1648}
1649
1650static int
1651uftdi_set_latency(struct ucom_softc *ucom, int latency)
1652{
1653 struct uftdi_softc *sc = ucom->sc_parent;
1654 usb_device_request_t req;
1655
1656 if (latency < 0 || latency > 255)
1657 return (USB_ERR_INVAL);
1658
1659 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1660 req.bRequest = FTDI_SIO_SET_LATENCY;
1661
1662 USETW(req.wIndex, sc->sc_ucom.sc_portno);
1663 USETW(req.wLength, 0);
1664 USETW2(req.wValue, 0, latency);
1665
1666 return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1667}
1668
1669static int
1670uftdi_get_latency(struct ucom_softc *ucom, int *latency)
1671{
1672 struct uftdi_softc *sc = ucom->sc_parent;
1673 usb_device_request_t req;
1674 usb_error_t err;
1675 uint8_t buf;
1676
1677 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1678 req.bRequest = FTDI_SIO_GET_LATENCY;
1679
1680 USETW(req.wIndex, sc->sc_ucom.sc_portno);
1681 USETW(req.wLength, 1);
1682 USETW(req.wValue, 0);
1683
1684 err = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, &buf);
1685 *latency = buf;
1686
1687 return (err);
1688}
1689
1690static int
1691uftdi_set_event_char(struct ucom_softc *ucom, int echar)
1692{
1693 struct uftdi_softc *sc = ucom->sc_parent;
1694 usb_device_request_t req;
1695 uint8_t enable;
1696
1697 enable = (echar == -1) ? 0 : 1;
1698
1699 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1700 req.bRequest = FTDI_SIO_SET_EVENT_CHAR;
1701
1702 USETW(req.wIndex, sc->sc_ucom.sc_portno);
1703 USETW(req.wLength, 0);
1704 USETW2(req.wValue, enable, echar & 0xff);
1705
1706 return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1707}
1708
1709static int
1710uftdi_set_error_char(struct ucom_softc *ucom, int echar)
1711{
1712 struct uftdi_softc *sc = ucom->sc_parent;
1713 usb_device_request_t req;
1714 uint8_t enable;
1715
1716 enable = (echar == -1) ? 0 : 1;
1717
1718 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1719 req.bRequest = FTDI_SIO_SET_ERROR_CHAR;
1720
1721 USETW(req.wIndex, sc->sc_ucom.sc_portno);
1722 USETW(req.wLength, 0);
1723 USETW2(req.wValue, enable, echar & 0xff);
1724
1725 return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
1726}
1727
1728static int
1729uftdi_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data,
1730 int flag, struct thread *td)
1731{
1732 struct uftdi_softc *sc = ucom->sc_parent;
1733 int err;
1734 struct uftdi_bitmode * mode;
1735
1736 DPRINTF("portno: %d cmd: %#x\n", ucom->sc_portno, cmd);
1737
1738 switch (cmd) {
1739 case UFTDIIOC_RESET_IO:
1740 case UFTDIIOC_RESET_RX:
1741 case UFTDIIOC_RESET_TX:
1742 err = uftdi_reset(ucom,
1743 cmd == UFTDIIOC_RESET_IO ? FTDI_SIO_RESET_SIO :
1744 (cmd == UFTDIIOC_RESET_RX ? FTDI_SIO_RESET_PURGE_RX :
1745 FTDI_SIO_RESET_PURGE_TX));
1746 break;
1747 case UFTDIIOC_SET_BITMODE:
1748 mode = (struct uftdi_bitmode *)data;
1749 err = uftdi_set_bitmode(ucom, mode->mode, mode->iomask);
1750 break;
1751 case UFTDIIOC_GET_BITMODE:
1752 mode = (struct uftdi_bitmode *)data;
1753 err = uftdi_get_bitmode(ucom, &mode->iomask);
1754 break;
1755 case UFTDIIOC_SET_LATENCY:
1756 err = uftdi_set_latency(ucom, *((int *)data));
1757 break;
1758 case UFTDIIOC_GET_LATENCY:
1759 err = uftdi_get_latency(ucom, (int *)data);
1760 break;
1761 case UFTDIIOC_SET_ERROR_CHAR:
1762 err = uftdi_set_event_char(ucom, *(int *)data);
1763 break;
1764 case UFTDIIOC_SET_EVENT_CHAR:
1765 err = uftdi_set_error_char(ucom, *(int *)data);
1766 case UFTDIIOC_GET_HWREV:
1767 *(int *)data = sc->sc_bcdDevice;
1768 err = 0;
1769 break;
1770 default:
1771 return (ENOIOCTL);
1772 }
1773 if (err != USB_ERR_NORMAL_COMPLETION)
1774 return (EIO);
1775 return (0);
1776}
1777
1586static void
1587uftdi_start_read(struct ucom_softc *ucom)
1588{
1589 struct uftdi_softc *sc = ucom->sc_parent;
1590
1591 usbd_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_RD]);
1592}
1593

--- 31 unchanged lines hidden ---
1778static void
1779uftdi_start_read(struct ucom_softc *ucom)
1780{
1781 struct uftdi_softc *sc = ucom->sc_parent;
1782
1783 usbd_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_RD]);
1784}
1785

--- 31 unchanged lines hidden ---