blob: 886e1294b120a4d0d387fef741f21b88a13706cd [file] [log] [blame]
Bill Pemberton52af9542010-07-29 11:05:41 -04001/*
2 * usb-serial driver for Quatech SSU-100
3 *
4 * based on ftdi_sio.c and the original serqt_usb.c from Quatech
5 *
6 */
7
8#include <linux/errno.h>
Bill Pemberton52af9542010-07-29 11:05:41 -04009#include <linux/slab.h>
10#include <linux/tty.h>
11#include <linux/tty_driver.h>
12#include <linux/tty_flip.h>
13#include <linux/module.h>
14#include <linux/serial.h>
15#include <linux/usb.h>
16#include <linux/usb/serial.h>
Bill Pemberton79f203a2010-08-05 17:01:07 -040017#include <linux/serial_reg.h>
Bill Pemberton52af9542010-07-29 11:05:41 -040018#include <linux/uaccess.h>
19
20#define QT_OPEN_CLOSE_CHANNEL 0xca
21#define QT_SET_GET_DEVICE 0xc2
22#define QT_SET_GET_REGISTER 0xc0
23#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
24#define QT_SET_ATF 0xcd
25#define QT_GET_SET_UART 0xc1
26#define QT_TRANSFER_IN 0xc0
27#define QT_HW_FLOW_CONTROL_MASK 0xc5
28#define QT_SW_FLOW_CONTROL_MASK 0xc6
29
Bill Pemberton52af9542010-07-29 11:05:41 -040030#define SERIAL_MSR_MASK 0xf0
31
Bill Pemberton79f203a2010-08-05 17:01:07 -040032#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS)
Bill Pemberton52af9542010-07-29 11:05:41 -040033
Bill Pemberton79f203a2010-08-05 17:01:07 -040034#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR)
Bill Pemberton52af9542010-07-29 11:05:41 -040035
36#define MAX_BAUD_RATE 460800
37
38#define ATC_DISABLED 0x00
39#define DUPMODE_BITS 0xc0
40#define RR_BITS 0x03
41#define LOOPMODE_BITS 0x41
42#define RS232_MODE 0x00
43#define RTSCTS_TO_CONNECTOR 0x40
44#define CLKS_X4 0x02
45#define FULLPWRBIT 0x00000080
46#define NEXT_BOARD_POWER_BIT 0x00000004
47
Bill Pemberton52af9542010-07-29 11:05:41 -040048#define DRIVER_DESC "Quatech SSU-100 USB to Serial Driver"
49
50#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */
51#define QUATECH_SSU100 0xC020 /* SSU100 */
52
53static const struct usb_device_id id_table[] = {
54 {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)},
55 {} /* Terminating entry */
56};
Bill Pemberton52af9542010-07-29 11:05:41 -040057MODULE_DEVICE_TABLE(usb, id_table);
58
Bill Pemberton52af9542010-07-29 11:05:41 -040059struct ssu100_port_private {
Bill Pemberton17523052010-08-05 17:01:05 -040060 spinlock_t status_lock;
Bill Pemberton52af9542010-07-29 11:05:41 -040061 u8 shadowLSR;
62 u8 shadowMSR;
Bill Pemberton52af9542010-07-29 11:05:41 -040063};
64
Bill Pemberton52af9542010-07-29 11:05:41 -040065static inline int ssu100_control_msg(struct usb_device *dev,
66 u8 request, u16 data, u16 index)
67{
68 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
69 request, 0x40, data, index,
70 NULL, 0, 300);
71}
72
73static inline int ssu100_setdevice(struct usb_device *dev, u8 *data)
74{
75 u16 x = ((u16)(data[1] << 8) | (u16)(data[0]));
76
77 return ssu100_control_msg(dev, QT_SET_GET_DEVICE, x, 0);
78}
79
80
81static inline int ssu100_getdevice(struct usb_device *dev, u8 *data)
82{
Johan Hovold4d32e362017-01-12 14:56:22 +010083 int ret;
84
85 ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
86 QT_SET_GET_DEVICE, 0xc0, 0, 0,
87 data, 3, 300);
88 if (ret < 3) {
89 if (ret >= 0)
90 ret = -EIO;
91 }
92
93 return ret;
Bill Pemberton52af9542010-07-29 11:05:41 -040094}
95
96static inline int ssu100_getregister(struct usb_device *dev,
97 unsigned short uart,
98 unsigned short reg,
99 u8 *data)
100{
Johan Hovold4d32e362017-01-12 14:56:22 +0100101 int ret;
Bill Pemberton52af9542010-07-29 11:05:41 -0400102
Johan Hovold4d32e362017-01-12 14:56:22 +0100103 ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
104 QT_SET_GET_REGISTER, 0xc0, reg,
105 uart, data, sizeof(*data), 300);
106 if (ret < sizeof(*data)) {
107 if (ret >= 0)
108 ret = -EIO;
109 }
110
111 return ret;
Bill Pemberton52af9542010-07-29 11:05:41 -0400112}
113
114
115static inline int ssu100_setregister(struct usb_device *dev,
116 unsigned short uart,
Bill Pemberton556f1a02010-08-05 17:01:08 -0400117 unsigned short reg,
Bill Pemberton52af9542010-07-29 11:05:41 -0400118 u16 data)
119{
Bill Pemberton556f1a02010-08-05 17:01:08 -0400120 u16 value = (data << 8) | reg;
Bill Pemberton52af9542010-07-29 11:05:41 -0400121
122 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
123 QT_SET_GET_REGISTER, 0x40, value, uart,
124 NULL, 0, 300);
125
126}
127
128#define set_mctrl(dev, set) update_mctrl((dev), (set), 0)
129#define clear_mctrl(dev, clear) update_mctrl((dev), 0, (clear))
130
131/* these do not deal with device that have more than 1 port */
132static inline int update_mctrl(struct usb_device *dev, unsigned int set,
133 unsigned int clear)
134{
135 unsigned urb_value;
136 int result;
137
138 if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700139 dev_dbg(&dev->dev, "%s - DTR|RTS not being set|cleared\n", __func__);
Bill Pemberton52af9542010-07-29 11:05:41 -0400140 return 0; /* no change */
141 }
142
143 clear &= ~set; /* 'set' takes precedence over 'clear' */
144 urb_value = 0;
145 if (set & TIOCM_DTR)
Bill Pemberton79f203a2010-08-05 17:01:07 -0400146 urb_value |= UART_MCR_DTR;
Bill Pemberton52af9542010-07-29 11:05:41 -0400147 if (set & TIOCM_RTS)
Bill Pemberton79f203a2010-08-05 17:01:07 -0400148 urb_value |= UART_MCR_RTS;
Bill Pemberton52af9542010-07-29 11:05:41 -0400149
Bill Pemberton556f1a02010-08-05 17:01:08 -0400150 result = ssu100_setregister(dev, 0, UART_MCR, urb_value);
Bill Pemberton52af9542010-07-29 11:05:41 -0400151 if (result < 0)
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700152 dev_dbg(&dev->dev, "%s Error from MODEM_CTRL urb\n", __func__);
Bill Pemberton52af9542010-07-29 11:05:41 -0400153
154 return result;
155}
156
157static int ssu100_initdevice(struct usb_device *dev)
158{
159 u8 *data;
160 int result = 0;
161
Bill Pemberton52af9542010-07-29 11:05:41 -0400162 data = kzalloc(3, GFP_KERNEL);
163 if (!data)
164 return -ENOMEM;
165
166 result = ssu100_getdevice(dev, data);
167 if (result < 0) {
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700168 dev_dbg(&dev->dev, "%s - get_device failed %i\n", __func__, result);
Bill Pemberton52af9542010-07-29 11:05:41 -0400169 goto out;
170 }
171
172 data[1] &= ~FULLPWRBIT;
173
174 result = ssu100_setdevice(dev, data);
175 if (result < 0) {
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700176 dev_dbg(&dev->dev, "%s - setdevice failed %i\n", __func__, result);
Bill Pemberton52af9542010-07-29 11:05:41 -0400177 goto out;
178 }
179
180 result = ssu100_control_msg(dev, QT_GET_SET_PREBUF_TRIG_LVL, 128, 0);
181 if (result < 0) {
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700182 dev_dbg(&dev->dev, "%s - set prebuffer level failed %i\n", __func__, result);
Bill Pemberton52af9542010-07-29 11:05:41 -0400183 goto out;
184 }
185
186 result = ssu100_control_msg(dev, QT_SET_ATF, ATC_DISABLED, 0);
187 if (result < 0) {
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700188 dev_dbg(&dev->dev, "%s - set ATFprebuffer level failed %i\n", __func__, result);
Bill Pemberton52af9542010-07-29 11:05:41 -0400189 goto out;
190 }
191
192 result = ssu100_getdevice(dev, data);
193 if (result < 0) {
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700194 dev_dbg(&dev->dev, "%s - get_device failed %i\n", __func__, result);
Bill Pemberton52af9542010-07-29 11:05:41 -0400195 goto out;
196 }
197
198 data[0] &= ~(RR_BITS | DUPMODE_BITS);
199 data[0] |= CLKS_X4;
200 data[1] &= ~(LOOPMODE_BITS);
201 data[1] |= RS232_MODE;
202
203 result = ssu100_setdevice(dev, data);
204 if (result < 0) {
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700205 dev_dbg(&dev->dev, "%s - setdevice failed %i\n", __func__, result);
Bill Pemberton52af9542010-07-29 11:05:41 -0400206 goto out;
207 }
208
209out: kfree(data);
210 return result;
211
212}
213
214
215static void ssu100_set_termios(struct tty_struct *tty,
216 struct usb_serial_port *port,
217 struct ktermios *old_termios)
218{
219 struct usb_device *dev = port->serial->dev;
Alan Coxadc8d742012-07-14 15:31:47 +0100220 struct ktermios *termios = &tty->termios;
Bill Pemberton52af9542010-07-29 11:05:41 -0400221 u16 baud, divisor, remainder;
222 unsigned int cflag = termios->c_cflag;
223 u16 urb_value = 0; /* will hold the new flags */
224 int result;
225
Bill Pemberton52af9542010-07-29 11:05:41 -0400226 if (cflag & PARENB) {
227 if (cflag & PARODD)
Bill Pemberton79f203a2010-08-05 17:01:07 -0400228 urb_value |= UART_LCR_PARITY;
Bill Pemberton52af9542010-07-29 11:05:41 -0400229 else
230 urb_value |= SERIAL_EVEN_PARITY;
231 }
232
233 switch (cflag & CSIZE) {
234 case CS5:
Bill Pemberton79f203a2010-08-05 17:01:07 -0400235 urb_value |= UART_LCR_WLEN5;
Bill Pemberton52af9542010-07-29 11:05:41 -0400236 break;
237 case CS6:
Bill Pemberton79f203a2010-08-05 17:01:07 -0400238 urb_value |= UART_LCR_WLEN6;
Bill Pemberton52af9542010-07-29 11:05:41 -0400239 break;
240 case CS7:
Bill Pemberton79f203a2010-08-05 17:01:07 -0400241 urb_value |= UART_LCR_WLEN7;
Bill Pemberton52af9542010-07-29 11:05:41 -0400242 break;
243 default:
244 case CS8:
Bill Pemberton79f203a2010-08-05 17:01:07 -0400245 urb_value |= UART_LCR_WLEN8;
Bill Pemberton52af9542010-07-29 11:05:41 -0400246 break;
247 }
248
249 baud = tty_get_baud_rate(tty);
250 if (!baud)
251 baud = 9600;
252
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700253 dev_dbg(&port->dev, "%s - got baud = %d\n", __func__, baud);
Bill Pemberton52af9542010-07-29 11:05:41 -0400254
255
256 divisor = MAX_BAUD_RATE / baud;
257 remainder = MAX_BAUD_RATE % baud;
258 if (((remainder * 2) >= baud) && (baud != 110))
259 divisor++;
260
261 urb_value = urb_value << 8;
262
263 result = ssu100_control_msg(dev, QT_GET_SET_UART, divisor, urb_value);
264 if (result < 0)
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700265 dev_dbg(&port->dev, "%s - set uart failed\n", __func__);
Bill Pemberton52af9542010-07-29 11:05:41 -0400266
267 if (cflag & CRTSCTS)
268 result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
269 SERIAL_CRTSCTS, 0);
270 else
271 result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
272 0, 0);
273 if (result < 0)
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700274 dev_dbg(&port->dev, "%s - set HW flow control failed\n", __func__);
Bill Pemberton52af9542010-07-29 11:05:41 -0400275
276 if (I_IXOFF(tty) || I_IXON(tty)) {
277 u16 x = ((u16)(START_CHAR(tty) << 8) | (u16)(STOP_CHAR(tty)));
278
279 result = ssu100_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
280 x, 0);
281 } else
282 result = ssu100_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
283 0, 0);
284
285 if (result < 0)
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700286 dev_dbg(&port->dev, "%s - set SW flow control failed\n", __func__);
Bill Pemberton52af9542010-07-29 11:05:41 -0400287
288}
289
290
291static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
292{
293 struct usb_device *dev = port->serial->dev;
294 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
295 u8 *data;
296 int result;
Bill Pemberton17523052010-08-05 17:01:05 -0400297 unsigned long flags;
Bill Pemberton52af9542010-07-29 11:05:41 -0400298
Bill Pemberton52af9542010-07-29 11:05:41 -0400299 data = kzalloc(2, GFP_KERNEL);
300 if (!data)
301 return -ENOMEM;
302
303 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
304 QT_OPEN_CLOSE_CHANNEL,
305 QT_TRANSFER_IN, 0x01,
306 0, data, 2, 300);
Johan Hovold4d32e362017-01-12 14:56:22 +0100307 if (result < 2) {
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700308 dev_dbg(&port->dev, "%s - open failed %i\n", __func__, result);
Johan Hovold4d32e362017-01-12 14:56:22 +0100309 if (result >= 0)
310 result = -EIO;
Bill Pemberton52af9542010-07-29 11:05:41 -0400311 kfree(data);
312 return result;
313 }
314
Bill Pemberton17523052010-08-05 17:01:05 -0400315 spin_lock_irqsave(&priv->status_lock, flags);
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400316 priv->shadowLSR = data[0];
317 priv->shadowMSR = data[1];
Bill Pemberton17523052010-08-05 17:01:05 -0400318 spin_unlock_irqrestore(&priv->status_lock, flags);
Bill Pemberton52af9542010-07-29 11:05:41 -0400319
320 kfree(data);
321
322/* set to 9600 */
323 result = ssu100_control_msg(dev, QT_GET_SET_UART, 0x30, 0x0300);
324 if (result < 0)
Greg Kroah-Hartman4f0c6412012-09-14 11:50:35 -0700325 dev_dbg(&port->dev, "%s - set uart failed\n", __func__);
Bill Pemberton52af9542010-07-29 11:05:41 -0400326
327 if (tty)
Alan Coxadc8d742012-07-14 15:31:47 +0100328 ssu100_set_termios(tty, port, &tty->termios);
Bill Pemberton52af9542010-07-29 11:05:41 -0400329
330 return usb_serial_generic_open(tty, port);
331}
332
Bill Pemberton52af9542010-07-29 11:05:41 -0400333static int get_serial_info(struct usb_serial_port *port,
334 struct serial_struct __user *retinfo)
335{
336 struct serial_struct tmp;
337
338 if (!retinfo)
339 return -EFAULT;
340
341 memset(&tmp, 0, sizeof(tmp));
Greg Kroah-Hartmane5b1e202013-06-07 11:04:28 -0700342 tmp.line = port->minor;
Bill Pemberton52af9542010-07-29 11:05:41 -0400343 tmp.port = 0;
344 tmp.irq = 0;
345 tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
346 tmp.xmit_fifo_size = port->bulk_out_size;
347 tmp.baud_base = 9600;
348 tmp.close_delay = 5*HZ;
349 tmp.closing_wait = 30*HZ;
350
351 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
352 return -EFAULT;
353 return 0;
354}
355
Alan Cox00a0d0d2011-02-14 16:27:06 +0000356static int ssu100_ioctl(struct tty_struct *tty,
Bill Pemberton52af9542010-07-29 11:05:41 -0400357 unsigned int cmd, unsigned long arg)
358{
359 struct usb_serial_port *port = tty->driver_data;
Bill Pemberton52af9542010-07-29 11:05:41 -0400360
Bill Pemberton52af9542010-07-29 11:05:41 -0400361 switch (cmd) {
362 case TIOCGSERIAL:
363 return get_serial_info(port,
364 (struct serial_struct __user *) arg);
Bill Pemberton52af9542010-07-29 11:05:41 -0400365 default:
366 break;
367 }
368
Bill Pemberton52af9542010-07-29 11:05:41 -0400369 return -ENOIOCTLCMD;
370}
371
Bill Pemberton52af9542010-07-29 11:05:41 -0400372static int ssu100_attach(struct usb_serial *serial)
373{
Johan Hovold638b9e12012-10-17 16:31:34 +0200374 return ssu100_initdevice(serial->dev);
375}
376
377static int ssu100_port_probe(struct usb_serial_port *port)
378{
Bill Pemberton52af9542010-07-29 11:05:41 -0400379 struct ssu100_port_private *priv;
Bill Pemberton52af9542010-07-29 11:05:41 -0400380
Bill Pemberton52af9542010-07-29 11:05:41 -0400381 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
Johan Hovold638b9e12012-10-17 16:31:34 +0200382 if (!priv)
Bill Pemberton52af9542010-07-29 11:05:41 -0400383 return -ENOMEM;
Bill Pemberton52af9542010-07-29 11:05:41 -0400384
Bill Pemberton17523052010-08-05 17:01:05 -0400385 spin_lock_init(&priv->status_lock);
Johan Hovold638b9e12012-10-17 16:31:34 +0200386
Bill Pemberton52af9542010-07-29 11:05:41 -0400387 usb_set_serial_port_data(port, priv);
Bill Pemberton52af9542010-07-29 11:05:41 -0400388
Johan Hovold638b9e12012-10-17 16:31:34 +0200389 return 0;
390}
391
392static int ssu100_port_remove(struct usb_serial_port *port)
393{
394 struct ssu100_port_private *priv;
395
396 priv = usb_get_serial_port_data(port);
397 kfree(priv);
398
399 return 0;
Bill Pemberton52af9542010-07-29 11:05:41 -0400400}
401
Alan Cox60b33c12011-02-14 16:26:14 +0000402static int ssu100_tiocmget(struct tty_struct *tty)
Bill Pemberton52af9542010-07-29 11:05:41 -0400403{
404 struct usb_serial_port *port = tty->driver_data;
405 struct usb_device *dev = port->serial->dev;
406 u8 *d;
407 int r;
408
Bill Pemberton52af9542010-07-29 11:05:41 -0400409 d = kzalloc(2, GFP_KERNEL);
410 if (!d)
411 return -ENOMEM;
412
Bill Pemberton79f203a2010-08-05 17:01:07 -0400413 r = ssu100_getregister(dev, 0, UART_MCR, d);
Bill Pemberton52af9542010-07-29 11:05:41 -0400414 if (r < 0)
415 goto mget_out;
416
Bill Pemberton79f203a2010-08-05 17:01:07 -0400417 r = ssu100_getregister(dev, 0, UART_MSR, d+1);
Bill Pemberton52af9542010-07-29 11:05:41 -0400418 if (r < 0)
419 goto mget_out;
420
Bill Pemberton79f203a2010-08-05 17:01:07 -0400421 r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) |
422 (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) |
423 (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) |
424 (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) |
425 (d[1] & UART_MSR_RI ? TIOCM_RI : 0) |
426 (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0);
Bill Pemberton52af9542010-07-29 11:05:41 -0400427
428mget_out:
429 kfree(d);
430 return r;
431}
432
Alan Cox20b9d172011-02-14 16:26:50 +0000433static int ssu100_tiocmset(struct tty_struct *tty,
Bill Pemberton52af9542010-07-29 11:05:41 -0400434 unsigned int set, unsigned int clear)
435{
436 struct usb_serial_port *port = tty->driver_data;
437 struct usb_device *dev = port->serial->dev;
438
Bill Pemberton52af9542010-07-29 11:05:41 -0400439 return update_mctrl(dev, set, clear);
440}
441
442static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
443{
444 struct usb_device *dev = port->serial->dev;
445
Johan Hovoldb2ca6992013-02-13 17:53:28 +0100446 /* Disable flow control */
447 if (!on) {
448 if (ssu100_setregister(dev, 0, UART_MCR, 0) < 0)
Bill Pemberton52af9542010-07-29 11:05:41 -0400449 dev_err(&port->dev, "error from flowcontrol urb\n");
Bill Pemberton52af9542010-07-29 11:05:41 -0400450 }
Johan Hovoldb2ca6992013-02-13 17:53:28 +0100451 /* drop RTS and DTR */
452 if (on)
453 set_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
454 else
455 clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
Bill Pemberton52af9542010-07-29 11:05:41 -0400456}
457
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400458static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
459{
460 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
461 unsigned long flags;
462
463 spin_lock_irqsave(&priv->status_lock, flags);
464 priv->shadowMSR = msr;
465 spin_unlock_irqrestore(&priv->status_lock, flags);
466
467 if (msr & UART_MSR_ANY_DELTA) {
468 /* update input line counters */
469 if (msr & UART_MSR_DCTS)
Johan Hovold31ecdb62013-03-21 12:37:31 +0100470 port->icount.cts++;
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400471 if (msr & UART_MSR_DDSR)
Johan Hovold31ecdb62013-03-21 12:37:31 +0100472 port->icount.dsr++;
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400473 if (msr & UART_MSR_DDCD)
Johan Hovold31ecdb62013-03-21 12:37:31 +0100474 port->icount.dcd++;
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400475 if (msr & UART_MSR_TERI)
Johan Hovold31ecdb62013-03-21 12:37:31 +0100476 port->icount.rng++;
Johan Hovoldc24c8382013-03-21 12:37:32 +0100477 wake_up_interruptible(&port->port.delta_msr_wait);
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400478 }
479}
480
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400481static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
482 char *tty_flag)
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400483{
484 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
485 unsigned long flags;
486
487 spin_lock_irqsave(&priv->status_lock, flags);
488 priv->shadowLSR = lsr;
489 spin_unlock_irqrestore(&priv->status_lock, flags);
490
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400491 *tty_flag = TTY_NORMAL;
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400492 if (lsr & UART_LSR_BRK_ERROR_BITS) {
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400493 /* we always want to update icount, but we only want to
494 * update tty_flag for one case */
495 if (lsr & UART_LSR_BI) {
Johan Hovold31ecdb62013-03-21 12:37:31 +0100496 port->icount.brk++;
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400497 *tty_flag = TTY_BREAK;
498 usb_serial_handle_break(port);
499 }
500 if (lsr & UART_LSR_PE) {
Johan Hovold31ecdb62013-03-21 12:37:31 +0100501 port->icount.parity++;
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400502 if (*tty_flag == TTY_NORMAL)
503 *tty_flag = TTY_PARITY;
504 }
505 if (lsr & UART_LSR_FE) {
Johan Hovold31ecdb62013-03-21 12:37:31 +0100506 port->icount.frame++;
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400507 if (*tty_flag == TTY_NORMAL)
508 *tty_flag = TTY_FRAME;
509 }
Johan Hovold75bcbf22014-11-18 11:25:21 +0100510 if (lsr & UART_LSR_OE) {
Johan Hovold31ecdb62013-03-21 12:37:31 +0100511 port->icount.overrun++;
Johan Hovold75bcbf22014-11-18 11:25:21 +0100512 tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400513 }
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400514 }
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400515
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400516}
517
Jiri Slaby2e124b42013-01-03 15:53:06 +0100518static void ssu100_process_read_urb(struct urb *urb)
Bill Pemberton52af9542010-07-29 11:05:41 -0400519{
Bill Pembertonf7043ec2010-10-21 14:43:05 -0400520 struct usb_serial_port *port = urb->context;
521 char *packet = (char *)urb->transfer_buffer;
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400522 char flag = TTY_NORMAL;
Bill Pembertonf7043ec2010-10-21 14:43:05 -0400523 u32 len = urb->actual_length;
524 int i;
Bill Pemberton52af9542010-07-29 11:05:41 -0400525 char *ch;
526
Bill Pemberton9b2cef32010-08-05 17:01:06 -0400527 if ((len >= 4) &&
528 (packet[0] == 0x1b) && (packet[1] == 0x1b) &&
Bill Pemberton52af9542010-07-29 11:05:41 -0400529 ((packet[2] == 0x00) || (packet[2] == 0x01))) {
Johan Hovold75bcbf22014-11-18 11:25:21 +0100530 if (packet[2] == 0x00)
Bill Pemberton6b8f1ca2010-08-13 09:59:31 -0400531 ssu100_update_lsr(port, packet[3], &flag);
Bill Pembertonf81c83d2010-08-05 17:01:09 -0400532 if (packet[2] == 0x01)
533 ssu100_update_msr(port, packet[3]);
Bill Pemberton52af9542010-07-29 11:05:41 -0400534
535 len -= 4;
536 ch = packet + 4;
537 } else
538 ch = packet;
539
540 if (!len)
Jiri Slaby2e124b42013-01-03 15:53:06 +0100541 return; /* status only */
Bill Pemberton52af9542010-07-29 11:05:41 -0400542
543 if (port->port.console && port->sysrq) {
544 for (i = 0; i < len; i++, ch++) {
Dmitry Torokhov6ee9f4b2010-08-17 21:15:47 -0700545 if (!usb_serial_handle_sysrq_char(port, *ch))
Jiri Slaby92a19f92013-01-03 15:53:03 +0100546 tty_insert_flip_char(&port->port, *ch, flag);
Bill Pemberton52af9542010-07-29 11:05:41 -0400547 }
548 } else
Jiri Slaby2f693352013-01-03 15:53:02 +0100549 tty_insert_flip_string_fixed_flag(&port->port, ch, flag, len);
Bill Pemberton52af9542010-07-29 11:05:41 -0400550
Jiri Slaby2e124b42013-01-03 15:53:06 +0100551 tty_flip_buffer_push(&port->port);
Bill Pemberton52af9542010-07-29 11:05:41 -0400552}
553
Bill Pemberton52af9542010-07-29 11:05:41 -0400554static struct usb_serial_driver ssu100_device = {
555 .driver = {
556 .owner = THIS_MODULE,
557 .name = "ssu100",
558 },
559 .description = DRIVER_DESC,
560 .id_table = id_table,
Bill Pemberton52af9542010-07-29 11:05:41 -0400561 .num_ports = 1,
Bill Pemberton52af9542010-07-29 11:05:41 -0400562 .open = ssu100_open,
Bill Pemberton52af9542010-07-29 11:05:41 -0400563 .attach = ssu100_attach,
Johan Hovold638b9e12012-10-17 16:31:34 +0200564 .port_probe = ssu100_port_probe,
565 .port_remove = ssu100_port_remove,
Bill Pemberton52af9542010-07-29 11:05:41 -0400566 .dtr_rts = ssu100_dtr_rts,
567 .process_read_urb = ssu100_process_read_urb,
568 .tiocmget = ssu100_tiocmget,
569 .tiocmset = ssu100_tiocmset,
Johan Hovoldc24c8382013-03-21 12:37:32 +0100570 .tiocmiwait = usb_serial_generic_tiocmiwait,
Johan Hovold31ecdb62013-03-21 12:37:31 +0100571 .get_icount = usb_serial_generic_get_icount,
Bill Pemberton52af9542010-07-29 11:05:41 -0400572 .ioctl = ssu100_ioctl,
573 .set_termios = ssu100_set_termios,
Bill Pemberton52af9542010-07-29 11:05:41 -0400574};
575
Alan Sternd8603222012-02-23 14:57:25 -0500576static struct usb_serial_driver * const serial_drivers[] = {
577 &ssu100_device, NULL
578};
579
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -0700580module_usb_serial_driver(serial_drivers, id_table);
Bill Pemberton52af9542010-07-29 11:05:41 -0400581
582MODULE_DESCRIPTION(DRIVER_DESC);
583MODULE_LICENSE("GPL");