diff options
-rw-r--r-- | share/man/man4/uftdi.4 | 6 | ||||
-rw-r--r-- | sys/dev/usb/uftdi.c | 57 | ||||
-rw-r--r-- | sys/dev/usb/uftdireg.h | 8 |
3 files changed, 57 insertions, 14 deletions
diff --git a/share/man/man4/uftdi.4 b/share/man/man4/uftdi.4 index ac65b252fa1..fa7156f38a6 100644 --- a/share/man/man4/uftdi.4 +++ b/share/man/man4/uftdi.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: uftdi.4,v 1.27 2009/11/07 05:18:09 deraadt Exp $ +.\" $OpenBSD: uftdi.4,v 1.28 2012/09/11 16:04:43 deraadt Exp $ .\" $NetBSD: uftdi.4,v 1.3 2001/01/13 20:53:22 nathanw Exp $ .\" .\" Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -28,7 +28,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: November 7 2009 $ +.Dd $Mdocdate: September 11 2012 $ .Dt UFTDI 4 .Os .Sh NAME @@ -41,7 +41,7 @@ The .Nm driver provides support for various serial adapters based on the FTDI -FT8U100AX, FT232BM, FT2232C, FT8U232AM, and FT8U245AM chips. +FT8U100AX, FT232BM, FT2232C, FT2232H, FT8U232AM, and FT8U245AM chips. .Pp The device is accessed through the .Xr ucom 4 diff --git a/sys/dev/usb/uftdi.c b/sys/dev/usb/uftdi.c index 003b8f4482a..5c524638454 100644 --- a/sys/dev/usb/uftdi.c +++ b/sys/dev/usb/uftdi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uftdi.c,v 1.62 2011/10/28 01:45:55 deraadt Exp $ */ +/* $OpenBSD: uftdi.c,v 1.63 2012/09/11 16:04:44 deraadt Exp $ */ /* $NetBSD: uftdi.c,v 1.14 2003/02/23 04:20:07 simonb Exp $ */ /* @@ -105,6 +105,7 @@ void uftdi_write(void *sc, int portno, u_char *to, u_char *from, u_int32_t *count); void uftdi_break(void *sc, int portno, int onoff); int uftdi_8u232am_getrate(speed_t speed, int *rate); +int uftdi_2232h_getrate(speed_t speed, int *rate); struct ucom_methods uftdi_methods = { uftdi_get_status, @@ -824,6 +825,9 @@ uftdi_attach(struct device *parent, struct device *self, void *aux) if (uaa->release < 0x0200) { sc->sc_type = UFTDI_TYPE_SIO; sc->sc_hdrlen = 1; + } else if (uaa->release == 0x0700 || uaa->release == 0x0800) { + sc->sc_type = UFTDI_TYPE_2232H; + sc->sc_hdrlen = 0; } else { sc->sc_type = UFTDI_TYPE_8U232AM; sc->sc_hdrlen = 0; @@ -842,11 +846,16 @@ uftdi_attach(struct device *parent, struct device *self, void *aux) addr = ed->bEndpointAddress; dir = UE_GET_DIR(ed->bEndpointAddress); attr = ed->bmAttributes & UE_XFERTYPE; - if (dir == UE_DIR_IN && attr == UE_BULK) + if (dir == UE_DIR_IN && attr == UE_BULK) { uca.bulkin = addr; - else if (dir == UE_DIR_OUT && attr == UE_BULK) + uca.ibufsize = (UGETW(ed->wMaxPacketSize) > 0) ? + UGETW(ed->wMaxPacketSize) : UFTDIIBUFSIZE; + } else if (dir == UE_DIR_OUT && attr == UE_BULK) { uca.bulkout = addr; - else { + uca.obufsize = (UGETW(ed->wMaxPacketSize) > 0) ? + UGETW(ed->wMaxPacketSize) : UFTDIOBUFSIZE; + uca.obufsize-= sc->sc_hdrlen; + } else { printf("%s: unexpected endpoint\n", devname); goto bad; } @@ -867,9 +876,7 @@ uftdi_attach(struct device *parent, struct device *self, void *aux) else uca.portno = FTDI_PIT_SIOA + id->bInterfaceNumber; /* bulkin, bulkout set above */ - uca.ibufsize = UFTDIIBUFSIZE; - uca.obufsize = UFTDIOBUFSIZE - sc->sc_hdrlen; - uca.ibufsizepad = UFTDIIBUFSIZE; + uca.ibufsizepad = uca.ibufsize; uca.opkthdrlen = sc->sc_hdrlen; uca.device = dev; uca.iface = iface; @@ -1076,11 +1083,15 @@ uftdi_param(void *vsc, int portno, struct termios *t) if (uftdi_8u232am_getrate(t->c_ospeed, &rate) == -1) return (EINVAL); break; + case UFTDI_TYPE_2232H: + if (uftdi_2232h_getrate(t->c_ospeed, &rate) == -1) + return (EINVAL); + break; } req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = FTDI_SIO_SET_BAUD_RATE; USETW(req.wValue, rate); - USETW(req.wIndex, portno); + USETW(req.wIndex, ((rate >> 8) & 0xFF00) | portno); USETW(req.wLength, 0); DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x " "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest, @@ -1250,3 +1261,33 @@ done: *rate = result; return (0); } + +int +uftdi_2232h_getrate(speed_t speed, int *rate) +{ + char sub[8] = {0, 3, 2, 4, 1, 5, 6, 7}; + int n = (FTDI_2232H_FREQ << 3) / speed; + int s = n & 7; + int result = (n >> 3) | (sub[s] << 14); + int resultspeed, accuracy; + + /* Special cases */ + if (result == 1) + result = 0; + else if (result == 0x4001) + result = 1; + + /* Check if resulting baud rate is within 3%. */ + if (result == 0) + goto done; + resultspeed = (FTDI_2232H_FREQ << 3) / + (((result & 0x00003FFF) << 3) | s); + accuracy = (abs(speed - resultspeed) * 100) / speed; + if (accuracy > 3) + return -1; + +done: + result|= 0x00020000; /* Set this bit to turn off a divide by 2.5 */ + *rate = result; + return 0; +} diff --git a/sys/dev/usb/uftdireg.h b/sys/dev/usb/uftdireg.h index 95d3a7e3505..a6e7d83162a 100644 --- a/sys/dev/usb/uftdireg.h +++ b/sys/dev/usb/uftdireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uftdireg.h,v 1.12 2008/07/05 14:41:28 mbalmer Exp $ */ +/* $OpenBSD: uftdireg.h,v 1.13 2012/09/11 16:04:44 deraadt Exp $ */ /* $NetBSD: uftdireg.h,v 1.6 2002/07/11 21:14:28 augustss Exp $ */ /* @@ -35,7 +35,8 @@ enum uftdi_type { UFTDI_TYPE_SIO, - UFTDI_TYPE_8U232AM + UFTDI_TYPE_8U232AM, + UFTDI_TYPE_2232H }; /* @@ -91,7 +92,8 @@ enum { ftdi_sio_b115200 = 9 }; -#define FTDI_8U232AM_FREQ 3000000 +#define FTDI_8U232AM_FREQ 3000000 /* (48MHz / 16) */ +#define FTDI_2232H_FREQ 12000000 /* (120MHz / 10) */ /* Bounds for normal divisors as 4-bit fixed precision ints. */ #define FTDI_8U232AM_MIN_DIV 0x20 |