aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank A Kingswood <frank@kingswood-consulting.co.uk>2007-08-22 15:48:58 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:55:29 -0400
commit6ce76104781a10554129791dc62c3104424f6d48 (patch)
tree0756774b493cce844b1d34f0df45fc6b462e79cf
parent4ac0718e83821db53451614e098399004694aa81 (diff)
USB: Driver for CH341 USB-serial adaptor
This patch implements a USB serial port driver for the Winchiphead CH341 USB-RS232 Converter. This chip also implements an IEEE 1284 parallel port, I2C and SPI, but that is not supported by the driver. Signed-off-by: Frank A Kingswood <frank@kingswood-consulting.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--Documentation/usb/usb-serial.txt11
-rw-r--r--drivers/usb/serial/Kconfig10
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/ch341.c352
4 files changed, 374 insertions, 0 deletions
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index 5b635ae84944..4e0b62b8566f 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -428,6 +428,17 @@ Options supported:
428 See http://www.uuhaus.de/linux/palmconnect.html for up-to-date 428 See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
429 information on this driver. 429 information on this driver.
430 430
431Winchiphead CH341 Driver
432
433 This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
434 also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
435 supported by the driver. The protocol was analyzed from the behaviour
436 of the Windows driver, no datasheet is available at present.
437 The manufacturer's website: http://www.winchiphead.com/.
438 For any questions or problems with this driver, please contact
439 frank@kingswood-consulting.co.uk.
440
441
431Generic Serial driver 442Generic Serial driver
432 443
433 If your device is not one of the above listed devices, compatible with 444 If your device is not one of the above listed devices, compatible with
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 43d6db696f90..99fefed77919 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN
92 To compile this driver as a module, choose M here: the 92 To compile this driver as a module, choose M here: the
93 module will be called belkin_sa. 93 module will be called belkin_sa.
94 94
95config USB_SERIAL_CH341
96 tristate "USB Winchiphead CH341 Single Port Serial Driver"
97 depends on USB_SERIAL
98 help
99 Say Y here if you want to use a Winchiphead CH341 single port
100 USB to serial adapter.
101
102 To compile this driver as a module, choose M here: the
103 module will be called ch341.
104
95config USB_SERIAL_WHITEHEAT 105config USB_SERIAL_WHITEHEAT
96 tristate "USB ConnectTech WhiteHEAT Serial Driver" 106 tristate "USB ConnectTech WhiteHEAT Serial Driver"
97 depends on USB_SERIAL 107 depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 07a976eca6b7..d6fb384e52b2 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
15obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o 15obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
16obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o 16obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
17obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o 17obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
18obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o
18obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o 19obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o
19obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o 20obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
20obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o 21obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
new file mode 100644
index 000000000000..eb681069e24e
--- /dev/null
+++ b/drivers/usb/serial/ch341.c
@@ -0,0 +1,352 @@
1/*
2 * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
3 *
4 * ch341.c implements a serial port driver for the Winchiphead CH341.
5 *
6 * The CH341 device can be used to implement an RS232 asynchronous
7 * serial port, an IEEE-1284 parallel printer port or a memory-like
8 * interface. In all cases the CH341 supports an I2C interface as well.
9 * This driver only supports the asynchronous serial interface.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License version
13 * 2 as published by the Free Software Foundation.
14 */
15
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/tty.h>
19#include <linux/module.h>
20#include <linux/usb.h>
21#include <linux/usb/serial.h>
22#include <linux/serial.h>
23
24#define DEFAULT_BAUD_RATE 2400
25#define DEFAULT_TIMEOUT 1000
26
27static int debug;
28
29static struct usb_device_id id_table [] = {
30 { USB_DEVICE(0x4348, 0x5523) },
31 { },
32};
33MODULE_DEVICE_TABLE(usb, id_table);
34
35struct ch341_private {
36 unsigned baud_rate;
37 u8 dtr;
38 u8 rts;
39};
40
41static int ch341_control_out(struct usb_device *dev, u8 request,
42 u16 value, u16 index)
43{
44 int r;
45 dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
46 (int)request, (int)value, (int)index);
47
48 r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
49 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
50 value, index, NULL, 0, DEFAULT_TIMEOUT);
51
52 return r;
53}
54
55static int ch341_control_in(struct usb_device *dev,
56 u8 request, u16 value, u16 index,
57 char *buf, unsigned bufsize)
58{
59 int r;
60 dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
61 (int)request, (int)value, (int)index, buf, (int)bufsize);
62
63 r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
64 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
65 value, index, buf, bufsize, DEFAULT_TIMEOUT);
66 return r;
67}
68
69int ch341_set_baudrate(struct usb_device *dev, struct ch341_private *priv)
70{
71 short a, b;
72 int r;
73
74 dbg("ch341_set_baudrate(%d)", priv->baud_rate);
75 switch (priv->baud_rate) {
76 case 2400:
77 a = 0xd901;
78 b = 0x0038;
79 break;
80 case 4800:
81 a = 0x6402;
82 b = 0x001f;
83 break;
84 case 9600:
85 a = 0xb202;
86 b = 0x0013;
87 break;
88 case 19200:
89 a = 0xd902;
90 b = 0x000d;
91 break;
92 case 38400:
93 a = 0x6403;
94 b = 0x000a;
95 break;
96 case 115200:
97 a = 0xcc03;
98 b = 0x0008;
99 break;
100 default:
101 return -EINVAL;
102 }
103
104 r = ch341_control_out(dev, 0x9a, 0x1312, a);
105 if (!r)
106 r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
107
108 return r;
109}
110
111int ch341_set_handshake(struct usb_device *dev, struct ch341_private *priv)
112{
113 dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
114 return ch341_control_out(dev, 0xa4,
115 ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
116}
117
118int ch341_get_status(struct usb_device *dev)
119{
120 char *buffer;
121 int r;
122 const unsigned size = 8;
123
124 dbg("ch341_get_status()");
125
126 buffer = kmalloc(size, GFP_KERNEL);
127 if (!buffer)
128 return -ENOMEM;
129
130 r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
131 if ( r < 0)
132 goto out;
133
134 /* Not having the datasheet for the CH341, we ignore the bytes returned
135 * from the device. Return error if the device did not respond in time.
136 */
137 r = 0;
138
139out: kfree(buffer);
140 return r;
141}
142
143/* -------------------------------------------------------------------------- */
144
145int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
146{
147 char *buffer;
148 int r;
149 const unsigned size = 8;
150
151 dbg("ch341_configure()");
152
153 buffer = kmalloc(size, GFP_KERNEL);
154 if (!buffer)
155 return -ENOMEM;
156
157 /* expect two bytes 0x27 0x00 */
158 r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
159 if (r < 0)
160 goto out;
161
162 r = ch341_control_out(dev, 0xa1, 0, 0);
163 if (r < 0)
164 goto out;
165
166 r = ch341_set_baudrate(dev, priv);
167 if (r < 0)
168 goto out;
169
170 /* expect two bytes 0x56 0x00 */
171 r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
172 if (r < 0)
173 goto out;
174
175 r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
176 if (r < 0)
177 goto out;
178
179 /* expect 0xff 0xee */
180 r = ch341_get_status(dev);
181 if (r < 0)
182 goto out;
183
184 r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
185 if (r < 0)
186 goto out;
187
188 r = ch341_set_baudrate(dev, priv);
189 if (r < 0)
190 goto out;
191
192 r = ch341_set_handshake(dev, priv);
193 if (r < 0)
194 goto out;
195
196 /* expect 0x9f 0xee */
197 r = ch341_get_status(dev);
198
199out: kfree(buffer);
200 return r;
201}
202
203/* allocate private data */
204static int ch341_attach(struct usb_serial *serial)
205{
206 struct ch341_private *priv;
207 int r;
208
209 dbg("ch341_attach()");
210
211 /* private data */
212 priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
213 if (!priv)
214 return -ENOMEM;
215
216 priv->baud_rate = DEFAULT_BAUD_RATE;
217 priv->dtr = 1;
218 priv->rts = 1;
219
220 r = ch341_configure(serial->dev, priv);
221 if (r < 0)
222 goto error;
223
224 usb_set_serial_port_data(serial->port[0], priv);
225 return 0;
226
227error: kfree(priv);
228 return r;
229}
230
231/* open this device, set default parameters */
232static int ch341_open(struct usb_serial_port *port, struct file *filp)
233{
234 struct usb_serial *serial = port->serial;
235 struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
236 int r;
237
238 dbg("ch341_open()");
239
240 priv->baud_rate = DEFAULT_BAUD_RATE;
241 priv->dtr = 1;
242 priv->rts = 1;
243
244 r = ch341_configure(serial->dev, priv);
245 if (r)
246 goto out;
247
248 r = ch341_set_handshake(serial->dev, priv);
249 if (r)
250 goto out;
251
252 r = ch341_set_baudrate(serial->dev, priv);
253 if (r)
254 goto out;
255
256 r = usb_serial_generic_open(port, filp);
257
258out: return r;
259}
260
261/* Old_termios contains the original termios settings and
262 * tty->termios contains the new setting to be used.
263 */
264static void ch341_set_termios(struct usb_serial_port *port,
265 struct ktermios *old_termios)
266{
267 struct ch341_private *priv = usb_get_serial_port_data(port);
268 struct tty_struct *tty = port->tty;
269 unsigned baud_rate;
270
271 dbg("ch341_set_termios()");
272
273 if (!tty || !tty->termios)
274 return;
275
276 baud_rate = tty_get_baud_rate(tty);
277
278 switch (baud_rate) {
279 case 2400:
280 case 4800:
281 case 9600:
282 case 19200:
283 case 38400:
284 case 115200:
285 priv->baud_rate = baud_rate;
286 break;
287 default:
288 dbg("Rate %d not supported, using %d",
289 baud_rate, DEFAULT_BAUD_RATE);
290 priv->baud_rate = DEFAULT_BAUD_RATE;
291 }
292
293 ch341_set_baudrate(port->serial->dev, priv);
294
295 /* Unimplemented:
296 * (cflag & CSIZE) : data bits [5, 8]
297 * (cflag & PARENB) : parity {NONE, EVEN, ODD}
298 * (cflag & CSTOPB) : stop bits [1, 2]
299 */
300}
301
302static struct usb_driver ch341_driver = {
303 .name = "ch341",
304 .probe = usb_serial_probe,
305 .disconnect = usb_serial_disconnect,
306 .id_table = id_table,
307 .no_dynamic_id = 1,
308};
309
310static struct usb_serial_driver ch341_device = {
311 .driver = {
312 .owner = THIS_MODULE,
313 .name = "ch341-uart",
314 },
315 .id_table = id_table,
316 .usb_driver = &ch341_driver,
317 .num_interrupt_in = NUM_DONT_CARE,
318 .num_bulk_in = 1,
319 .num_bulk_out = 1,
320 .num_ports = 1,
321 .open = ch341_open,
322 .set_termios = ch341_set_termios,
323 .attach = ch341_attach,
324};
325
326static int __init ch341_init(void)
327{
328 int retval;
329
330 retval = usb_serial_register(&ch341_device);
331 if (retval)
332 return retval;
333 retval = usb_register(&ch341_driver);
334 if (retval)
335 usb_serial_deregister(&ch341_device);
336 return retval;
337}
338
339static void __exit ch341_exit(void)
340{
341 usb_deregister(&ch341_driver);
342 usb_serial_deregister(&ch341_device);
343}
344
345module_init(ch341_init);
346module_exit(ch341_exit);
347MODULE_LICENSE("GPL");
348
349module_param(debug, bool, S_IRUGO | S_IWUSR);
350MODULE_PARM_DESC(debug, "Debug enabled or not");
351
352/* EOF ch341.c */