Sun May 24 16:24:26 2009 UTC ()
- detect FTDI chiptype from bcdDevice field to determine the number of
  channels.
- tested on 232BM, 232RL and 2232D chips.
- now capable of quad channel FT4232H.
- minor format nit and legacy title comment removal.
- non UART type bit stream (!= ucom) support is under planning.


(nisimura)
diff -r1.40 -r1.41 src/sys/dev/usb/uftdi.c

cvs diff -r1.40 -r1.41 src/sys/dev/usb/uftdi.c (expand / switch to unified diff)

--- src/sys/dev/usb/uftdi.c 2009/04/21 16:26:01 1.40
+++ src/sys/dev/usb/uftdi.c 2009/05/24 16:24:25 1.41
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: uftdi.c,v 1.40 2009/04/21 16:26:01 taca Exp $ */ 1/* $NetBSD: uftdi.c,v 1.41 2009/05/24 16:24:25 nisimura Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net). 8 * by Lennart Augustsson (lennart@augustsson.net).
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -19,32 +19,28 @@ @@ -19,32 +19,28 @@
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32/* 
33 * FTDI FT8U100AX serial adapter driver 
34 */ 
35 
36#include <sys/cdefs.h> 32#include <sys/cdefs.h>
37__KERNEL_RCSID(0, "$NetBSD: uftdi.c,v 1.40 2009/04/21 16:26:01 taca Exp $"); 33__KERNEL_RCSID(0, "$NetBSD: uftdi.c,v 1.41 2009/05/24 16:24:25 nisimura Exp $");
38 34
39#include <sys/param.h> 35#include <sys/param.h>
40#include <sys/systm.h> 36#include <sys/systm.h>
41#include <sys/kernel.h> 37#include <sys/kernel.h>
42#include <sys/device.h> 38#include <sys/device.h>
43#include <sys/conf.h> 39#include <sys/conf.h>
44#include <sys/tty.h> 40#include <sys/tty.h>
45 41
46#include <dev/usb/usb.h> 42#include <dev/usb/usb.h>
47 43
48#include <dev/usb/usbdi.h> 44#include <dev/usb/usbdi.h>
49#include <dev/usb/usbdi_util.h> 45#include <dev/usb/usbdi_util.h>
50#include <dev/usb/usbdevs.h> 46#include <dev/usb/usbdevs.h>
@@ -54,52 +50,54 @@ __KERNEL_RCSID(0, "$NetBSD: uftdi.c,v 1. @@ -54,52 +50,54 @@ __KERNEL_RCSID(0, "$NetBSD: uftdi.c,v 1.
54#include <dev/usb/uftdireg.h> 50#include <dev/usb/uftdireg.h>
55 51
56#ifdef UFTDI_DEBUG 52#ifdef UFTDI_DEBUG
57#define DPRINTF(x) if (uftdidebug) printf x 53#define DPRINTF(x) if (uftdidebug) printf x
58#define DPRINTFN(n,x) if (uftdidebug>(n)) printf x 54#define DPRINTFN(n,x) if (uftdidebug>(n)) printf x
59int uftdidebug = 0; 55int uftdidebug = 0;
60#else 56#else
61#define DPRINTF(x) 57#define DPRINTF(x)
62#define DPRINTFN(n,x) 58#define DPRINTFN(n,x)
63#endif 59#endif
64 60
65#define UFTDI_CONFIG_INDEX 0 61#define UFTDI_CONFIG_INDEX 0
66#define UFTDI_IFACE_INDEX 0 62#define UFTDI_IFACE_INDEX 0
67#define UFTDI_MAX_PORTS 2 63#define UFTDI_MAX_PORTS 4
68 64
69/* 65/*
70 * These are the maximum number of bytes transferred per frame. 66 * These are the maximum number of bytes transferred per frame.
71 * The output buffer size cannot be increased due to the size encoding. 67 * The output buffer size cannot be increased due to the size encoding.
72 */ 68 */
73#define UFTDIIBUFSIZE 64 69#define UFTDIIBUFSIZE 64
74#define UFTDIOBUFSIZE 64 70#define UFTDIOBUFSIZE 64
75 71
76struct uftdi_softc { 72struct uftdi_softc {
77 USBBASEDEVICE sc_dev; /* base device */ 73 USBBASEDEVICE sc_dev; /* base device */
78 usbd_device_handle sc_udev; /* device */ 74 usbd_device_handle sc_udev; /* device */
79 usbd_interface_handle sc_iface[UFTDI_MAX_PORTS]; /* interface */ 75 usbd_interface_handle sc_iface[UFTDI_MAX_PORTS]; /* interface */
80 76
81 enum uftdi_type sc_type; 77 enum uftdi_type sc_type;
82 u_int sc_hdrlen; 78 u_int sc_hdrlen;
83 u_int sc_numports; 79 u_int sc_numports;
 80 u_int sc_chiptype;
84 81
85 u_char sc_msr; 82 u_char sc_msr;
86 u_char sc_lsr; 83 u_char sc_lsr;
87 84
88 device_ptr_t sc_subdev[UFTDI_MAX_PORTS]; 85 device_ptr_t sc_subdev[UFTDI_MAX_PORTS];
89 86
90 u_char sc_dying; 87 u_char sc_dying;
91 88
92 u_int last_lcr; 89 u_int last_lcr;
 90
93}; 91};
94 92
95Static void uftdi_get_status(void *, int portno, u_char *lsr, u_char *msr); 93Static void uftdi_get_status(void *, int portno, u_char *lsr, u_char *msr);
96Static void uftdi_set(void *, int, int, int); 94Static void uftdi_set(void *, int, int, int);
97Static int uftdi_param(void *, int, struct termios *); 95Static int uftdi_param(void *, int, struct termios *);
98Static int uftdi_open(void *sc, int portno); 96Static int uftdi_open(void *sc, int portno);
99Static void uftdi_read(void *sc, int portno, u_char **ptr,u_int32_t *count); 97Static void uftdi_read(void *sc, int portno, u_char **ptr,u_int32_t *count);
100Static void uftdi_write(void *sc, int portno, u_char *to, u_char *from, 98Static void uftdi_write(void *sc, int portno, u_char *to, u_char *from,
101 u_int32_t *count); 99 u_int32_t *count);
102Static void uftdi_break(void *sc, int portno, int onoff); 100Static void uftdi_break(void *sc, int portno, int onoff);
103 101
104struct ucom_methods uftdi_methods = { 102struct ucom_methods uftdi_methods = {
105 uftdi_get_status, 103 uftdi_get_status,
@@ -169,70 +167,76 @@ USB_MATCH(uftdi) @@ -169,70 +167,76 @@ USB_MATCH(uftdi)
169 167
170 DPRINTFN(20,("uftdi: vendor=0x%x, product=0x%x\n", 168 DPRINTFN(20,("uftdi: vendor=0x%x, product=0x%x\n",
171 uaa->vendor, uaa->product)); 169 uaa->vendor, uaa->product));
172 170
173 return (uftdi_lookup(uaa->vendor, uaa->product) != NULL ? 171 return (uftdi_lookup(uaa->vendor, uaa->product) != NULL ?
174 UMATCH_VENDOR_PRODUCT : UMATCH_NONE); 172 UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
175} 173}
176 174
177USB_ATTACH(uftdi) 175USB_ATTACH(uftdi)
178{ 176{
179 USB_ATTACH_START(uftdi, sc, uaa); 177 USB_ATTACH_START(uftdi, sc, uaa);
180 usbd_device_handle dev = uaa->device; 178 usbd_device_handle dev = uaa->device;
181 usbd_interface_handle iface; 179 usbd_interface_handle iface;
 180 usb_device_descriptor_t *ddesc;
182 usb_interface_descriptor_t *id; 181 usb_interface_descriptor_t *id;
183 usb_endpoint_descriptor_t *ed; 182 usb_endpoint_descriptor_t *ed;
184 char *devinfop; 183 char *devinfop;
185 const char *devname = device_xname(self); 184 const char *devname = device_xname(self);
186 int i,idx; 185 int i,idx;
187 usbd_status err; 186 usbd_status err;
188 struct ucom_attach_args uca; 187 struct ucom_attach_args uca;
189 188
190 DPRINTFN(10,("\nuftdi_attach: sc=%p\n", sc)); 189 DPRINTFN(10,("\nuftdi_attach: sc=%p\n", sc));
191 190
192 /* Move the device into the configured state. */ 191 /* Move the device into the configured state. */
193 err = usbd_set_config_index(dev, UFTDI_CONFIG_INDEX, 1); 192 err = usbd_set_config_index(dev, UFTDI_CONFIG_INDEX, 1);
194 if (err) { 193 if (err) {
195 aprint_error("\n%s: failed to set configuration, err=%s\n", 194 aprint_error("\n%s: failed to set configuration, err=%s\n",
196 devname, usbd_errstr(err)); 195 devname, usbd_errstr(err));
197 goto bad; 196 goto bad;
198 } 197 }
199 198
200 devinfop = usbd_devinfo_alloc(dev, 0); 199 devinfop = usbd_devinfo_alloc(dev, 0);
201 USB_ATTACH_SETUP; 200 USB_ATTACH_SETUP;
202 aprint_normal_dev(self, "%s\n", devinfop); 201 aprint_normal_dev(self, "%s\n", devinfop);
203 usbd_devinfo_free(devinfop); 202 usbd_devinfo_free(devinfop);
204 203
205 sc->sc_dev = self; 204 sc->sc_dev = self;
206 sc->sc_udev = dev; 205 sc->sc_udev = dev;
207 sc->sc_numports = 1; 206 sc->sc_numports = 1;
208 switch( uaa->vendor ) { 207 sc->sc_type = UFTDI_TYPE_8U232AM; /* most devices are post-8U232AM */
209 case USB_VENDOR_FTDI: 208 sc->sc_hdrlen = 0;
210 switch (uaa->product) { 209 if (uaa->vendor == USB_VENDOR_FTDI
211 case USB_PRODUCT_FTDI_SERIAL_8U100AX: 210 && uaa->product == USB_PRODUCT_FTDI_SERIAL_8U100AX) {
212 sc->sc_type = UFTDI_TYPE_SIO; 211 sc->sc_type = UFTDI_TYPE_SIO;
213 sc->sc_hdrlen = 1; 212 sc->sc_hdrlen = 1;
214 break; 213 }
215 case USB_PRODUCT_FTDI_SERIAL_2232C: 214
216 sc->sc_numports = 2; 215 ddesc = usbd_get_device_descriptor(dev);
217 /* FALLTHROUGH */ 216 sc->sc_chiptype = UGETW(ddesc->bcdDevice);
218 default: /* Most uftdi devices are 8U232AM */ 217 switch (sc->sc_chiptype) {
219 sc->sc_type = UFTDI_TYPE_8U232AM; 218 case 0x500: /* 2232D */
220 sc->sc_hdrlen = 0; 219 case 0x700: /* 2232H */
221 } 220 sc->sc_numports = 2;
 221 break;
 222 case 0x800: /* 4232H */
 223 sc->sc_numports = 4;
 224 break;
 225 case 0x200: /* 232/245AM */
 226 case 0x400: /* 232/245BL */
 227 case 0x600: /* 232/245R */
 228 default:
222 break; 229 break;
223 default: /* Most uftdi devices are 8U232AM */ 
224 sc->sc_type = UFTDI_TYPE_8U232AM; 
225 sc->sc_hdrlen = 0; 
226 } 230 }
227 231
228 for (idx = UFTDI_IFACE_INDEX; idx < sc->sc_numports; idx++) { 232 for (idx = UFTDI_IFACE_INDEX; idx < sc->sc_numports; idx++) {
229 err = usbd_device2interface_handle(dev, idx, &iface); 233 err = usbd_device2interface_handle(dev, idx, &iface);
230 if (err) { 234 if (err) {
231 aprint_error( 235 aprint_error(
232 "\n%s: failed to get interface idx=%d, err=%s\n", 236 "\n%s: failed to get interface idx=%d, err=%s\n",
233 devname, idx, usbd_errstr(err)); 237 devname, idx, usbd_errstr(err));
234 goto bad; 238 goto bad;
235 } 239 }
236 240
237 id = usbd_get_interface_descriptor(iface); 241 id = usbd_get_interface_descriptor(iface);
238 242
@@ -276,28 +280,28 @@ USB_ATTACH(uftdi) @@ -276,28 +280,28 @@ USB_ATTACH(uftdi)
276 uca.portno = FTDI_PIT_SIOA + idx; 280 uca.portno = FTDI_PIT_SIOA + idx;
277 /* bulkin, bulkout set above */ 281 /* bulkin, bulkout set above */
278 uca.ibufsize = UFTDIIBUFSIZE; 282 uca.ibufsize = UFTDIIBUFSIZE;
279 uca.obufsize = UFTDIOBUFSIZE - sc->sc_hdrlen; 283 uca.obufsize = UFTDIOBUFSIZE - sc->sc_hdrlen;
280 uca.ibufsizepad = UFTDIIBUFSIZE; 284 uca.ibufsizepad = UFTDIIBUFSIZE;
281 uca.opkthdrlen = sc->sc_hdrlen; 285 uca.opkthdrlen = sc->sc_hdrlen;
282 uca.device = dev; 286 uca.device = dev;
283 uca.iface = iface; 287 uca.iface = iface;
284 uca.methods = &uftdi_methods; 288 uca.methods = &uftdi_methods;
285 uca.arg = sc; 289 uca.arg = sc;
286 uca.info = NULL; 290 uca.info = NULL;
287 291
288 DPRINTF(("uftdi: in=0x%x out=0x%x\n", uca.bulkin, uca.bulkout)); 292 DPRINTF(("uftdi: in=0x%x out=0x%x\n", uca.bulkin, uca.bulkout));
289 sc->sc_subdev[idx] = config_found_sm_loc(self, "ucombus", NULL, &uca, 293 sc->sc_subdev[idx] = config_found_sm_loc(self, "ucombus", NULL,
290 ucomprint, ucomsubmatch); 294 &uca, ucomprint, ucomsubmatch);
291 } 295 }
292 296
293 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 297 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
294 USBDEV(sc->sc_dev)); 298 USBDEV(sc->sc_dev));
295 299
296 USB_ATTACH_SUCCESS_RETURN; 300 USB_ATTACH_SUCCESS_RETURN;
297 301
298bad: 302bad:
299 DPRINTF(("uftdi_attach: ATTACH ERROR\n")); 303 DPRINTF(("uftdi_attach: ATTACH ERROR\n"));
300 sc->sc_dying = 1; 304 sc->sc_dying = 1;
301 USB_ATTACH_ERROR_RETURN; 305 USB_ATTACH_ERROR_RETURN;
302} 306}
303 307