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