1/*
2 * Copyright (C) 2006
3 *   Simon Schulz (ark3116_driver <at> auctionant.de)
4 *
5 * ark3116
6 * - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547,
7 *   productid=0x0232) (used in a datacable called KQ-U8A)
8 *
9 * - based on code by krisfx -> thanks !!
10 *   (see http://www.linuxquestions.org/questions/showthread.php?p=2184457#post2184457)
11 *
12 *  - based on logs created by usbsnoopy
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
18 */
19
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/tty.h>
23#include <linux/module.h>
24#include <linux/usb.h>
25#include <linux/usb/serial.h>
26#include <linux/serial.h>
27#include <asm/uaccess.h>
28
29
30static int debug;
31
32static struct usb_device_id id_table [] = {
33	{ USB_DEVICE(0x6547, 0x0232) },
34	{ },
35};
36MODULE_DEVICE_TABLE(usb, id_table);
37
38struct ark3116_private {
39	spinlock_t lock;
40	u8 termios_initialized;
41};
42
43static inline void ARK3116_SND(struct usb_serial *serial, int seq,
44			       __u8 request, __u8 requesttype,
45			       __u16 value, __u16 index)
46{
47	int result;
48	result = usb_control_msg(serial->dev,
49				 usb_sndctrlpipe(serial->dev, 0),
50				 request, requesttype, value, index,
51				 NULL, 0x00, 1000);
52	dbg("%03d > ok", seq);
53}
54
55static inline void ARK3116_RCV(struct usb_serial *serial, int seq,
56			       __u8 request, __u8 requesttype,
57			       __u16 value, __u16 index, __u8 expected,
58			       char *buf)
59{
60	int result;
61	result = usb_control_msg(serial->dev,
62				 usb_rcvctrlpipe(serial->dev, 0),
63				 request, requesttype, value, index,
64				 buf, 0x0000001, 1000);
65	if (result)
66		dbg("%03d < %d bytes [0x%02X]", seq, result,
67		    ((unsigned char *)buf)[0]);
68	else
69		dbg("%03d < 0 bytes", seq);
70}
71
72static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
73				     __u8 request, __u8 requesttype,
74				     __u16 value, __u16 index, char *buf)
75{
76	usb_control_msg(serial->dev,
77			usb_rcvctrlpipe(serial->dev, 0),
78			request, requesttype, value, index,
79			buf, 0x0000001, 1000);
80}
81
82static int ark3116_attach(struct usb_serial *serial)
83{
84	char *buf;
85	struct ark3116_private *priv;
86	int i;
87
88	for (i = 0; i < serial->num_ports; ++i) {
89		priv = kzalloc(sizeof(struct ark3116_private), GFP_KERNEL);
90		if (!priv)
91			goto cleanup;
92		spin_lock_init(&priv->lock);
93
94		usb_set_serial_port_data(serial->port[i], priv);
95	}
96
97	buf = kmalloc(1, GFP_KERNEL);
98	if (!buf) {
99		dbg("error kmalloc -> out of mem?");
100		goto cleanup;
101	}
102
103	/* 3 */
104	ARK3116_SND(serial, 3, 0xFE, 0x40, 0x0008, 0x0002);
105	ARK3116_SND(serial, 4, 0xFE, 0x40, 0x0008, 0x0001);
106	ARK3116_SND(serial, 5, 0xFE, 0x40, 0x0000, 0x0008);
107	ARK3116_SND(serial, 6, 0xFE, 0x40, 0x0000, 0x000B);
108
109	/* <-- seq7 */
110	ARK3116_RCV(serial,  7, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
111	ARK3116_SND(serial,  8, 0xFE, 0x40, 0x0080, 0x0003);
112	ARK3116_SND(serial,  9, 0xFE, 0x40, 0x001A, 0x0000);
113	ARK3116_SND(serial, 10, 0xFE, 0x40, 0x0000, 0x0001);
114	ARK3116_SND(serial, 11, 0xFE, 0x40, 0x0000, 0x0003);
115
116	/* <-- seq12 */
117	ARK3116_RCV(serial, 12, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
118	ARK3116_SND(serial, 13, 0xFE, 0x40, 0x0000, 0x0004);
119
120	/* 14 */
121	ARK3116_RCV(serial, 14, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
122	ARK3116_SND(serial, 15, 0xFE, 0x40, 0x0000, 0x0004);
123
124	/* 16 */
125	ARK3116_RCV(serial, 16, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
126	/* --> seq17 */
127	ARK3116_SND(serial, 17, 0xFE, 0x40, 0x0001, 0x0004);
128
129	/* <-- seq18 */
130	ARK3116_RCV(serial, 18, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
131
132	/* --> seq19 */
133	ARK3116_SND(serial, 19, 0xFE, 0x40, 0x0003, 0x0004);
134
135	/* <-- seq20 */
136	/* seems like serial port status info (RTS, CTS, ...) */
137	/* returns modem control line status?! */
138	ARK3116_RCV(serial, 20, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
139
140	/* set 9600 baud & do some init?! */
141	ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
142	ARK3116_SND(serial, 148, 0xFE, 0x40, 0x0038, 0x0000);
143	ARK3116_SND(serial, 149, 0xFE, 0x40, 0x0001, 0x0001);
144	ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
145	ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
146	ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
147	ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
148	ARK3116_SND(serial, 154, 0xFE, 0x40, 0x0003, 0x0003);
149
150	kfree(buf);
151	return 0;
152
153cleanup:
154	for (--i; i >= 0; --i)
155		usb_set_serial_port_data(serial->port[i], NULL);
156	return -ENOMEM;
157}
158
159static void ark3116_set_termios(struct usb_serial_port *port,
160				struct ktermios *old_termios)
161{
162	struct usb_serial *serial = port->serial;
163	struct ark3116_private *priv = usb_get_serial_port_data(port);
164	unsigned int cflag = port->tty->termios->c_cflag;
165	unsigned long flags;
166	int baud;
167	int ark3116_baud;
168	char *buf;
169	char config;
170
171	config = 0;
172
173	dbg("%s - port %d", __FUNCTION__, port->number);
174
175	if ((!port->tty) || (!port->tty->termios)) {
176		dbg("%s - no tty structures", __FUNCTION__);
177		return;
178	}
179
180	spin_lock_irqsave(&priv->lock, flags);
181	if (!priv->termios_initialized) {
182		*(port->tty->termios) = tty_std_termios;
183		port->tty->termios->c_cflag = B9600 | CS8
184					      | CREAD | HUPCL | CLOCAL;
185		priv->termios_initialized = 1;
186	}
187	spin_unlock_irqrestore(&priv->lock, flags);
188
189	cflag = port->tty->termios->c_cflag;
190
191	/* check that they really want us to change something: */
192	if (old_termios) {
193		if ((cflag == old_termios->c_cflag) &&
194		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
195		     RELEVANT_IFLAG(old_termios->c_iflag))) {
196			dbg("%s - nothing to change...", __FUNCTION__);
197			return;
198		}
199	}
200
201	buf = kmalloc(1, GFP_KERNEL);
202	if (!buf) {
203		dbg("error kmalloc");
204		return;
205	}
206
207	/* set data bit count (8/7/6/5) */
208	if (cflag & CSIZE) {
209		switch (cflag & CSIZE) {
210		case CS5:
211			config |= 0x00;
212			dbg("setting CS5");
213			break;
214		case CS6:
215			config |= 0x01;
216			dbg("setting CS6");
217			break;
218		case CS7:
219			config |= 0x02;
220			dbg("setting CS7");
221			break;
222		default:
223			err("CSIZE was set but not CS5-CS8, using CS8!");
224			/* fall through */
225		case CS8:
226			config |= 0x03;
227			dbg("setting CS8");
228			break;
229		}
230	}
231
232	/* set parity (NONE/EVEN/ODD) */
233	if (cflag & PARENB) {
234		if (cflag & PARODD) {
235			config |= 0x08;
236			dbg("setting parity to ODD");
237		} else {
238			config |= 0x18;
239			dbg("setting parity to EVEN");
240		}
241	} else {
242		dbg("setting parity to NONE");
243	}
244
245	/* set stop bit (1/2) */
246	if (cflag & CSTOPB) {
247		config |= 0x04;
248		dbg("setting 2 stop bits");
249	} else {
250		dbg("setting 1 stop bit");
251	}
252
253	/* set baudrate */
254	baud = 0;
255	switch (cflag & CBAUD) {
256		case B0:
257			err("can't set 0 baud, using 9600 instead");
258			break;
259		case B75:	baud = 75;	break;
260		case B150:	baud = 150;	break;
261		case B300:	baud = 300;	break;
262		case B600:	baud = 600;	break;
263		case B1200:	baud = 1200;	break;
264		case B1800:	baud = 1800;	break;
265		case B2400:	baud = 2400;	break;
266		case B4800:	baud = 4800;	break;
267		case B9600:	baud = 9600;	break;
268		case B19200:	baud = 19200;	break;
269		case B38400:	baud = 38400;	break;
270		case B57600:	baud = 57600;	break;
271		case B115200:	baud = 115200;	break;
272		case B230400:	baud = 230400;	break;
273		case B460800:	baud = 460800;	break;
274		default:
275			dbg("does not support the baudrate requested (fix it)");
276			break;
277	}
278
279	/* set 9600 as default (if given baudrate is invalid for example) */
280	if (baud == 0)
281		baud = 9600;
282
283	/*
284	 * found by try'n'error, be careful, maybe there are other options
285	 * for multiplicator etc!
286	 */
287	if (baud == 460800)
288		/* strange, for 460800 the formula is wrong
289		 * if using round() then 9600baud is wrong) */
290		ark3116_baud = 7;
291	else
292		ark3116_baud = 3000000 / baud;
293
294	/* ? */
295	ARK3116_RCV(serial, 0, 0xFE, 0xC0, 0x0000, 0x0003, 0x03, buf);
296
297	/* offset = buf[0]; */
298	/* offset = 0x03; */
299	/* dbg("using 0x%04X as target for 0x0003:", 0x0080 + offset); */
300
301	/* set baudrate */
302	dbg("setting baudrate to %d (->reg=%d)", baud, ark3116_baud);
303	ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
304	ARK3116_SND(serial, 148, 0xFE, 0x40,
305			    (ark3116_baud & 0x00FF), 0x0000);
306	ARK3116_SND(serial, 149, 0xFE, 0x40,
307			    (ark3116_baud & 0xFF00) >> 8, 0x0001);
308	ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
309
310	/* ? */
311	ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
312	ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
313
314	/* set data bit count, stop bit count & parity: */
315	dbg("updating bit count, stop bit or parity (cfg=0x%02X)", config);
316	ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
317	ARK3116_SND(serial, 154, 0xFE, 0x40, config, 0x0003);
318
319	if (cflag & CRTSCTS)
320		dbg("CRTSCTS not supported by chipset?!");
321
322	/* TEST ARK3116_SND(154, 0xFE, 0x40, 0xFFFF, 0x0006); */
323
324	kfree(buf);
325	return;
326}
327
328static int ark3116_open(struct usb_serial_port *port, struct file *filp)
329{
330	struct ktermios tmp_termios;
331	struct usb_serial *serial = port->serial;
332	char *buf;
333	int result = 0;
334
335	dbg("%s - port %d", __FUNCTION__, port->number);
336
337	buf = kmalloc(1, GFP_KERNEL);
338	if (!buf) {
339		dbg("error kmalloc -> out of mem?");
340		return -ENOMEM;
341	}
342
343	result = usb_serial_generic_open(port, filp);
344	if (result)
345		goto err_out;
346
347	/* open */
348	ARK3116_RCV(serial, 111, 0xFE, 0xC0, 0x0000, 0x0003, 0x02, buf);
349
350	ARK3116_SND(serial, 112, 0xFE, 0x40, 0x0082, 0x0003);
351	ARK3116_SND(serial, 113, 0xFE, 0x40, 0x001A, 0x0000);
352	ARK3116_SND(serial, 114, 0xFE, 0x40, 0x0000, 0x0001);
353	ARK3116_SND(serial, 115, 0xFE, 0x40, 0x0002, 0x0003);
354
355	ARK3116_RCV(serial, 116, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
356	ARK3116_SND(serial, 117, 0xFE, 0x40, 0x0002, 0x0004);
357
358	ARK3116_RCV(serial, 118, 0xFE, 0xC0, 0x0000, 0x0004, 0x02, buf);
359	ARK3116_SND(serial, 119, 0xFE, 0x40, 0x0000, 0x0004);
360
361	ARK3116_RCV(serial, 120, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
362
363	ARK3116_SND(serial, 121, 0xFE, 0x40, 0x0001, 0x0004);
364
365	ARK3116_RCV(serial, 122, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
366
367	ARK3116_SND(serial, 123, 0xFE, 0x40, 0x0003, 0x0004);
368
369	/* returns different values (control lines?!) */
370	ARK3116_RCV(serial, 124, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
371
372	/* initialise termios */
373	if (port->tty)
374		ark3116_set_termios(port, &tmp_termios);
375
376err_out:
377	kfree(buf);
378
379	return result;
380}
381
382static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
383			 unsigned int cmd, unsigned long arg)
384{
385	struct serial_struct serstruct;
386	void __user *user_arg = (void __user *)arg;
387
388	switch (cmd) {
389	case TIOCGSERIAL:
390		memset(&serstruct, 0, sizeof (serstruct));
391		serstruct.type = PORT_16654;
392		serstruct.line = port->serial->minor;
393		serstruct.port = port->number;
394		serstruct.custom_divisor = 0;
395		serstruct.baud_base = 460800;
396
397		if (copy_to_user(user_arg, &serstruct, sizeof (serstruct)))
398			return -EFAULT;
399
400		return 0;
401	case TIOCSSERIAL:
402		if (copy_from_user(&serstruct, user_arg, sizeof (serstruct)))
403			return -EFAULT;
404		return 0;
405	default:
406		dbg("%s cmd 0x%04x not supported", __FUNCTION__, cmd);
407		break;
408	}
409
410	return -ENOIOCTLCMD;
411}
412
413static int ark3116_tiocmget(struct usb_serial_port *port, struct file *file)
414{
415	struct usb_serial *serial = port->serial;
416	char *buf;
417	char temp;
418
419	/* seems like serial port status info (RTS, CTS, ...) is stored
420	 * in reg(?) 0x0006
421	 * pcb connection point 11 = GND -> sets bit4 of response
422	 * pcb connection point  7 = GND -> sets bit6 of response
423	 */
424
425	buf = kmalloc(1, GFP_KERNEL);
426	if (!buf) {
427		dbg("error kmalloc");
428		return -ENOMEM;
429	}
430
431	/* read register */
432	ARK3116_RCV_QUIET(serial, 0xFE, 0xC0, 0x0000, 0x0006, buf);
433	temp = buf[0];
434	kfree(buf);
435
436	/* i do not really know if bit4=CTS and bit6=DSR... just a
437	 * quick guess!
438	 */
439	return (temp & (1<<4) ? TIOCM_CTS : 0)
440	       | (temp & (1<<6) ? TIOCM_DSR : 0);
441}
442
443static struct usb_driver ark3116_driver = {
444	.name =		"ark3116",
445	.probe =	usb_serial_probe,
446	.disconnect =	usb_serial_disconnect,
447	.id_table =	id_table,
448	.no_dynamic_id =	1,
449};
450
451static struct usb_serial_driver ark3116_device = {
452	.driver = {
453		.owner =	THIS_MODULE,
454		.name =		"ark3116",
455	},
456	.id_table =		id_table,
457	.usb_driver =		&ark3116_driver,
458	.num_interrupt_in =	1,
459	.num_bulk_in =		1,
460	.num_bulk_out =		1,
461	.num_ports =		1,
462	.attach =		ark3116_attach,
463	.set_termios =		ark3116_set_termios,
464	.ioctl =		ark3116_ioctl,
465	.tiocmget =		ark3116_tiocmget,
466	.open =			ark3116_open,
467};
468
469static int __init ark3116_init(void)
470{
471	int retval;
472
473	retval = usb_serial_register(&ark3116_device);
474	if (retval)
475		return retval;
476	retval = usb_register(&ark3116_driver);
477	if (retval)
478		usb_serial_deregister(&ark3116_device);
479	return retval;
480}
481
482static void __exit ark3116_exit(void)
483{
484	usb_deregister(&ark3116_driver);
485	usb_serial_deregister(&ark3116_device);
486}
487
488module_init(ark3116_init);
489module_exit(ark3116_exit);
490MODULE_LICENSE("GPL");
491
492module_param(debug, bool, S_IRUGO | S_IWUSR);
493MODULE_PARM_DESC(debug, "Debug enabled or not");
494