1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * spcp8x5 USB to serial adaptor driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2010-2013 Johan Hovold (jhovold@gmail.com)
6*4882a593Smuzhiyun * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn)
7*4882a593Smuzhiyun * Copyright (C) 2006 S1 Corp.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Original driver for 2.6.10 pl2303 driver by
10*4882a593Smuzhiyun * Greg Kroah-Hartman (greg@kroah.com)
11*4882a593Smuzhiyun * Changes for 2.6.20 by Harald Klein <hari@vt100.at>
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/errno.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/tty.h>
17*4882a593Smuzhiyun #include <linux/tty_driver.h>
18*4882a593Smuzhiyun #include <linux/tty_flip.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/spinlock.h>
21*4882a593Smuzhiyun #include <linux/usb.h>
22*4882a593Smuzhiyun #include <linux/usb/serial.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define SPCP825_QUIRK_NO_UART_STATUS 0x01
27*4882a593Smuzhiyun #define SPCP825_QUIRK_NO_WORK_MODE 0x02
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define SPCP8x5_007_VID 0x04FC
30*4882a593Smuzhiyun #define SPCP8x5_007_PID 0x0201
31*4882a593Smuzhiyun #define SPCP8x5_008_VID 0x04fc
32*4882a593Smuzhiyun #define SPCP8x5_008_PID 0x0235
33*4882a593Smuzhiyun #define SPCP8x5_PHILIPS_VID 0x0471
34*4882a593Smuzhiyun #define SPCP8x5_PHILIPS_PID 0x081e
35*4882a593Smuzhiyun #define SPCP8x5_INTERMATIC_VID 0x04FC
36*4882a593Smuzhiyun #define SPCP8x5_INTERMATIC_PID 0x0204
37*4882a593Smuzhiyun #define SPCP8x5_835_VID 0x04fc
38*4882a593Smuzhiyun #define SPCP8x5_835_PID 0x0231
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static const struct usb_device_id id_table[] = {
41*4882a593Smuzhiyun { USB_DEVICE(SPCP8x5_PHILIPS_VID , SPCP8x5_PHILIPS_PID)},
42*4882a593Smuzhiyun { USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},
43*4882a593Smuzhiyun { USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},
44*4882a593Smuzhiyun { USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)},
45*4882a593Smuzhiyun { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID),
46*4882a593Smuzhiyun .driver_info = SPCP825_QUIRK_NO_UART_STATUS |
47*4882a593Smuzhiyun SPCP825_QUIRK_NO_WORK_MODE },
48*4882a593Smuzhiyun { } /* Terminating entry */
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, id_table);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun struct spcp8x5_usb_ctrl_arg {
53*4882a593Smuzhiyun u8 type;
54*4882a593Smuzhiyun u8 cmd;
55*4882a593Smuzhiyun u8 cmd_type;
56*4882a593Smuzhiyun u16 value;
57*4882a593Smuzhiyun u16 index;
58*4882a593Smuzhiyun u16 length;
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* spcp8x5 spec register define */
63*4882a593Smuzhiyun #define MCR_CONTROL_LINE_RTS 0x02
64*4882a593Smuzhiyun #define MCR_CONTROL_LINE_DTR 0x01
65*4882a593Smuzhiyun #define MCR_DTR 0x01
66*4882a593Smuzhiyun #define MCR_RTS 0x02
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun #define MSR_STATUS_LINE_DCD 0x80
69*4882a593Smuzhiyun #define MSR_STATUS_LINE_RI 0x40
70*4882a593Smuzhiyun #define MSR_STATUS_LINE_DSR 0x20
71*4882a593Smuzhiyun #define MSR_STATUS_LINE_CTS 0x10
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* verdor command here , we should define myself */
74*4882a593Smuzhiyun #define SET_DEFAULT 0x40
75*4882a593Smuzhiyun #define SET_DEFAULT_TYPE 0x20
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define SET_UART_FORMAT 0x40
78*4882a593Smuzhiyun #define SET_UART_FORMAT_TYPE 0x21
79*4882a593Smuzhiyun #define SET_UART_FORMAT_SIZE_5 0x00
80*4882a593Smuzhiyun #define SET_UART_FORMAT_SIZE_6 0x01
81*4882a593Smuzhiyun #define SET_UART_FORMAT_SIZE_7 0x02
82*4882a593Smuzhiyun #define SET_UART_FORMAT_SIZE_8 0x03
83*4882a593Smuzhiyun #define SET_UART_FORMAT_STOP_1 0x00
84*4882a593Smuzhiyun #define SET_UART_FORMAT_STOP_2 0x04
85*4882a593Smuzhiyun #define SET_UART_FORMAT_PAR_NONE 0x00
86*4882a593Smuzhiyun #define SET_UART_FORMAT_PAR_ODD 0x10
87*4882a593Smuzhiyun #define SET_UART_FORMAT_PAR_EVEN 0x30
88*4882a593Smuzhiyun #define SET_UART_FORMAT_PAR_MASK 0xD0
89*4882a593Smuzhiyun #define SET_UART_FORMAT_PAR_SPACE 0x90
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun #define GET_UART_STATUS_TYPE 0xc0
92*4882a593Smuzhiyun #define GET_UART_STATUS 0x22
93*4882a593Smuzhiyun #define GET_UART_STATUS_MSR 0x06
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun #define SET_UART_STATUS 0x40
96*4882a593Smuzhiyun #define SET_UART_STATUS_TYPE 0x23
97*4882a593Smuzhiyun #define SET_UART_STATUS_MCR 0x0004
98*4882a593Smuzhiyun #define SET_UART_STATUS_MCR_DTR 0x01
99*4882a593Smuzhiyun #define SET_UART_STATUS_MCR_RTS 0x02
100*4882a593Smuzhiyun #define SET_UART_STATUS_MCR_LOOP 0x10
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun #define SET_WORKING_MODE 0x40
103*4882a593Smuzhiyun #define SET_WORKING_MODE_TYPE 0x24
104*4882a593Smuzhiyun #define SET_WORKING_MODE_U2C 0x00
105*4882a593Smuzhiyun #define SET_WORKING_MODE_RS485 0x01
106*4882a593Smuzhiyun #define SET_WORKING_MODE_PDMA 0x02
107*4882a593Smuzhiyun #define SET_WORKING_MODE_SPP 0x03
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun #define SET_FLOWCTL_CHAR 0x40
110*4882a593Smuzhiyun #define SET_FLOWCTL_CHAR_TYPE 0x25
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun #define GET_VERSION 0xc0
113*4882a593Smuzhiyun #define GET_VERSION_TYPE 0x26
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun #define SET_REGISTER 0x40
116*4882a593Smuzhiyun #define SET_REGISTER_TYPE 0x27
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun #define GET_REGISTER 0xc0
119*4882a593Smuzhiyun #define GET_REGISTER_TYPE 0x28
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun #define SET_RAM 0x40
122*4882a593Smuzhiyun #define SET_RAM_TYPE 0x31
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun #define GET_RAM 0xc0
125*4882a593Smuzhiyun #define GET_RAM_TYPE 0x32
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* how come ??? */
128*4882a593Smuzhiyun #define UART_STATE 0x08
129*4882a593Smuzhiyun #define UART_STATE_TRANSIENT_MASK 0x75
130*4882a593Smuzhiyun #define UART_DCD 0x01
131*4882a593Smuzhiyun #define UART_DSR 0x02
132*4882a593Smuzhiyun #define UART_BREAK_ERROR 0x04
133*4882a593Smuzhiyun #define UART_RING 0x08
134*4882a593Smuzhiyun #define UART_FRAME_ERROR 0x10
135*4882a593Smuzhiyun #define UART_PARITY_ERROR 0x20
136*4882a593Smuzhiyun #define UART_OVERRUN_ERROR 0x40
137*4882a593Smuzhiyun #define UART_CTS 0x80
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun struct spcp8x5_private {
140*4882a593Smuzhiyun unsigned quirks;
141*4882a593Smuzhiyun spinlock_t lock;
142*4882a593Smuzhiyun u8 line_control;
143*4882a593Smuzhiyun };
144*4882a593Smuzhiyun
spcp8x5_probe(struct usb_serial * serial,const struct usb_device_id * id)145*4882a593Smuzhiyun static int spcp8x5_probe(struct usb_serial *serial,
146*4882a593Smuzhiyun const struct usb_device_id *id)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun usb_set_serial_data(serial, (void *)id);
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun return 0;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
spcp8x5_port_probe(struct usb_serial_port * port)153*4882a593Smuzhiyun static int spcp8x5_port_probe(struct usb_serial_port *port)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun const struct usb_device_id *id = usb_get_serial_data(port->serial);
156*4882a593Smuzhiyun struct spcp8x5_private *priv;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun priv = kzalloc(sizeof(*priv), GFP_KERNEL);
159*4882a593Smuzhiyun if (!priv)
160*4882a593Smuzhiyun return -ENOMEM;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun spin_lock_init(&priv->lock);
163*4882a593Smuzhiyun priv->quirks = id->driver_info;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun usb_set_serial_port_data(port, priv);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun port->port.drain_delay = 256;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun return 0;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
spcp8x5_port_remove(struct usb_serial_port * port)172*4882a593Smuzhiyun static int spcp8x5_port_remove(struct usb_serial_port *port)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun struct spcp8x5_private *priv;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun priv = usb_get_serial_port_data(port);
177*4882a593Smuzhiyun kfree(priv);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun return 0;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
spcp8x5_set_ctrl_line(struct usb_serial_port * port,u8 mcr)182*4882a593Smuzhiyun static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun struct spcp8x5_private *priv = usb_get_serial_port_data(port);
185*4882a593Smuzhiyun struct usb_device *dev = port->serial->dev;
186*4882a593Smuzhiyun int retval;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
189*4882a593Smuzhiyun return -EPERM;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
192*4882a593Smuzhiyun SET_UART_STATUS_TYPE, SET_UART_STATUS,
193*4882a593Smuzhiyun mcr, 0x04, NULL, 0, 100);
194*4882a593Smuzhiyun if (retval != 0) {
195*4882a593Smuzhiyun dev_err(&port->dev, "failed to set control lines: %d\n",
196*4882a593Smuzhiyun retval);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun return retval;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
spcp8x5_get_msr(struct usb_serial_port * port,u8 * status)201*4882a593Smuzhiyun static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun struct spcp8x5_private *priv = usb_get_serial_port_data(port);
204*4882a593Smuzhiyun struct usb_device *dev = port->serial->dev;
205*4882a593Smuzhiyun u8 *buf;
206*4882a593Smuzhiyun int ret;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
209*4882a593Smuzhiyun return -EPERM;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun buf = kzalloc(1, GFP_KERNEL);
212*4882a593Smuzhiyun if (!buf)
213*4882a593Smuzhiyun return -ENOMEM;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
216*4882a593Smuzhiyun GET_UART_STATUS, GET_UART_STATUS_TYPE,
217*4882a593Smuzhiyun 0, GET_UART_STATUS_MSR, buf, 1, 100);
218*4882a593Smuzhiyun if (ret < 1) {
219*4882a593Smuzhiyun dev_err(&port->dev, "failed to get modem status: %d\n", ret);
220*4882a593Smuzhiyun if (ret >= 0)
221*4882a593Smuzhiyun ret = -EIO;
222*4882a593Smuzhiyun goto out;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf);
226*4882a593Smuzhiyun *status = *buf;
227*4882a593Smuzhiyun ret = 0;
228*4882a593Smuzhiyun out:
229*4882a593Smuzhiyun kfree(buf);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun return ret;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
spcp8x5_set_work_mode(struct usb_serial_port * port,u16 value,u16 index)234*4882a593Smuzhiyun static void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value,
235*4882a593Smuzhiyun u16 index)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun struct spcp8x5_private *priv = usb_get_serial_port_data(port);
238*4882a593Smuzhiyun struct usb_device *dev = port->serial->dev;
239*4882a593Smuzhiyun int ret;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (priv->quirks & SPCP825_QUIRK_NO_WORK_MODE)
242*4882a593Smuzhiyun return;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
245*4882a593Smuzhiyun SET_WORKING_MODE_TYPE, SET_WORKING_MODE,
246*4882a593Smuzhiyun value, index, NULL, 0, 100);
247*4882a593Smuzhiyun dev_dbg(&port->dev, "value = %#x , index = %#x\n", value, index);
248*4882a593Smuzhiyun if (ret < 0)
249*4882a593Smuzhiyun dev_err(&port->dev, "failed to set work mode: %d\n", ret);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
spcp8x5_carrier_raised(struct usb_serial_port * port)252*4882a593Smuzhiyun static int spcp8x5_carrier_raised(struct usb_serial_port *port)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun u8 msr;
255*4882a593Smuzhiyun int ret;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun ret = spcp8x5_get_msr(port, &msr);
258*4882a593Smuzhiyun if (ret || msr & MSR_STATUS_LINE_DCD)
259*4882a593Smuzhiyun return 1;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun return 0;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
spcp8x5_dtr_rts(struct usb_serial_port * port,int on)264*4882a593Smuzhiyun static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun struct spcp8x5_private *priv = usb_get_serial_port_data(port);
267*4882a593Smuzhiyun unsigned long flags;
268*4882a593Smuzhiyun u8 control;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
271*4882a593Smuzhiyun if (on)
272*4882a593Smuzhiyun priv->line_control = MCR_CONTROL_LINE_DTR
273*4882a593Smuzhiyun | MCR_CONTROL_LINE_RTS;
274*4882a593Smuzhiyun else
275*4882a593Smuzhiyun priv->line_control &= ~ (MCR_CONTROL_LINE_DTR
276*4882a593Smuzhiyun | MCR_CONTROL_LINE_RTS);
277*4882a593Smuzhiyun control = priv->line_control;
278*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
279*4882a593Smuzhiyun spcp8x5_set_ctrl_line(port, control);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
spcp8x5_init_termios(struct tty_struct * tty)282*4882a593Smuzhiyun static void spcp8x5_init_termios(struct tty_struct *tty)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun tty_encode_baud_rate(tty, 115200, 115200);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
spcp8x5_set_termios(struct tty_struct * tty,struct usb_serial_port * port,struct ktermios * old_termios)287*4882a593Smuzhiyun static void spcp8x5_set_termios(struct tty_struct *tty,
288*4882a593Smuzhiyun struct usb_serial_port *port, struct ktermios *old_termios)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun struct usb_serial *serial = port->serial;
291*4882a593Smuzhiyun struct spcp8x5_private *priv = usb_get_serial_port_data(port);
292*4882a593Smuzhiyun unsigned long flags;
293*4882a593Smuzhiyun unsigned int cflag = tty->termios.c_cflag;
294*4882a593Smuzhiyun unsigned short uartdata;
295*4882a593Smuzhiyun unsigned char buf[2] = {0, 0};
296*4882a593Smuzhiyun int baud;
297*4882a593Smuzhiyun int i;
298*4882a593Smuzhiyun u8 control;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /* check that they really want us to change something */
301*4882a593Smuzhiyun if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
302*4882a593Smuzhiyun return;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /* set DTR/RTS active */
305*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
306*4882a593Smuzhiyun control = priv->line_control;
307*4882a593Smuzhiyun if (old_termios && (old_termios->c_cflag & CBAUD) == B0) {
308*4882a593Smuzhiyun priv->line_control |= MCR_DTR;
309*4882a593Smuzhiyun if (!(old_termios->c_cflag & CRTSCTS))
310*4882a593Smuzhiyun priv->line_control |= MCR_RTS;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun if (control != priv->line_control) {
313*4882a593Smuzhiyun control = priv->line_control;
314*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
315*4882a593Smuzhiyun spcp8x5_set_ctrl_line(port, control);
316*4882a593Smuzhiyun } else {
317*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /* Set Baud Rate */
321*4882a593Smuzhiyun baud = tty_get_baud_rate(tty);
322*4882a593Smuzhiyun switch (baud) {
323*4882a593Smuzhiyun case 300: buf[0] = 0x00; break;
324*4882a593Smuzhiyun case 600: buf[0] = 0x01; break;
325*4882a593Smuzhiyun case 1200: buf[0] = 0x02; break;
326*4882a593Smuzhiyun case 2400: buf[0] = 0x03; break;
327*4882a593Smuzhiyun case 4800: buf[0] = 0x04; break;
328*4882a593Smuzhiyun case 9600: buf[0] = 0x05; break;
329*4882a593Smuzhiyun case 19200: buf[0] = 0x07; break;
330*4882a593Smuzhiyun case 38400: buf[0] = 0x09; break;
331*4882a593Smuzhiyun case 57600: buf[0] = 0x0a; break;
332*4882a593Smuzhiyun case 115200: buf[0] = 0x0b; break;
333*4882a593Smuzhiyun case 230400: buf[0] = 0x0c; break;
334*4882a593Smuzhiyun case 460800: buf[0] = 0x0d; break;
335*4882a593Smuzhiyun case 921600: buf[0] = 0x0e; break;
336*4882a593Smuzhiyun /* case 1200000: buf[0] = 0x0f; break; */
337*4882a593Smuzhiyun /* case 2400000: buf[0] = 0x10; break; */
338*4882a593Smuzhiyun case 3000000: buf[0] = 0x11; break;
339*4882a593Smuzhiyun /* case 6000000: buf[0] = 0x12; break; */
340*4882a593Smuzhiyun case 0:
341*4882a593Smuzhiyun case 1000000:
342*4882a593Smuzhiyun buf[0] = 0x0b; break;
343*4882a593Smuzhiyun default:
344*4882a593Smuzhiyun dev_err(&port->dev, "unsupported baudrate, using 9600\n");
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
348*4882a593Smuzhiyun switch (cflag & CSIZE) {
349*4882a593Smuzhiyun case CS5:
350*4882a593Smuzhiyun buf[1] |= SET_UART_FORMAT_SIZE_5;
351*4882a593Smuzhiyun break;
352*4882a593Smuzhiyun case CS6:
353*4882a593Smuzhiyun buf[1] |= SET_UART_FORMAT_SIZE_6;
354*4882a593Smuzhiyun break;
355*4882a593Smuzhiyun case CS7:
356*4882a593Smuzhiyun buf[1] |= SET_UART_FORMAT_SIZE_7;
357*4882a593Smuzhiyun break;
358*4882a593Smuzhiyun default:
359*4882a593Smuzhiyun case CS8:
360*4882a593Smuzhiyun buf[1] |= SET_UART_FORMAT_SIZE_8;
361*4882a593Smuzhiyun break;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun /* Set Stop bit2 : 0:1bit 1:2bit */
365*4882a593Smuzhiyun buf[1] |= (cflag & CSTOPB) ? SET_UART_FORMAT_STOP_2 :
366*4882a593Smuzhiyun SET_UART_FORMAT_STOP_1;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun /* Set Parity bit3-4 01:Odd 11:Even */
369*4882a593Smuzhiyun if (cflag & PARENB) {
370*4882a593Smuzhiyun buf[1] |= (cflag & PARODD) ?
371*4882a593Smuzhiyun SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ;
372*4882a593Smuzhiyun } else {
373*4882a593Smuzhiyun buf[1] |= SET_UART_FORMAT_PAR_NONE;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun uartdata = buf[0] | buf[1]<<8;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
378*4882a593Smuzhiyun SET_UART_FORMAT_TYPE, SET_UART_FORMAT,
379*4882a593Smuzhiyun uartdata, 0, NULL, 0, 100);
380*4882a593Smuzhiyun if (i < 0)
381*4882a593Smuzhiyun dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n",
382*4882a593Smuzhiyun uartdata, i);
383*4882a593Smuzhiyun dev_dbg(&port->dev, "0x21:0x40:0:0 %d\n", i);
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun if (cflag & CRTSCTS) {
386*4882a593Smuzhiyun /* enable hardware flow control */
387*4882a593Smuzhiyun spcp8x5_set_work_mode(port, 0x000a, SET_WORKING_MODE_U2C);
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
spcp8x5_open(struct tty_struct * tty,struct usb_serial_port * port)391*4882a593Smuzhiyun static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun struct usb_serial *serial = port->serial;
394*4882a593Smuzhiyun struct spcp8x5_private *priv = usb_get_serial_port_data(port);
395*4882a593Smuzhiyun int ret;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun usb_clear_halt(serial->dev, port->write_urb->pipe);
398*4882a593Smuzhiyun usb_clear_halt(serial->dev, port->read_urb->pipe);
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
401*4882a593Smuzhiyun 0x09, 0x00,
402*4882a593Smuzhiyun 0x01, 0x00, NULL, 0x00, 100);
403*4882a593Smuzhiyun if (ret)
404*4882a593Smuzhiyun return ret;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun spcp8x5_set_ctrl_line(port, priv->line_control);
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun if (tty)
409*4882a593Smuzhiyun spcp8x5_set_termios(tty, port, NULL);
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun return usb_serial_generic_open(tty, port);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
spcp8x5_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)414*4882a593Smuzhiyun static int spcp8x5_tiocmset(struct tty_struct *tty,
415*4882a593Smuzhiyun unsigned int set, unsigned int clear)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun struct usb_serial_port *port = tty->driver_data;
418*4882a593Smuzhiyun struct spcp8x5_private *priv = usb_get_serial_port_data(port);
419*4882a593Smuzhiyun unsigned long flags;
420*4882a593Smuzhiyun u8 control;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
423*4882a593Smuzhiyun if (set & TIOCM_RTS)
424*4882a593Smuzhiyun priv->line_control |= MCR_RTS;
425*4882a593Smuzhiyun if (set & TIOCM_DTR)
426*4882a593Smuzhiyun priv->line_control |= MCR_DTR;
427*4882a593Smuzhiyun if (clear & TIOCM_RTS)
428*4882a593Smuzhiyun priv->line_control &= ~MCR_RTS;
429*4882a593Smuzhiyun if (clear & TIOCM_DTR)
430*4882a593Smuzhiyun priv->line_control &= ~MCR_DTR;
431*4882a593Smuzhiyun control = priv->line_control;
432*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun return spcp8x5_set_ctrl_line(port, control);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
spcp8x5_tiocmget(struct tty_struct * tty)437*4882a593Smuzhiyun static int spcp8x5_tiocmget(struct tty_struct *tty)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun struct usb_serial_port *port = tty->driver_data;
440*4882a593Smuzhiyun struct spcp8x5_private *priv = usb_get_serial_port_data(port);
441*4882a593Smuzhiyun unsigned long flags;
442*4882a593Smuzhiyun unsigned int mcr;
443*4882a593Smuzhiyun u8 status;
444*4882a593Smuzhiyun unsigned int result;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun result = spcp8x5_get_msr(port, &status);
447*4882a593Smuzhiyun if (result)
448*4882a593Smuzhiyun return result;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
451*4882a593Smuzhiyun mcr = priv->line_control;
452*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
455*4882a593Smuzhiyun | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
456*4882a593Smuzhiyun | ((status & MSR_STATUS_LINE_CTS) ? TIOCM_CTS : 0)
457*4882a593Smuzhiyun | ((status & MSR_STATUS_LINE_DSR) ? TIOCM_DSR : 0)
458*4882a593Smuzhiyun | ((status & MSR_STATUS_LINE_RI) ? TIOCM_RI : 0)
459*4882a593Smuzhiyun | ((status & MSR_STATUS_LINE_DCD) ? TIOCM_CD : 0);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun return result;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun static struct usb_serial_driver spcp8x5_device = {
465*4882a593Smuzhiyun .driver = {
466*4882a593Smuzhiyun .owner = THIS_MODULE,
467*4882a593Smuzhiyun .name = "SPCP8x5",
468*4882a593Smuzhiyun },
469*4882a593Smuzhiyun .id_table = id_table,
470*4882a593Smuzhiyun .num_ports = 1,
471*4882a593Smuzhiyun .num_bulk_in = 1,
472*4882a593Smuzhiyun .num_bulk_out = 1,
473*4882a593Smuzhiyun .open = spcp8x5_open,
474*4882a593Smuzhiyun .dtr_rts = spcp8x5_dtr_rts,
475*4882a593Smuzhiyun .carrier_raised = spcp8x5_carrier_raised,
476*4882a593Smuzhiyun .set_termios = spcp8x5_set_termios,
477*4882a593Smuzhiyun .init_termios = spcp8x5_init_termios,
478*4882a593Smuzhiyun .tiocmget = spcp8x5_tiocmget,
479*4882a593Smuzhiyun .tiocmset = spcp8x5_tiocmset,
480*4882a593Smuzhiyun .probe = spcp8x5_probe,
481*4882a593Smuzhiyun .port_probe = spcp8x5_port_probe,
482*4882a593Smuzhiyun .port_remove = spcp8x5_port_remove,
483*4882a593Smuzhiyun };
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun static struct usb_serial_driver * const serial_drivers[] = {
486*4882a593Smuzhiyun &spcp8x5_device, NULL
487*4882a593Smuzhiyun };
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun module_usb_serial_driver(serial_drivers, id_table);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
492*4882a593Smuzhiyun MODULE_LICENSE("GPL");
493