xref: /OK3568_Linux_fs/kernel/drivers/usb/serial/kl5kusb105.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * KLSI KL5KUSB105 chip RS232 converter driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *   Copyright (C) 2010 Johan Hovold <jhovold@gmail.com>
6*4882a593Smuzhiyun  *   Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * All information about the device was acquired using SniffUSB ans snoopUSB
9*4882a593Smuzhiyun  * on Windows98.
10*4882a593Smuzhiyun  * It was written out of frustration with the PalmConnect USB Serial adapter
11*4882a593Smuzhiyun  * sold by Palm Inc.
12*4882a593Smuzhiyun  * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided
13*4882a593Smuzhiyun  * information that was not already available.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * It seems that KLSI bought some silicon-design information from ScanLogic,
16*4882a593Smuzhiyun  * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI.
17*4882a593Smuzhiyun  * KLSI has firmware available for their devices; it is probable that the
18*4882a593Smuzhiyun  * firmware differs from that used by KLSI in their products. If you have an
19*4882a593Smuzhiyun  * original KLSI device and can provide some information on it, I would be
20*4882a593Smuzhiyun  * most interested in adding support for it here. If you have any information
21*4882a593Smuzhiyun  * on the protocol used (or find errors in my reverse-engineered stuff), please
22*4882a593Smuzhiyun  * let me know.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * The code was only tested with a PalmConnect USB adapter; if you
25*4882a593Smuzhiyun  * are adventurous, try it with any KLSI-based device and let me know how it
26*4882a593Smuzhiyun  * breaks so that I can fix it!
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun /* TODO:
30*4882a593Smuzhiyun  *	check modem line signals
31*4882a593Smuzhiyun  *	implement handshaking or decide that we do not support it
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #include <linux/kernel.h>
35*4882a593Smuzhiyun #include <linux/errno.h>
36*4882a593Smuzhiyun #include <linux/slab.h>
37*4882a593Smuzhiyun #include <linux/tty.h>
38*4882a593Smuzhiyun #include <linux/tty_driver.h>
39*4882a593Smuzhiyun #include <linux/tty_flip.h>
40*4882a593Smuzhiyun #include <linux/module.h>
41*4882a593Smuzhiyun #include <linux/uaccess.h>
42*4882a593Smuzhiyun #include <asm/unaligned.h>
43*4882a593Smuzhiyun #include <linux/usb.h>
44*4882a593Smuzhiyun #include <linux/usb/serial.h>
45*4882a593Smuzhiyun #include "kl5kusb105.h"
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>"
48*4882a593Smuzhiyun #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /*
52*4882a593Smuzhiyun  * Function prototypes
53*4882a593Smuzhiyun  */
54*4882a593Smuzhiyun static int klsi_105_port_probe(struct usb_serial_port *port);
55*4882a593Smuzhiyun static int klsi_105_port_remove(struct usb_serial_port *port);
56*4882a593Smuzhiyun static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port);
57*4882a593Smuzhiyun static void klsi_105_close(struct usb_serial_port *port);
58*4882a593Smuzhiyun static void klsi_105_set_termios(struct tty_struct *tty,
59*4882a593Smuzhiyun 			struct usb_serial_port *port, struct ktermios *old);
60*4882a593Smuzhiyun static int  klsi_105_tiocmget(struct tty_struct *tty);
61*4882a593Smuzhiyun static void klsi_105_process_read_urb(struct urb *urb);
62*4882a593Smuzhiyun static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
63*4882a593Smuzhiyun 						void *dest, size_t size);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /*
66*4882a593Smuzhiyun  * All of the device info needed for the KLSI converters.
67*4882a593Smuzhiyun  */
68*4882a593Smuzhiyun static const struct usb_device_id id_table[] = {
69*4882a593Smuzhiyun 	{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
70*4882a593Smuzhiyun 	{ }		/* Terminating entry */
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, id_table);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun static struct usb_serial_driver kl5kusb105d_device = {
76*4882a593Smuzhiyun 	.driver = {
77*4882a593Smuzhiyun 		.owner =	THIS_MODULE,
78*4882a593Smuzhiyun 		.name =		"kl5kusb105d",
79*4882a593Smuzhiyun 	},
80*4882a593Smuzhiyun 	.description =		"KL5KUSB105D / PalmConnect",
81*4882a593Smuzhiyun 	.id_table =		id_table,
82*4882a593Smuzhiyun 	.num_ports =		1,
83*4882a593Smuzhiyun 	.bulk_out_size =	64,
84*4882a593Smuzhiyun 	.open =			klsi_105_open,
85*4882a593Smuzhiyun 	.close =		klsi_105_close,
86*4882a593Smuzhiyun 	.set_termios =		klsi_105_set_termios,
87*4882a593Smuzhiyun 	.tiocmget =		klsi_105_tiocmget,
88*4882a593Smuzhiyun 	.port_probe =		klsi_105_port_probe,
89*4882a593Smuzhiyun 	.port_remove =		klsi_105_port_remove,
90*4882a593Smuzhiyun 	.throttle =		usb_serial_generic_throttle,
91*4882a593Smuzhiyun 	.unthrottle =		usb_serial_generic_unthrottle,
92*4882a593Smuzhiyun 	.process_read_urb =	klsi_105_process_read_urb,
93*4882a593Smuzhiyun 	.prepare_write_buffer =	klsi_105_prepare_write_buffer,
94*4882a593Smuzhiyun };
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun static struct usb_serial_driver * const serial_drivers[] = {
97*4882a593Smuzhiyun 	&kl5kusb105d_device, NULL
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun struct klsi_105_port_settings {
101*4882a593Smuzhiyun 	u8	pktlen;		/* always 5, it seems */
102*4882a593Smuzhiyun 	u8	baudrate;
103*4882a593Smuzhiyun 	u8	databits;
104*4882a593Smuzhiyun 	u8	unknown1;
105*4882a593Smuzhiyun 	u8	unknown2;
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun struct klsi_105_private {
109*4882a593Smuzhiyun 	struct klsi_105_port_settings	cfg;
110*4882a593Smuzhiyun 	unsigned long			line_state; /* modem line settings */
111*4882a593Smuzhiyun 	spinlock_t			lock;
112*4882a593Smuzhiyun };
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun /*
116*4882a593Smuzhiyun  * Handle vendor specific USB requests
117*4882a593Smuzhiyun  */
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun #define KLSI_TIMEOUT	 5000 /* default urb timeout */
121*4882a593Smuzhiyun 
klsi_105_chg_port_settings(struct usb_serial_port * port,struct klsi_105_port_settings * settings)122*4882a593Smuzhiyun static int klsi_105_chg_port_settings(struct usb_serial_port *port,
123*4882a593Smuzhiyun 				      struct klsi_105_port_settings *settings)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	int rc;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	rc = usb_control_msg(port->serial->dev,
128*4882a593Smuzhiyun 			usb_sndctrlpipe(port->serial->dev, 0),
129*4882a593Smuzhiyun 			KL5KUSB105A_SIO_SET_DATA,
130*4882a593Smuzhiyun 			USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE,
131*4882a593Smuzhiyun 			0, /* value */
132*4882a593Smuzhiyun 			0, /* index */
133*4882a593Smuzhiyun 			settings,
134*4882a593Smuzhiyun 			sizeof(struct klsi_105_port_settings),
135*4882a593Smuzhiyun 			KLSI_TIMEOUT);
136*4882a593Smuzhiyun 	if (rc < 0)
137*4882a593Smuzhiyun 		dev_err(&port->dev,
138*4882a593Smuzhiyun 			"Change port settings failed (error = %d)\n", rc);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	dev_dbg(&port->dev,
141*4882a593Smuzhiyun 		"pktlen %u, baudrate 0x%02x, databits %u, u1 %u, u2 %u\n",
142*4882a593Smuzhiyun 		settings->pktlen, settings->baudrate, settings->databits,
143*4882a593Smuzhiyun 		settings->unknown1, settings->unknown2);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	return rc;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun /* translate a 16-bit status value from the device to linux's TIO bits */
klsi_105_status2linestate(const __u16 status)149*4882a593Smuzhiyun static unsigned long klsi_105_status2linestate(const __u16 status)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	unsigned long res = 0;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	res =   ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0)
154*4882a593Smuzhiyun 	      | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0)
155*4882a593Smuzhiyun 	      ;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	return res;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun /*
161*4882a593Smuzhiyun  * Read line control via vendor command and return result through
162*4882a593Smuzhiyun  * *line_state_p
163*4882a593Smuzhiyun  */
164*4882a593Smuzhiyun /* It seems that the status buffer has always only 2 bytes length */
165*4882a593Smuzhiyun #define KLSI_STATUSBUF_LEN	2
klsi_105_get_line_state(struct usb_serial_port * port,unsigned long * line_state_p)166*4882a593Smuzhiyun static int klsi_105_get_line_state(struct usb_serial_port *port,
167*4882a593Smuzhiyun 				   unsigned long *line_state_p)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	int rc;
170*4882a593Smuzhiyun 	u8 *status_buf;
171*4882a593Smuzhiyun 	__u16 status;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL);
174*4882a593Smuzhiyun 	if (!status_buf)
175*4882a593Smuzhiyun 		return -ENOMEM;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	status_buf[0] = 0xff;
178*4882a593Smuzhiyun 	status_buf[1] = 0xff;
179*4882a593Smuzhiyun 	rc = usb_control_msg(port->serial->dev,
180*4882a593Smuzhiyun 			     usb_rcvctrlpipe(port->serial->dev, 0),
181*4882a593Smuzhiyun 			     KL5KUSB105A_SIO_POLL,
182*4882a593Smuzhiyun 			     USB_TYPE_VENDOR | USB_DIR_IN,
183*4882a593Smuzhiyun 			     0, /* value */
184*4882a593Smuzhiyun 			     0, /* index */
185*4882a593Smuzhiyun 			     status_buf, KLSI_STATUSBUF_LEN,
186*4882a593Smuzhiyun 			     10000
187*4882a593Smuzhiyun 			     );
188*4882a593Smuzhiyun 	if (rc != KLSI_STATUSBUF_LEN) {
189*4882a593Smuzhiyun 		dev_err(&port->dev, "reading line status failed: %d\n", rc);
190*4882a593Smuzhiyun 		if (rc >= 0)
191*4882a593Smuzhiyun 			rc = -EIO;
192*4882a593Smuzhiyun 	} else {
193*4882a593Smuzhiyun 		status = get_unaligned_le16(status_buf);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 		dev_dbg(&port->dev, "read status %02x %02x\n",
196*4882a593Smuzhiyun 			status_buf[0], status_buf[1]);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 		*line_state_p = klsi_105_status2linestate(status);
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	kfree(status_buf);
202*4882a593Smuzhiyun 	return rc;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun /*
207*4882a593Smuzhiyun  * Driver's tty interface functions
208*4882a593Smuzhiyun  */
209*4882a593Smuzhiyun 
klsi_105_port_probe(struct usb_serial_port * port)210*4882a593Smuzhiyun static int klsi_105_port_probe(struct usb_serial_port *port)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	struct klsi_105_private *priv;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
215*4882a593Smuzhiyun 	if (!priv)
216*4882a593Smuzhiyun 		return -ENOMEM;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	/* set initial values for control structures */
219*4882a593Smuzhiyun 	priv->cfg.pktlen    = 5;
220*4882a593Smuzhiyun 	priv->cfg.baudrate  = kl5kusb105a_sio_b9600;
221*4882a593Smuzhiyun 	priv->cfg.databits  = kl5kusb105a_dtb_8;
222*4882a593Smuzhiyun 	priv->cfg.unknown1  = 0;
223*4882a593Smuzhiyun 	priv->cfg.unknown2  = 1;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	priv->line_state    = 0;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	spin_lock_init(&priv->lock);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	usb_set_serial_port_data(port, priv);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
klsi_105_port_remove(struct usb_serial_port * port)234*4882a593Smuzhiyun static int klsi_105_port_remove(struct usb_serial_port *port)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	struct klsi_105_private *priv;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	priv = usb_get_serial_port_data(port);
239*4882a593Smuzhiyun 	kfree(priv);
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	return 0;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
klsi_105_open(struct tty_struct * tty,struct usb_serial_port * port)244*4882a593Smuzhiyun static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	struct klsi_105_private *priv = usb_get_serial_port_data(port);
247*4882a593Smuzhiyun 	int retval = 0;
248*4882a593Smuzhiyun 	int rc;
249*4882a593Smuzhiyun 	unsigned long line_state;
250*4882a593Smuzhiyun 	struct klsi_105_port_settings *cfg;
251*4882a593Smuzhiyun 	unsigned long flags;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	/* Do a defined restart:
254*4882a593Smuzhiyun 	 * Set up sane default baud rate and send the 'READ_ON'
255*4882a593Smuzhiyun 	 * vendor command.
256*4882a593Smuzhiyun 	 * FIXME: set modem line control (how?)
257*4882a593Smuzhiyun 	 * Then read the modem line control and store values in
258*4882a593Smuzhiyun 	 * priv->line_state.
259*4882a593Smuzhiyun 	 */
260*4882a593Smuzhiyun 	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
261*4882a593Smuzhiyun 	if (!cfg)
262*4882a593Smuzhiyun 		return -ENOMEM;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	cfg->pktlen   = 5;
265*4882a593Smuzhiyun 	cfg->baudrate = kl5kusb105a_sio_b9600;
266*4882a593Smuzhiyun 	cfg->databits = kl5kusb105a_dtb_8;
267*4882a593Smuzhiyun 	cfg->unknown1 = 0;
268*4882a593Smuzhiyun 	cfg->unknown2 = 1;
269*4882a593Smuzhiyun 	klsi_105_chg_port_settings(port, cfg);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->lock, flags);
272*4882a593Smuzhiyun 	priv->cfg.pktlen   = cfg->pktlen;
273*4882a593Smuzhiyun 	priv->cfg.baudrate = cfg->baudrate;
274*4882a593Smuzhiyun 	priv->cfg.databits = cfg->databits;
275*4882a593Smuzhiyun 	priv->cfg.unknown1 = cfg->unknown1;
276*4882a593Smuzhiyun 	priv->cfg.unknown2 = cfg->unknown2;
277*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->lock, flags);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	kfree(cfg);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	/* READ_ON and urb submission */
282*4882a593Smuzhiyun 	rc = usb_serial_generic_open(tty, port);
283*4882a593Smuzhiyun 	if (rc)
284*4882a593Smuzhiyun 		return rc;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	rc = usb_control_msg(port->serial->dev,
287*4882a593Smuzhiyun 			     usb_sndctrlpipe(port->serial->dev, 0),
288*4882a593Smuzhiyun 			     KL5KUSB105A_SIO_CONFIGURE,
289*4882a593Smuzhiyun 			     USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
290*4882a593Smuzhiyun 			     KL5KUSB105A_SIO_CONFIGURE_READ_ON,
291*4882a593Smuzhiyun 			     0, /* index */
292*4882a593Smuzhiyun 			     NULL,
293*4882a593Smuzhiyun 			     0,
294*4882a593Smuzhiyun 			     KLSI_TIMEOUT);
295*4882a593Smuzhiyun 	if (rc < 0) {
296*4882a593Smuzhiyun 		dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
297*4882a593Smuzhiyun 		retval = rc;
298*4882a593Smuzhiyun 		goto err_generic_close;
299*4882a593Smuzhiyun 	} else
300*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - enabled reading\n", __func__);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	rc = klsi_105_get_line_state(port, &line_state);
303*4882a593Smuzhiyun 	if (rc < 0) {
304*4882a593Smuzhiyun 		retval = rc;
305*4882a593Smuzhiyun 		goto err_disable_read;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->lock, flags);
309*4882a593Smuzhiyun 	priv->line_state = line_state;
310*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->lock, flags);
311*4882a593Smuzhiyun 	dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__,
312*4882a593Smuzhiyun 			line_state);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	return 0;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun err_disable_read:
317*4882a593Smuzhiyun 	usb_control_msg(port->serial->dev,
318*4882a593Smuzhiyun 			     usb_sndctrlpipe(port->serial->dev, 0),
319*4882a593Smuzhiyun 			     KL5KUSB105A_SIO_CONFIGURE,
320*4882a593Smuzhiyun 			     USB_TYPE_VENDOR | USB_DIR_OUT,
321*4882a593Smuzhiyun 			     KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
322*4882a593Smuzhiyun 			     0, /* index */
323*4882a593Smuzhiyun 			     NULL, 0,
324*4882a593Smuzhiyun 			     KLSI_TIMEOUT);
325*4882a593Smuzhiyun err_generic_close:
326*4882a593Smuzhiyun 	usb_serial_generic_close(port);
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	return retval;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
klsi_105_close(struct usb_serial_port * port)331*4882a593Smuzhiyun static void klsi_105_close(struct usb_serial_port *port)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	int rc;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	/* send READ_OFF */
336*4882a593Smuzhiyun 	rc = usb_control_msg(port->serial->dev,
337*4882a593Smuzhiyun 			     usb_sndctrlpipe(port->serial->dev, 0),
338*4882a593Smuzhiyun 			     KL5KUSB105A_SIO_CONFIGURE,
339*4882a593Smuzhiyun 			     USB_TYPE_VENDOR | USB_DIR_OUT,
340*4882a593Smuzhiyun 			     KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
341*4882a593Smuzhiyun 			     0, /* index */
342*4882a593Smuzhiyun 			     NULL, 0,
343*4882a593Smuzhiyun 			     KLSI_TIMEOUT);
344*4882a593Smuzhiyun 	if (rc < 0)
345*4882a593Smuzhiyun 		dev_err(&port->dev, "failed to disable read: %d\n", rc);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	/* shutdown our bulk reads and writes */
348*4882a593Smuzhiyun 	usb_serial_generic_close(port);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun /* We need to write a complete 64-byte data block and encode the
352*4882a593Smuzhiyun  * number actually sent in the first double-byte, LSB-order. That
353*4882a593Smuzhiyun  * leaves at most 62 bytes of payload.
354*4882a593Smuzhiyun  */
355*4882a593Smuzhiyun #define KLSI_HDR_LEN		2
klsi_105_prepare_write_buffer(struct usb_serial_port * port,void * dest,size_t size)356*4882a593Smuzhiyun static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
357*4882a593Smuzhiyun 						void *dest, size_t size)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	unsigned char *buf = dest;
360*4882a593Smuzhiyun 	int count;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size,
363*4882a593Smuzhiyun 								&port->lock);
364*4882a593Smuzhiyun 	put_unaligned_le16(count, buf);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	return count + KLSI_HDR_LEN;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun /* The data received is preceded by a length double-byte in LSB-first order.
370*4882a593Smuzhiyun  */
klsi_105_process_read_urb(struct urb * urb)371*4882a593Smuzhiyun static void klsi_105_process_read_urb(struct urb *urb)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	struct usb_serial_port *port = urb->context;
374*4882a593Smuzhiyun 	unsigned char *data = urb->transfer_buffer;
375*4882a593Smuzhiyun 	unsigned len;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	/* empty urbs seem to happen, we ignore them */
378*4882a593Smuzhiyun 	if (!urb->actual_length)
379*4882a593Smuzhiyun 		return;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	if (urb->actual_length <= KLSI_HDR_LEN) {
382*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - malformed packet\n", __func__);
383*4882a593Smuzhiyun 		return;
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	len = get_unaligned_le16(data);
387*4882a593Smuzhiyun 	if (len > urb->actual_length - KLSI_HDR_LEN) {
388*4882a593Smuzhiyun 		dev_dbg(&port->dev, "%s - packet length mismatch\n", __func__);
389*4882a593Smuzhiyun 		len = urb->actual_length - KLSI_HDR_LEN;
390*4882a593Smuzhiyun 	}
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	tty_insert_flip_string(&port->port, data + KLSI_HDR_LEN, len);
393*4882a593Smuzhiyun 	tty_flip_buffer_push(&port->port);
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
klsi_105_set_termios(struct tty_struct * tty,struct usb_serial_port * port,struct ktermios * old_termios)396*4882a593Smuzhiyun static void klsi_105_set_termios(struct tty_struct *tty,
397*4882a593Smuzhiyun 				 struct usb_serial_port *port,
398*4882a593Smuzhiyun 				 struct ktermios *old_termios)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	struct klsi_105_private *priv = usb_get_serial_port_data(port);
401*4882a593Smuzhiyun 	struct device *dev = &port->dev;
402*4882a593Smuzhiyun 	unsigned int iflag = tty->termios.c_iflag;
403*4882a593Smuzhiyun 	unsigned int old_iflag = old_termios->c_iflag;
404*4882a593Smuzhiyun 	unsigned int cflag = tty->termios.c_cflag;
405*4882a593Smuzhiyun 	unsigned int old_cflag = old_termios->c_cflag;
406*4882a593Smuzhiyun 	struct klsi_105_port_settings *cfg;
407*4882a593Smuzhiyun 	unsigned long flags;
408*4882a593Smuzhiyun 	speed_t baud;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
411*4882a593Smuzhiyun 	if (!cfg)
412*4882a593Smuzhiyun 		return;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	/* lock while we are modifying the settings */
415*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->lock, flags);
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	/*
418*4882a593Smuzhiyun 	 * Update baud rate
419*4882a593Smuzhiyun 	 */
420*4882a593Smuzhiyun 	baud = tty_get_baud_rate(tty);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	switch (baud) {
423*4882a593Smuzhiyun 	case 0: /* handled below */
424*4882a593Smuzhiyun 		break;
425*4882a593Smuzhiyun 	case 1200:
426*4882a593Smuzhiyun 		priv->cfg.baudrate = kl5kusb105a_sio_b1200;
427*4882a593Smuzhiyun 		break;
428*4882a593Smuzhiyun 	case 2400:
429*4882a593Smuzhiyun 		priv->cfg.baudrate = kl5kusb105a_sio_b2400;
430*4882a593Smuzhiyun 		break;
431*4882a593Smuzhiyun 	case 4800:
432*4882a593Smuzhiyun 		priv->cfg.baudrate = kl5kusb105a_sio_b4800;
433*4882a593Smuzhiyun 		break;
434*4882a593Smuzhiyun 	case 9600:
435*4882a593Smuzhiyun 		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
436*4882a593Smuzhiyun 		break;
437*4882a593Smuzhiyun 	case 19200:
438*4882a593Smuzhiyun 		priv->cfg.baudrate = kl5kusb105a_sio_b19200;
439*4882a593Smuzhiyun 		break;
440*4882a593Smuzhiyun 	case 38400:
441*4882a593Smuzhiyun 		priv->cfg.baudrate = kl5kusb105a_sio_b38400;
442*4882a593Smuzhiyun 		break;
443*4882a593Smuzhiyun 	case 57600:
444*4882a593Smuzhiyun 		priv->cfg.baudrate = kl5kusb105a_sio_b57600;
445*4882a593Smuzhiyun 		break;
446*4882a593Smuzhiyun 	case 115200:
447*4882a593Smuzhiyun 		priv->cfg.baudrate = kl5kusb105a_sio_b115200;
448*4882a593Smuzhiyun 		break;
449*4882a593Smuzhiyun 	default:
450*4882a593Smuzhiyun 		dev_dbg(dev, "unsupported baudrate, using 9600\n");
451*4882a593Smuzhiyun 		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
452*4882a593Smuzhiyun 		baud = 9600;
453*4882a593Smuzhiyun 		break;
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	/*
457*4882a593Smuzhiyun 	 * FIXME: implement B0 handling
458*4882a593Smuzhiyun 	 *
459*4882a593Smuzhiyun 	 * Maybe this should be simulated by sending read disable and read
460*4882a593Smuzhiyun 	 * enable messages?
461*4882a593Smuzhiyun 	 */
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	tty_encode_baud_rate(tty, baud, baud);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
466*4882a593Smuzhiyun 		/* set the number of data bits */
467*4882a593Smuzhiyun 		switch (cflag & CSIZE) {
468*4882a593Smuzhiyun 		case CS5:
469*4882a593Smuzhiyun 			dev_dbg(dev, "%s - 5 bits/byte not supported\n", __func__);
470*4882a593Smuzhiyun 			spin_unlock_irqrestore(&priv->lock, flags);
471*4882a593Smuzhiyun 			goto err;
472*4882a593Smuzhiyun 		case CS6:
473*4882a593Smuzhiyun 			dev_dbg(dev, "%s - 6 bits/byte not supported\n", __func__);
474*4882a593Smuzhiyun 			spin_unlock_irqrestore(&priv->lock, flags);
475*4882a593Smuzhiyun 			goto err;
476*4882a593Smuzhiyun 		case CS7:
477*4882a593Smuzhiyun 			priv->cfg.databits = kl5kusb105a_dtb_7;
478*4882a593Smuzhiyun 			break;
479*4882a593Smuzhiyun 		case CS8:
480*4882a593Smuzhiyun 			priv->cfg.databits = kl5kusb105a_dtb_8;
481*4882a593Smuzhiyun 			break;
482*4882a593Smuzhiyun 		default:
483*4882a593Smuzhiyun 			dev_err(dev, "CSIZE was not CS5-CS8, using default of 8\n");
484*4882a593Smuzhiyun 			priv->cfg.databits = kl5kusb105a_dtb_8;
485*4882a593Smuzhiyun 			break;
486*4882a593Smuzhiyun 		}
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	/*
490*4882a593Smuzhiyun 	 * Update line control register (LCR)
491*4882a593Smuzhiyun 	 */
492*4882a593Smuzhiyun 	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
493*4882a593Smuzhiyun 	    || (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
494*4882a593Smuzhiyun 		/* Not currently supported */
495*4882a593Smuzhiyun 		tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB);
496*4882a593Smuzhiyun 	}
497*4882a593Smuzhiyun 	/*
498*4882a593Smuzhiyun 	 * Set flow control: well, I do not really now how to handle DTR/RTS.
499*4882a593Smuzhiyun 	 * Just do what we have seen with SniffUSB on Win98.
500*4882a593Smuzhiyun 	 */
501*4882a593Smuzhiyun 	if ((iflag & IXOFF) != (old_iflag & IXOFF)
502*4882a593Smuzhiyun 	    || (iflag & IXON) != (old_iflag & IXON)
503*4882a593Smuzhiyun 	    ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
504*4882a593Smuzhiyun 		/* Not currently supported */
505*4882a593Smuzhiyun 		tty->termios.c_cflag &= ~CRTSCTS;
506*4882a593Smuzhiyun 	}
507*4882a593Smuzhiyun 	memcpy(cfg, &priv->cfg, sizeof(*cfg));
508*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->lock, flags);
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	/* now commit changes to device */
511*4882a593Smuzhiyun 	klsi_105_chg_port_settings(port, cfg);
512*4882a593Smuzhiyun err:
513*4882a593Smuzhiyun 	kfree(cfg);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun 
klsi_105_tiocmget(struct tty_struct * tty)516*4882a593Smuzhiyun static int klsi_105_tiocmget(struct tty_struct *tty)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	struct usb_serial_port *port = tty->driver_data;
519*4882a593Smuzhiyun 	struct klsi_105_private *priv = usb_get_serial_port_data(port);
520*4882a593Smuzhiyun 	unsigned long flags;
521*4882a593Smuzhiyun 	int rc;
522*4882a593Smuzhiyun 	unsigned long line_state;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	rc = klsi_105_get_line_state(port, &line_state);
525*4882a593Smuzhiyun 	if (rc < 0) {
526*4882a593Smuzhiyun 		dev_err(&port->dev,
527*4882a593Smuzhiyun 			"Reading line control failed (error = %d)\n", rc);
528*4882a593Smuzhiyun 		/* better return value? EAGAIN? */
529*4882a593Smuzhiyun 		return rc;
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	spin_lock_irqsave(&priv->lock, flags);
533*4882a593Smuzhiyun 	priv->line_state = line_state;
534*4882a593Smuzhiyun 	spin_unlock_irqrestore(&priv->lock, flags);
535*4882a593Smuzhiyun 	dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
536*4882a593Smuzhiyun 	return (int)line_state;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun module_usb_serial_driver(serial_drivers, id_table);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun MODULE_AUTHOR(DRIVER_AUTHOR);
542*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
543*4882a593Smuzhiyun MODULE_LICENSE("GPL");
544