15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2f7a33e60SBill Pemberton /*
3f7a33e60SBill Pemberton * usb-serial driver for Quatech USB 2 devices
4f7a33e60SBill Pemberton *
5f88e6a30SBill Pemberton * Copyright (C) 2012 Bill Pemberton (wfp5p@virginia.edu)
6f88e6a30SBill Pemberton *
7f7a33e60SBill Pemberton * These devices all have only 1 bulk in and 1 bulk out that is shared
8f7a33e60SBill Pemberton * for all serial ports.
9f7a33e60SBill Pemberton *
10f7a33e60SBill Pemberton */
11f7a33e60SBill Pemberton
12f7a33e60SBill Pemberton #include <asm/unaligned.h>
13f7a33e60SBill Pemberton #include <linux/errno.h>
14f7a33e60SBill Pemberton #include <linux/slab.h>
15f7a33e60SBill Pemberton #include <linux/tty.h>
16f7a33e60SBill Pemberton #include <linux/tty_driver.h>
17f7a33e60SBill Pemberton #include <linux/tty_flip.h>
18f7a33e60SBill Pemberton #include <linux/module.h>
19f7a33e60SBill Pemberton #include <linux/serial.h>
20f7a33e60SBill Pemberton #include <linux/usb.h>
21f7a33e60SBill Pemberton #include <linux/usb/serial.h>
22f7a33e60SBill Pemberton #include <linux/serial_reg.h>
23f7a33e60SBill Pemberton #include <linux/uaccess.h>
24f7a33e60SBill Pemberton
25f7a33e60SBill Pemberton /* default urb timeout for usb operations */
26f7a33e60SBill Pemberton #define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT
27f7a33e60SBill Pemberton
28f7a33e60SBill Pemberton #define QT_OPEN_CLOSE_CHANNEL 0xca
29f7a33e60SBill Pemberton #define QT_SET_GET_DEVICE 0xc2
30f7a33e60SBill Pemberton #define QT_SET_GET_REGISTER 0xc0
31f7a33e60SBill Pemberton #define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
32f7a33e60SBill Pemberton #define QT_SET_ATF 0xcd
33f7a33e60SBill Pemberton #define QT_TRANSFER_IN 0xc0
34f7a33e60SBill Pemberton #define QT_HW_FLOW_CONTROL_MASK 0xc5
35f7a33e60SBill Pemberton #define QT_SW_FLOW_CONTROL_MASK 0xc6
36f7a33e60SBill Pemberton #define QT2_BREAK_CONTROL 0xc8
37f7a33e60SBill Pemberton #define QT2_GET_SET_UART 0xc1
38f7a33e60SBill Pemberton #define QT2_FLUSH_DEVICE 0xc4
39f7a33e60SBill Pemberton #define QT2_GET_SET_QMCR 0xe1
40f7a33e60SBill Pemberton #define QT2_QMCR_RS232 0x40
41f7a33e60SBill Pemberton #define QT2_QMCR_RS422 0x10
42f7a33e60SBill Pemberton
43f7a33e60SBill Pemberton #define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS)
44f7a33e60SBill Pemberton
45f7a33e60SBill Pemberton #define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR)
46f7a33e60SBill Pemberton
47f7a33e60SBill Pemberton /* status bytes for the device */
48f7a33e60SBill Pemberton #define QT2_CONTROL_BYTE 0x1b
49f7a33e60SBill Pemberton #define QT2_LINE_STATUS 0x00 /* following 1 byte is line status */
50f7a33e60SBill Pemberton #define QT2_MODEM_STATUS 0x01 /* following 1 byte is modem status */
51f7a33e60SBill Pemberton #define QT2_XMIT_HOLD 0x02 /* following 2 bytes are ?? */
52f7a33e60SBill Pemberton #define QT2_CHANGE_PORT 0x03 /* following 1 byte is port to change to */
53f7a33e60SBill Pemberton #define QT2_REC_FLUSH 0x04 /* no following info */
54f7a33e60SBill Pemberton #define QT2_XMIT_FLUSH 0x05 /* no following info */
55f7a33e60SBill Pemberton #define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */
56f7a33e60SBill Pemberton
57f7a33e60SBill Pemberton #define MAX_BAUD_RATE 921600
58f7a33e60SBill Pemberton #define DEFAULT_BAUD_RATE 9600
59f7a33e60SBill Pemberton
6004480671SJohan Hovold #define QT2_READ_BUFFER_SIZE 512 /* size of read buffer */
61f7a33e60SBill Pemberton #define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */
62f7a33e60SBill Pemberton #define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */
63f7a33e60SBill Pemberton
64f7a33e60SBill Pemberton #define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver"
65f7a33e60SBill Pemberton
66f7a33e60SBill Pemberton #define USB_VENDOR_ID_QUATECH 0x061d
67f7a33e60SBill Pemberton #define QUATECH_SSU2_100 0xC120 /* RS232 single port */
68f7a33e60SBill Pemberton #define QUATECH_DSU2_100 0xC140 /* RS232 dual port */
69f7a33e60SBill Pemberton #define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */
70f7a33e60SBill Pemberton #define QUATECH_QSU2_100 0xC160 /* RS232 four port */
71f7a33e60SBill Pemberton #define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */
72f7a33e60SBill Pemberton #define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */
73f7a33e60SBill Pemberton #define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */
74f7a33e60SBill Pemberton
75f7a33e60SBill Pemberton struct qt2_device_detail {
76f7a33e60SBill Pemberton int product_id;
77f7a33e60SBill Pemberton int num_ports;
78f7a33e60SBill Pemberton };
79f7a33e60SBill Pemberton
80f7a33e60SBill Pemberton #define QT_DETAILS(prod, ports) \
81f7a33e60SBill Pemberton .product_id = (prod), \
82f7a33e60SBill Pemberton .num_ports = (ports)
83f7a33e60SBill Pemberton
84f7a33e60SBill Pemberton static const struct qt2_device_detail qt2_device_details[] = {
85f7a33e60SBill Pemberton {QT_DETAILS(QUATECH_SSU2_100, 1)},
86f7a33e60SBill Pemberton {QT_DETAILS(QUATECH_DSU2_400, 2)},
87f7a33e60SBill Pemberton {QT_DETAILS(QUATECH_DSU2_100, 2)},
88f7a33e60SBill Pemberton {QT_DETAILS(QUATECH_QSU2_400, 4)},
89f7a33e60SBill Pemberton {QT_DETAILS(QUATECH_QSU2_100, 4)},
90f7a33e60SBill Pemberton {QT_DETAILS(QUATECH_ESU2_400, 8)},
91f7a33e60SBill Pemberton {QT_DETAILS(QUATECH_ESU2_100, 8)},
92f7a33e60SBill Pemberton {QT_DETAILS(0, 0)} /* Terminating entry */
93f7a33e60SBill Pemberton };
94f7a33e60SBill Pemberton
95f7a33e60SBill Pemberton static const struct usb_device_id id_table[] = {
96f7a33e60SBill Pemberton {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
97f7a33e60SBill Pemberton {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
98f7a33e60SBill Pemberton {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
99f7a33e60SBill Pemberton {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)},
100f7a33e60SBill Pemberton {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)},
101f7a33e60SBill Pemberton {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)},
102f7a33e60SBill Pemberton {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)},
103f7a33e60SBill Pemberton {} /* Terminating entry */
104f7a33e60SBill Pemberton };
105f7a33e60SBill Pemberton MODULE_DEVICE_TABLE(usb, id_table);
106f7a33e60SBill Pemberton
107f7a33e60SBill Pemberton struct qt2_serial_private {
108f7a33e60SBill Pemberton unsigned char current_port; /* current port for incoming data */
109f7a33e60SBill Pemberton
110f7a33e60SBill Pemberton struct urb *read_urb; /* shared among all ports */
11104480671SJohan Hovold char *read_buffer;
112f7a33e60SBill Pemberton };
113f7a33e60SBill Pemberton
114f7a33e60SBill Pemberton struct qt2_port_private {
115f7a33e60SBill Pemberton u8 device_port;
116f7a33e60SBill Pemberton
117f7a33e60SBill Pemberton spinlock_t urb_lock;
118f7a33e60SBill Pemberton bool urb_in_use;
119f7a33e60SBill Pemberton struct urb *write_urb;
120cbf30a91SJohan Hovold char *write_buffer;
121f7a33e60SBill Pemberton
122f7a33e60SBill Pemberton spinlock_t lock;
123f7a33e60SBill Pemberton u8 shadowLSR;
124f7a33e60SBill Pemberton u8 shadowMSR;
125f7a33e60SBill Pemberton
126f7a33e60SBill Pemberton struct usb_serial_port *port;
127f7a33e60SBill Pemberton };
128f7a33e60SBill Pemberton
129f7a33e60SBill Pemberton static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch);
130f7a33e60SBill Pemberton static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch);
131f7a33e60SBill Pemberton static void qt2_write_bulk_callback(struct urb *urb);
132f7a33e60SBill Pemberton static void qt2_read_bulk_callback(struct urb *urb);
133f7a33e60SBill Pemberton
qt2_release(struct usb_serial * serial)134f7a33e60SBill Pemberton static void qt2_release(struct usb_serial *serial)
135f7a33e60SBill Pemberton {
13640d04738SJohan Hovold struct qt2_serial_private *serial_priv;
137f7a33e60SBill Pemberton
13840d04738SJohan Hovold serial_priv = usb_get_serial_data(serial);
139f7a33e60SBill Pemberton
140028c49f5SJohan Hovold usb_kill_urb(serial_priv->read_urb);
14140d04738SJohan Hovold usb_free_urb(serial_priv->read_urb);
14204480671SJohan Hovold kfree(serial_priv->read_buffer);
14340d04738SJohan Hovold kfree(serial_priv);
144f7a33e60SBill Pemberton }
145f7a33e60SBill Pemberton
calc_baud_divisor(int baudrate)146f7a33e60SBill Pemberton static inline int calc_baud_divisor(int baudrate)
147f7a33e60SBill Pemberton {
148f7a33e60SBill Pemberton int divisor, rem;
149f7a33e60SBill Pemberton
150f7a33e60SBill Pemberton divisor = MAX_BAUD_RATE / baudrate;
151f7a33e60SBill Pemberton rem = MAX_BAUD_RATE % baudrate;
152f7a33e60SBill Pemberton /* Round to nearest divisor */
153f7a33e60SBill Pemberton if (((rem * 2) >= baudrate) && (baudrate != 110))
154f7a33e60SBill Pemberton divisor++;
155f7a33e60SBill Pemberton
156f7a33e60SBill Pemberton return divisor;
157f7a33e60SBill Pemberton }
158f7a33e60SBill Pemberton
qt2_set_port_config(struct usb_device * dev,unsigned char port_number,u16 baudrate,u16 lcr)159f7a33e60SBill Pemberton static inline int qt2_set_port_config(struct usb_device *dev,
160f7a33e60SBill Pemberton unsigned char port_number,
161f7a33e60SBill Pemberton u16 baudrate, u16 lcr)
162f7a33e60SBill Pemberton {
163f7a33e60SBill Pemberton int divisor = calc_baud_divisor(baudrate);
164f7a33e60SBill Pemberton u16 index = ((u16) (lcr << 8) | (u16) (port_number));
165f7a33e60SBill Pemberton
166f7a33e60SBill Pemberton return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
167f7a33e60SBill Pemberton QT2_GET_SET_UART, 0x40,
168f7a33e60SBill Pemberton divisor, index, NULL, 0, QT2_USB_TIMEOUT);
169f7a33e60SBill Pemberton }
170f7a33e60SBill Pemberton
qt2_control_msg(struct usb_device * dev,u8 request,u16 data,u16 index)171f7a33e60SBill Pemberton static inline int qt2_control_msg(struct usb_device *dev,
172f7a33e60SBill Pemberton u8 request, u16 data, u16 index)
173f7a33e60SBill Pemberton {
174f7a33e60SBill Pemberton return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
175f7a33e60SBill Pemberton request, 0x40, data, index,
176f7a33e60SBill Pemberton NULL, 0, QT2_USB_TIMEOUT);
177f7a33e60SBill Pemberton }
178f7a33e60SBill Pemberton
qt2_getregister(struct usb_device * dev,u8 uart,u8 reg,u8 * data)179f7a33e60SBill Pemberton static inline int qt2_getregister(struct usb_device *dev,
180f7a33e60SBill Pemberton u8 uart,
181f7a33e60SBill Pemberton u8 reg,
182f7a33e60SBill Pemberton u8 *data)
183f7a33e60SBill Pemberton {
1848c34cb8dSJohan Hovold int ret;
1858c34cb8dSJohan Hovold
1868c34cb8dSJohan Hovold ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
187f7a33e60SBill Pemberton QT_SET_GET_REGISTER, 0xc0, reg,
188f7a33e60SBill Pemberton uart, data, sizeof(*data), QT2_USB_TIMEOUT);
1893391ca1dSChengguang Xu if (ret < (int)sizeof(*data)) {
1908c34cb8dSJohan Hovold if (ret >= 0)
1918c34cb8dSJohan Hovold ret = -EIO;
1928c34cb8dSJohan Hovold }
193f7a33e60SBill Pemberton
1948c34cb8dSJohan Hovold return ret;
195f7a33e60SBill Pemberton }
196f7a33e60SBill Pemberton
qt2_setregister(struct usb_device * dev,u8 uart,u8 reg,u16 data)197f7a33e60SBill Pemberton static inline int qt2_setregister(struct usb_device *dev,
198f7a33e60SBill Pemberton u8 uart, u8 reg, u16 data)
199f7a33e60SBill Pemberton {
200f7a33e60SBill Pemberton u16 value = (data << 8) | reg;
201f7a33e60SBill Pemberton
202f7a33e60SBill Pemberton return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
203f7a33e60SBill Pemberton QT_SET_GET_REGISTER, 0x40, value, uart,
204f7a33e60SBill Pemberton NULL, 0, QT2_USB_TIMEOUT);
205f7a33e60SBill Pemberton }
206f7a33e60SBill Pemberton
update_mctrl(struct qt2_port_private * port_priv,unsigned int set,unsigned int clear)207f7a33e60SBill Pemberton static inline int update_mctrl(struct qt2_port_private *port_priv,
208f7a33e60SBill Pemberton unsigned int set, unsigned int clear)
209f7a33e60SBill Pemberton {
210f7a33e60SBill Pemberton struct usb_serial_port *port = port_priv->port;
211f7a33e60SBill Pemberton struct usb_device *dev = port->serial->dev;
212f7a33e60SBill Pemberton unsigned urb_value;
213f7a33e60SBill Pemberton int status;
214f7a33e60SBill Pemberton
215f7a33e60SBill Pemberton if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
216f7a33e60SBill Pemberton dev_dbg(&port->dev,
217f7a33e60SBill Pemberton "update_mctrl - DTR|RTS not being set|cleared\n");
218f7a33e60SBill Pemberton return 0; /* no change */
219f7a33e60SBill Pemberton }
220f7a33e60SBill Pemberton
221f7a33e60SBill Pemberton clear &= ~set; /* 'set' takes precedence over 'clear' */
222f7a33e60SBill Pemberton urb_value = 0;
223f7a33e60SBill Pemberton if (set & TIOCM_DTR)
224f7a33e60SBill Pemberton urb_value |= UART_MCR_DTR;
225f7a33e60SBill Pemberton if (set & TIOCM_RTS)
226f7a33e60SBill Pemberton urb_value |= UART_MCR_RTS;
227f7a33e60SBill Pemberton
228f7a33e60SBill Pemberton status = qt2_setregister(dev, port_priv->device_port, UART_MCR,
229f7a33e60SBill Pemberton urb_value);
230f7a33e60SBill Pemberton if (status < 0)
231f7a33e60SBill Pemberton dev_err(&port->dev,
232f7a33e60SBill Pemberton "update_mctrl - Error from MODEM_CTRL urb: %i\n",
233f7a33e60SBill Pemberton status);
234f7a33e60SBill Pemberton return status;
235f7a33e60SBill Pemberton }
236f7a33e60SBill Pemberton
qt2_calc_num_ports(struct usb_serial * serial,struct usb_serial_endpoints * epds)23707814246SJohan Hovold static int qt2_calc_num_ports(struct usb_serial *serial,
23807814246SJohan Hovold struct usb_serial_endpoints *epds)
239f7a33e60SBill Pemberton {
240f7a33e60SBill Pemberton struct qt2_device_detail d;
241f7a33e60SBill Pemberton int i;
242f7a33e60SBill Pemberton
243f7a33e60SBill Pemberton for (i = 0; d = qt2_device_details[i], d.product_id != 0; i++) {
244f7a33e60SBill Pemberton if (d.product_id == le16_to_cpu(serial->dev->descriptor.idProduct))
245f7a33e60SBill Pemberton return d.num_ports;
246f7a33e60SBill Pemberton }
247f7a33e60SBill Pemberton
248f7a33e60SBill Pemberton /* we didn't recognize the device */
249f7a33e60SBill Pemberton dev_err(&serial->dev->dev,
250f7a33e60SBill Pemberton "don't know the number of ports, assuming 1\n");
251f7a33e60SBill Pemberton
252f7a33e60SBill Pemberton return 1;
253f7a33e60SBill Pemberton }
254f7a33e60SBill Pemberton
qt2_set_termios(struct tty_struct * tty,struct usb_serial_port * port,const struct ktermios * old_termios)255f7a33e60SBill Pemberton static void qt2_set_termios(struct tty_struct *tty,
256f7a33e60SBill Pemberton struct usb_serial_port *port,
257f6d47fe5SIlpo Järvinen const struct ktermios *old_termios)
258f7a33e60SBill Pemberton {
259f7a33e60SBill Pemberton struct usb_device *dev = port->serial->dev;
260f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
261adc8d746SAlan Cox struct ktermios *termios = &tty->termios;
262f7a33e60SBill Pemberton u16 baud;
263f7a33e60SBill Pemberton unsigned int cflag = termios->c_cflag;
264f7a33e60SBill Pemberton u16 new_lcr = 0;
265f7a33e60SBill Pemberton int status;
266f7a33e60SBill Pemberton
267f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(port);
268f7a33e60SBill Pemberton
269f7a33e60SBill Pemberton if (cflag & PARENB) {
270f7a33e60SBill Pemberton if (cflag & PARODD)
271f7a33e60SBill Pemberton new_lcr |= UART_LCR_PARITY;
272f7a33e60SBill Pemberton else
273f7a33e60SBill Pemberton new_lcr |= SERIAL_EVEN_PARITY;
274f7a33e60SBill Pemberton }
275f7a33e60SBill Pemberton
2765e1440bcSJiri Slaby new_lcr |= UART_LCR_WLEN(tty_get_char_size(cflag));
277f7a33e60SBill Pemberton
278f7a33e60SBill Pemberton baud = tty_get_baud_rate(tty);
279f7a33e60SBill Pemberton if (!baud)
280f7a33e60SBill Pemberton baud = 9600;
281f7a33e60SBill Pemberton
282f7a33e60SBill Pemberton status = qt2_set_port_config(dev, port_priv->device_port, baud,
283f7a33e60SBill Pemberton new_lcr);
284f7a33e60SBill Pemberton if (status < 0)
285f7a33e60SBill Pemberton dev_err(&port->dev, "%s - qt2_set_port_config failed: %i\n",
286f7a33e60SBill Pemberton __func__, status);
287f7a33e60SBill Pemberton
288f7a33e60SBill Pemberton if (cflag & CRTSCTS)
289f7a33e60SBill Pemberton status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
290f7a33e60SBill Pemberton SERIAL_CRTSCTS,
291f7a33e60SBill Pemberton port_priv->device_port);
292f7a33e60SBill Pemberton else
293f7a33e60SBill Pemberton status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
294f7a33e60SBill Pemberton 0, port_priv->device_port);
295f7a33e60SBill Pemberton if (status < 0)
296f7a33e60SBill Pemberton dev_err(&port->dev, "%s - set HW flow control failed: %i\n",
297f7a33e60SBill Pemberton __func__, status);
298f7a33e60SBill Pemberton
299f7a33e60SBill Pemberton if (I_IXOFF(tty) || I_IXON(tty)) {
300f7a33e60SBill Pemberton u16 x = ((u16) (START_CHAR(tty) << 8) | (u16) (STOP_CHAR(tty)));
301f7a33e60SBill Pemberton
302f7a33e60SBill Pemberton status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
303f7a33e60SBill Pemberton x, port_priv->device_port);
304f7a33e60SBill Pemberton } else
305f7a33e60SBill Pemberton status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
306f7a33e60SBill Pemberton 0, port_priv->device_port);
307f7a33e60SBill Pemberton
308f7a33e60SBill Pemberton if (status < 0)
309f7a33e60SBill Pemberton dev_err(&port->dev, "%s - set SW flow control failed: %i\n",
310f7a33e60SBill Pemberton __func__, status);
311f7a33e60SBill Pemberton
312f7a33e60SBill Pemberton }
313f7a33e60SBill Pemberton
qt2_open(struct tty_struct * tty,struct usb_serial_port * port)314f7a33e60SBill Pemberton static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
315f7a33e60SBill Pemberton {
316f7a33e60SBill Pemberton struct usb_serial *serial;
317f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
318f7a33e60SBill Pemberton u8 *data;
319f7a33e60SBill Pemberton u16 device_port;
320f7a33e60SBill Pemberton int status;
321f7a33e60SBill Pemberton unsigned long flags;
322f7a33e60SBill Pemberton
3231143832eSGreg Kroah-Hartman device_port = port->port_number;
324f7a33e60SBill Pemberton
325f7a33e60SBill Pemberton serial = port->serial;
326f7a33e60SBill Pemberton
327f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(port);
328f7a33e60SBill Pemberton
329f7a33e60SBill Pemberton /* set the port to RS232 mode */
330f7a33e60SBill Pemberton status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR,
331f7a33e60SBill Pemberton QT2_QMCR_RS232, device_port);
332f7a33e60SBill Pemberton if (status < 0) {
333f7a33e60SBill Pemberton dev_err(&port->dev,
334f7a33e60SBill Pemberton "%s failed to set RS232 mode for port %i error %i\n",
335f7a33e60SBill Pemberton __func__, device_port, status);
336f7a33e60SBill Pemberton return status;
337f7a33e60SBill Pemberton }
338f7a33e60SBill Pemberton
339f7a33e60SBill Pemberton data = kzalloc(2, GFP_KERNEL);
340f7a33e60SBill Pemberton if (!data)
341f7a33e60SBill Pemberton return -ENOMEM;
342f7a33e60SBill Pemberton
343f7a33e60SBill Pemberton /* open the port */
344f7a33e60SBill Pemberton status = usb_control_msg(serial->dev,
345f7a33e60SBill Pemberton usb_rcvctrlpipe(serial->dev, 0),
346f7a33e60SBill Pemberton QT_OPEN_CLOSE_CHANNEL,
347f7a33e60SBill Pemberton 0xc0, 0,
348f7a33e60SBill Pemberton device_port, data, 2, QT2_USB_TIMEOUT);
349f7a33e60SBill Pemberton
3508c34cb8dSJohan Hovold if (status < 2) {
351d9a38a87SJohan Hovold dev_err(&port->dev, "%s - open port failed %i\n", __func__,
352f7a33e60SBill Pemberton status);
3538c34cb8dSJohan Hovold if (status >= 0)
3548c34cb8dSJohan Hovold status = -EIO;
355f7a33e60SBill Pemberton kfree(data);
356f7a33e60SBill Pemberton return status;
357f7a33e60SBill Pemberton }
358f7a33e60SBill Pemberton
359f7a33e60SBill Pemberton spin_lock_irqsave(&port_priv->lock, flags);
360f7a33e60SBill Pemberton port_priv->shadowLSR = data[0];
361f7a33e60SBill Pemberton port_priv->shadowMSR = data[1];
362f7a33e60SBill Pemberton spin_unlock_irqrestore(&port_priv->lock, flags);
363f7a33e60SBill Pemberton
364f7a33e60SBill Pemberton kfree(data);
365f7a33e60SBill Pemberton
366f7a33e60SBill Pemberton /* set to default speed and 8bit word size */
367f7a33e60SBill Pemberton status = qt2_set_port_config(serial->dev, device_port,
368f7a33e60SBill Pemberton DEFAULT_BAUD_RATE, UART_LCR_WLEN8);
369f7a33e60SBill Pemberton if (status < 0) {
3701143832eSGreg Kroah-Hartman dev_err(&port->dev, "%s - initial setup failed (%i)\n",
3711143832eSGreg Kroah-Hartman __func__, device_port);
372f7a33e60SBill Pemberton return status;
373f7a33e60SBill Pemberton }
374f7a33e60SBill Pemberton
375f7a33e60SBill Pemberton port_priv->device_port = (u8) device_port;
376f7a33e60SBill Pemberton
377f7a33e60SBill Pemberton if (tty)
378adc8d746SAlan Cox qt2_set_termios(tty, port, &tty->termios);
379f7a33e60SBill Pemberton
380f7a33e60SBill Pemberton return 0;
381f7a33e60SBill Pemberton
382f7a33e60SBill Pemberton }
383f7a33e60SBill Pemberton
qt2_close(struct usb_serial_port * port)384f7a33e60SBill Pemberton static void qt2_close(struct usb_serial_port *port)
385f7a33e60SBill Pemberton {
386f7a33e60SBill Pemberton struct usb_serial *serial;
387f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
388f7a33e60SBill Pemberton int i;
389f7a33e60SBill Pemberton
390f7a33e60SBill Pemberton serial = port->serial;
391f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(port);
392f7a33e60SBill Pemberton
393f7a33e60SBill Pemberton usb_kill_urb(port_priv->write_urb);
394f7a33e60SBill Pemberton
395f7a33e60SBill Pemberton /* flush the port transmit buffer */
396f7a33e60SBill Pemberton i = usb_control_msg(serial->dev,
397eb8dbe80SJohan Hovold usb_sndctrlpipe(serial->dev, 0),
398f7a33e60SBill Pemberton QT2_FLUSH_DEVICE, 0x40, 1,
399f7a33e60SBill Pemberton port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
400f7a33e60SBill Pemberton
401f7a33e60SBill Pemberton if (i < 0)
402f7a33e60SBill Pemberton dev_err(&port->dev, "%s - transmit buffer flush failed: %i\n",
403f7a33e60SBill Pemberton __func__, i);
404f7a33e60SBill Pemberton
405f7a33e60SBill Pemberton /* flush the port receive buffer */
406f7a33e60SBill Pemberton i = usb_control_msg(serial->dev,
407eb8dbe80SJohan Hovold usb_sndctrlpipe(serial->dev, 0),
408f7a33e60SBill Pemberton QT2_FLUSH_DEVICE, 0x40, 0,
409f7a33e60SBill Pemberton port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
410f7a33e60SBill Pemberton
411f7a33e60SBill Pemberton if (i < 0)
412f7a33e60SBill Pemberton dev_err(&port->dev, "%s - receive buffer flush failed: %i\n",
413f7a33e60SBill Pemberton __func__, i);
414f7a33e60SBill Pemberton
415f7a33e60SBill Pemberton /* close the port */
416f7a33e60SBill Pemberton i = usb_control_msg(serial->dev,
417f7a33e60SBill Pemberton usb_sndctrlpipe(serial->dev, 0),
418f7a33e60SBill Pemberton QT_OPEN_CLOSE_CHANNEL,
419f7a33e60SBill Pemberton 0x40, 0,
420f7a33e60SBill Pemberton port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
421f7a33e60SBill Pemberton
422f7a33e60SBill Pemberton if (i < 0)
423f7a33e60SBill Pemberton dev_err(&port->dev, "%s - close port failed %i\n",
424f7a33e60SBill Pemberton __func__, i);
425f7a33e60SBill Pemberton }
426f7a33e60SBill Pemberton
qt2_disconnect(struct usb_serial * serial)427f7a33e60SBill Pemberton static void qt2_disconnect(struct usb_serial *serial)
428f7a33e60SBill Pemberton {
429f7a33e60SBill Pemberton struct qt2_serial_private *serial_priv = usb_get_serial_data(serial);
430f7a33e60SBill Pemberton
431f7a33e60SBill Pemberton usb_kill_urb(serial_priv->read_urb);
432f7a33e60SBill Pemberton }
433f7a33e60SBill Pemberton
qt2_process_status(struct usb_serial_port * port,unsigned char * ch)434f7a33e60SBill Pemberton static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch)
435f7a33e60SBill Pemberton {
436f7a33e60SBill Pemberton switch (*ch) {
437f7a33e60SBill Pemberton case QT2_LINE_STATUS:
438f7a33e60SBill Pemberton qt2_update_lsr(port, ch + 1);
439f7a33e60SBill Pemberton break;
440f7a33e60SBill Pemberton case QT2_MODEM_STATUS:
441f7a33e60SBill Pemberton qt2_update_msr(port, ch + 1);
442f7a33e60SBill Pemberton break;
443f7a33e60SBill Pemberton }
444f7a33e60SBill Pemberton }
445f7a33e60SBill Pemberton
qt2_process_read_urb(struct urb * urb)4460e357899SSachin Kamat static void qt2_process_read_urb(struct urb *urb)
447f7a33e60SBill Pemberton {
448f7a33e60SBill Pemberton struct usb_serial *serial;
449f7a33e60SBill Pemberton struct qt2_serial_private *serial_priv;
450f7a33e60SBill Pemberton struct usb_serial_port *port;
451f7a33e60SBill Pemberton bool escapeflag;
452f7a33e60SBill Pemberton unsigned char *ch;
453f7a33e60SBill Pemberton int i;
454f7a33e60SBill Pemberton unsigned char newport;
455f7a33e60SBill Pemberton int len = urb->actual_length;
456f7a33e60SBill Pemberton
457f7a33e60SBill Pemberton if (!len)
458f7a33e60SBill Pemberton return;
459f7a33e60SBill Pemberton
460f7a33e60SBill Pemberton ch = urb->transfer_buffer;
461f7a33e60SBill Pemberton serial = urb->context;
462f7a33e60SBill Pemberton serial_priv = usb_get_serial_data(serial);
463f7a33e60SBill Pemberton port = serial->port[serial_priv->current_port];
464f7a33e60SBill Pemberton
465f7a33e60SBill Pemberton for (i = 0; i < urb->actual_length; i++) {
466f7a33e60SBill Pemberton ch = (unsigned char *)urb->transfer_buffer + i;
467f7a33e60SBill Pemberton if ((i <= (len - 3)) &&
468f7a33e60SBill Pemberton (*ch == QT2_CONTROL_BYTE) &&
469f7a33e60SBill Pemberton (*(ch + 1) == QT2_CONTROL_BYTE)) {
470f7a33e60SBill Pemberton escapeflag = false;
471f7a33e60SBill Pemberton switch (*(ch + 2)) {
472f7a33e60SBill Pemberton case QT2_LINE_STATUS:
473f7a33e60SBill Pemberton case QT2_MODEM_STATUS:
474f7a33e60SBill Pemberton if (i > (len - 4)) {
475f7a33e60SBill Pemberton dev_warn(&port->dev,
476f7a33e60SBill Pemberton "%s - status message too short\n",
477f7a33e60SBill Pemberton __func__);
478f7a33e60SBill Pemberton break;
479f7a33e60SBill Pemberton }
480f7a33e60SBill Pemberton qt2_process_status(port, ch + 2);
481f7a33e60SBill Pemberton i += 3;
482f7a33e60SBill Pemberton escapeflag = true;
483f7a33e60SBill Pemberton break;
484f7a33e60SBill Pemberton case QT2_XMIT_HOLD:
485f7a33e60SBill Pemberton if (i > (len - 5)) {
486f7a33e60SBill Pemberton dev_warn(&port->dev,
487f7a33e60SBill Pemberton "%s - xmit_empty message too short\n",
488f7a33e60SBill Pemberton __func__);
489f7a33e60SBill Pemberton break;
490f7a33e60SBill Pemberton }
491b83076a9SJohan Hovold /* bytes_written = (ch[1] << 4) + ch[0]; */
492f7a33e60SBill Pemberton i += 4;
493f7a33e60SBill Pemberton escapeflag = true;
494f7a33e60SBill Pemberton break;
495f7a33e60SBill Pemberton case QT2_CHANGE_PORT:
496f7a33e60SBill Pemberton if (i > (len - 4)) {
497f7a33e60SBill Pemberton dev_warn(&port->dev,
498f7a33e60SBill Pemberton "%s - change_port message too short\n",
499f7a33e60SBill Pemberton __func__);
500f7a33e60SBill Pemberton break;
501f7a33e60SBill Pemberton }
5022e124b4aSJiri Slaby tty_flip_buffer_push(&port->port);
503f7a33e60SBill Pemberton
504f7a33e60SBill Pemberton newport = *(ch + 3);
505f7a33e60SBill Pemberton
506*63778385SQasim Ijaz if (newport >= serial->num_ports) {
507f7a33e60SBill Pemberton dev_err(&port->dev,
508f7a33e60SBill Pemberton "%s - port change to invalid port: %i\n",
509f7a33e60SBill Pemberton __func__, newport);
510f7a33e60SBill Pemberton break;
511f7a33e60SBill Pemberton }
512f7a33e60SBill Pemberton
513f7a33e60SBill Pemberton serial_priv->current_port = newport;
514f7a33e60SBill Pemberton port = serial->port[serial_priv->current_port];
515f7a33e60SBill Pemberton i += 3;
516f7a33e60SBill Pemberton escapeflag = true;
517f7a33e60SBill Pemberton break;
518f7a33e60SBill Pemberton case QT2_REC_FLUSH:
519f7a33e60SBill Pemberton case QT2_XMIT_FLUSH:
520f7a33e60SBill Pemberton i += 2;
521f7a33e60SBill Pemberton escapeflag = true;
522f7a33e60SBill Pemberton break;
523f7a33e60SBill Pemberton case QT2_CONTROL_ESCAPE:
52405c7cd39SJiri Slaby tty_insert_flip_string(&port->port, ch, 2);
525f7a33e60SBill Pemberton i += 2;
526f7a33e60SBill Pemberton escapeflag = true;
527f7a33e60SBill Pemberton break;
528f7a33e60SBill Pemberton default:
529f7a33e60SBill Pemberton dev_warn(&port->dev,
530f7a33e60SBill Pemberton "%s - unsupported command %i\n",
531f7a33e60SBill Pemberton __func__, *(ch + 2));
532f7a33e60SBill Pemberton break;
533f7a33e60SBill Pemberton }
534f7a33e60SBill Pemberton if (escapeflag)
535f7a33e60SBill Pemberton continue;
536f7a33e60SBill Pemberton }
537f7a33e60SBill Pemberton
538185fcb3fSJohan Hovold tty_insert_flip_char(&port->port, *ch, TTY_NORMAL);
539f7a33e60SBill Pemberton }
540f7a33e60SBill Pemberton
5412e124b4aSJiri Slaby tty_flip_buffer_push(&port->port);
542f7a33e60SBill Pemberton }
543f7a33e60SBill Pemberton
qt2_write_bulk_callback(struct urb * urb)544f7a33e60SBill Pemberton static void qt2_write_bulk_callback(struct urb *urb)
545f7a33e60SBill Pemberton {
546f7a33e60SBill Pemberton struct usb_serial_port *port;
547f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
5482ba02c8dSJohn Ogness unsigned long flags;
549f7a33e60SBill Pemberton
550f7a33e60SBill Pemberton port = urb->context;
551f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(port);
552f7a33e60SBill Pemberton
5532ba02c8dSJohn Ogness spin_lock_irqsave(&port_priv->urb_lock, flags);
554f7a33e60SBill Pemberton
555f7a33e60SBill Pemberton port_priv->urb_in_use = false;
556f7a33e60SBill Pemberton usb_serial_port_softint(port);
557f7a33e60SBill Pemberton
5582ba02c8dSJohn Ogness spin_unlock_irqrestore(&port_priv->urb_lock, flags);
559f7a33e60SBill Pemberton
560f7a33e60SBill Pemberton }
561f7a33e60SBill Pemberton
qt2_read_bulk_callback(struct urb * urb)562f7a33e60SBill Pemberton static void qt2_read_bulk_callback(struct urb *urb)
563f7a33e60SBill Pemberton {
564f7a33e60SBill Pemberton struct usb_serial *serial = urb->context;
565f7a33e60SBill Pemberton int status;
566f7a33e60SBill Pemberton
567f7a33e60SBill Pemberton if (urb->status) {
568f7a33e60SBill Pemberton dev_warn(&serial->dev->dev,
569f7a33e60SBill Pemberton "%s - non-zero urb status: %i\n", __func__,
570f7a33e60SBill Pemberton urb->status);
571f7a33e60SBill Pemberton return;
572f7a33e60SBill Pemberton }
573f7a33e60SBill Pemberton
574f7a33e60SBill Pemberton qt2_process_read_urb(urb);
575f7a33e60SBill Pemberton
576f7a33e60SBill Pemberton status = usb_submit_urb(urb, GFP_ATOMIC);
577f7a33e60SBill Pemberton if (status != 0)
578f7a33e60SBill Pemberton dev_err(&serial->dev->dev,
579f7a33e60SBill Pemberton "%s - resubmit read urb failed: %i\n",
580f7a33e60SBill Pemberton __func__, status);
581f7a33e60SBill Pemberton }
582f7a33e60SBill Pemberton
qt2_setup_urbs(struct usb_serial * serial)583f7a33e60SBill Pemberton static int qt2_setup_urbs(struct usb_serial *serial)
584f7a33e60SBill Pemberton {
585f7a33e60SBill Pemberton struct usb_serial_port *port0;
586f7a33e60SBill Pemberton struct qt2_serial_private *serial_priv;
58740d04738SJohan Hovold int status;
588f7a33e60SBill Pemberton
589f7a33e60SBill Pemberton port0 = serial->port[0];
590f7a33e60SBill Pemberton
591f7a33e60SBill Pemberton serial_priv = usb_get_serial_data(serial);
592f7a33e60SBill Pemberton serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
59310c642d0SJohan Hovold if (!serial_priv->read_urb)
594f7a33e60SBill Pemberton return -ENOMEM;
595f7a33e60SBill Pemberton
596f7a33e60SBill Pemberton usb_fill_bulk_urb(serial_priv->read_urb, serial->dev,
597f7a33e60SBill Pemberton usb_rcvbulkpipe(serial->dev,
598f7a33e60SBill Pemberton port0->bulk_in_endpointAddress),
599f7a33e60SBill Pemberton serial_priv->read_buffer,
60004480671SJohan Hovold QT2_READ_BUFFER_SIZE,
601f7a33e60SBill Pemberton qt2_read_bulk_callback, serial);
602f7a33e60SBill Pemberton
603f7a33e60SBill Pemberton status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL);
604f7a33e60SBill Pemberton if (status != 0) {
605f7a33e60SBill Pemberton dev_err(&serial->dev->dev,
606f7a33e60SBill Pemberton "%s - submit read urb failed %i\n", __func__, status);
607b8a00550SJohan Hovold usb_free_urb(serial_priv->read_urb);
608f7a33e60SBill Pemberton return status;
609f7a33e60SBill Pemberton }
610f7a33e60SBill Pemberton
611f7a33e60SBill Pemberton return 0;
612f7a33e60SBill Pemberton }
613f7a33e60SBill Pemberton
qt2_attach(struct usb_serial * serial)614f7a33e60SBill Pemberton static int qt2_attach(struct usb_serial *serial)
615f7a33e60SBill Pemberton {
616f7a33e60SBill Pemberton struct qt2_serial_private *serial_priv;
61740d04738SJohan Hovold int status;
618f7a33e60SBill Pemberton
619f7a33e60SBill Pemberton /* power on unit */
620eb8dbe80SJohan Hovold status = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
621f7a33e60SBill Pemberton 0xc2, 0x40, 0x8000, 0, NULL, 0,
622f7a33e60SBill Pemberton QT2_USB_TIMEOUT);
623f7a33e60SBill Pemberton if (status < 0) {
624f7a33e60SBill Pemberton dev_err(&serial->dev->dev,
625f7a33e60SBill Pemberton "%s - failed to power on unit: %i\n", __func__, status);
626f7a33e60SBill Pemberton return status;
627f7a33e60SBill Pemberton }
628f7a33e60SBill Pemberton
629f7a33e60SBill Pemberton serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
63010c642d0SJohan Hovold if (!serial_priv)
631f7a33e60SBill Pemberton return -ENOMEM;
632f7a33e60SBill Pemberton
63304480671SJohan Hovold serial_priv->read_buffer = kmalloc(QT2_READ_BUFFER_SIZE, GFP_KERNEL);
63404480671SJohan Hovold if (!serial_priv->read_buffer) {
63504480671SJohan Hovold status = -ENOMEM;
63604480671SJohan Hovold goto err_buf;
63704480671SJohan Hovold }
63804480671SJohan Hovold
639f7a33e60SBill Pemberton usb_set_serial_data(serial, serial_priv);
640f7a33e60SBill Pemberton
641f7a33e60SBill Pemberton status = qt2_setup_urbs(serial);
642f7a33e60SBill Pemberton if (status != 0)
643f7a33e60SBill Pemberton goto attach_failed;
644f7a33e60SBill Pemberton
645f7a33e60SBill Pemberton return 0;
646f7a33e60SBill Pemberton
647f7a33e60SBill Pemberton attach_failed:
64804480671SJohan Hovold kfree(serial_priv->read_buffer);
64904480671SJohan Hovold err_buf:
650f7a33e60SBill Pemberton kfree(serial_priv);
651f7a33e60SBill Pemberton return status;
652f7a33e60SBill Pemberton }
653f7a33e60SBill Pemberton
qt2_port_probe(struct usb_serial_port * port)65440d04738SJohan Hovold static int qt2_port_probe(struct usb_serial_port *port)
65540d04738SJohan Hovold {
65640d04738SJohan Hovold struct usb_serial *serial = port->serial;
65740d04738SJohan Hovold struct qt2_port_private *port_priv;
65840d04738SJohan Hovold u8 bEndpointAddress;
65940d04738SJohan Hovold
66040d04738SJohan Hovold port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
66140d04738SJohan Hovold if (!port_priv)
66240d04738SJohan Hovold return -ENOMEM;
66340d04738SJohan Hovold
66440d04738SJohan Hovold spin_lock_init(&port_priv->lock);
66540d04738SJohan Hovold spin_lock_init(&port_priv->urb_lock);
66640d04738SJohan Hovold port_priv->port = port;
66740d04738SJohan Hovold
668cbf30a91SJohan Hovold port_priv->write_buffer = kmalloc(QT2_WRITE_BUFFER_SIZE, GFP_KERNEL);
669cbf30a91SJohan Hovold if (!port_priv->write_buffer)
670cbf30a91SJohan Hovold goto err_buf;
671cbf30a91SJohan Hovold
67240d04738SJohan Hovold port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
673cbf30a91SJohan Hovold if (!port_priv->write_urb)
674cbf30a91SJohan Hovold goto err_urb;
675cbf30a91SJohan Hovold
67640d04738SJohan Hovold bEndpointAddress = serial->port[0]->bulk_out_endpointAddress;
67740d04738SJohan Hovold usb_fill_bulk_urb(port_priv->write_urb, serial->dev,
67840d04738SJohan Hovold usb_sndbulkpipe(serial->dev, bEndpointAddress),
67940d04738SJohan Hovold port_priv->write_buffer,
680cbf30a91SJohan Hovold QT2_WRITE_BUFFER_SIZE,
68140d04738SJohan Hovold qt2_write_bulk_callback, port);
68240d04738SJohan Hovold
68340d04738SJohan Hovold usb_set_serial_port_data(port, port_priv);
68440d04738SJohan Hovold
68540d04738SJohan Hovold return 0;
686cbf30a91SJohan Hovold err_urb:
687cbf30a91SJohan Hovold kfree(port_priv->write_buffer);
688cbf30a91SJohan Hovold err_buf:
689cbf30a91SJohan Hovold kfree(port_priv);
690cbf30a91SJohan Hovold return -ENOMEM;
69140d04738SJohan Hovold }
69240d04738SJohan Hovold
qt2_port_remove(struct usb_serial_port * port)693c5d1448fSUwe Kleine-König static void qt2_port_remove(struct usb_serial_port *port)
69440d04738SJohan Hovold {
69540d04738SJohan Hovold struct qt2_port_private *port_priv;
69640d04738SJohan Hovold
69740d04738SJohan Hovold port_priv = usb_get_serial_port_data(port);
69840d04738SJohan Hovold usb_free_urb(port_priv->write_urb);
699cbf30a91SJohan Hovold kfree(port_priv->write_buffer);
70040d04738SJohan Hovold kfree(port_priv);
70140d04738SJohan Hovold }
70240d04738SJohan Hovold
qt2_tiocmget(struct tty_struct * tty)703f7a33e60SBill Pemberton static int qt2_tiocmget(struct tty_struct *tty)
704f7a33e60SBill Pemberton {
705f7a33e60SBill Pemberton struct usb_serial_port *port = tty->driver_data;
706f7a33e60SBill Pemberton struct usb_device *dev = port->serial->dev;
707f7a33e60SBill Pemberton struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
708f7a33e60SBill Pemberton u8 *d;
709f7a33e60SBill Pemberton int r;
710f7a33e60SBill Pemberton
711f7a33e60SBill Pemberton d = kzalloc(2, GFP_KERNEL);
712f7a33e60SBill Pemberton if (!d)
713f7a33e60SBill Pemberton return -ENOMEM;
714f7a33e60SBill Pemberton
715f7a33e60SBill Pemberton r = qt2_getregister(dev, port_priv->device_port, UART_MCR, d);
716f7a33e60SBill Pemberton if (r < 0)
717f7a33e60SBill Pemberton goto mget_out;
718f7a33e60SBill Pemberton
719f7a33e60SBill Pemberton r = qt2_getregister(dev, port_priv->device_port, UART_MSR, d + 1);
720f7a33e60SBill Pemberton if (r < 0)
721f7a33e60SBill Pemberton goto mget_out;
722f7a33e60SBill Pemberton
723f7a33e60SBill Pemberton r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) |
724f7a33e60SBill Pemberton (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) |
725f7a33e60SBill Pemberton (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) |
726f7a33e60SBill Pemberton (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) |
727f7a33e60SBill Pemberton (d[1] & UART_MSR_RI ? TIOCM_RI : 0) |
728f7a33e60SBill Pemberton (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0);
729f7a33e60SBill Pemberton
730f7a33e60SBill Pemberton mget_out:
731f7a33e60SBill Pemberton kfree(d);
732f7a33e60SBill Pemberton return r;
733f7a33e60SBill Pemberton }
734f7a33e60SBill Pemberton
qt2_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)735f7a33e60SBill Pemberton static int qt2_tiocmset(struct tty_struct *tty,
736f7a33e60SBill Pemberton unsigned int set, unsigned int clear)
737f7a33e60SBill Pemberton {
738f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
739f7a33e60SBill Pemberton
740f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(tty->driver_data);
741f7a33e60SBill Pemberton return update_mctrl(port_priv, set, clear);
742f7a33e60SBill Pemberton }
743f7a33e60SBill Pemberton
qt2_break_ctl(struct tty_struct * tty,int break_state)7446ff58ae1SJohan Hovold static int qt2_break_ctl(struct tty_struct *tty, int break_state)
745f7a33e60SBill Pemberton {
746f7a33e60SBill Pemberton struct usb_serial_port *port = tty->driver_data;
747f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
748f7a33e60SBill Pemberton int status;
749f7a33e60SBill Pemberton u16 val;
750f7a33e60SBill Pemberton
751f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(port);
752f7a33e60SBill Pemberton
753f7a33e60SBill Pemberton val = (break_state == -1) ? 1 : 0;
754f7a33e60SBill Pemberton
755f7a33e60SBill Pemberton status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL,
756f7a33e60SBill Pemberton val, port_priv->device_port);
7576ff58ae1SJohan Hovold if (status < 0) {
758f7a33e60SBill Pemberton dev_warn(&port->dev,
759f7a33e60SBill Pemberton "%s - failed to send control message: %i\n", __func__,
760f7a33e60SBill Pemberton status);
7616ff58ae1SJohan Hovold return status;
7626ff58ae1SJohan Hovold }
7636ff58ae1SJohan Hovold
7646ff58ae1SJohan Hovold return 0;
765f7a33e60SBill Pemberton }
766f7a33e60SBill Pemberton
767f7a33e60SBill Pemberton
768f7a33e60SBill Pemberton
qt2_dtr_rts(struct usb_serial_port * port,int on)769f7a33e60SBill Pemberton static void qt2_dtr_rts(struct usb_serial_port *port, int on)
770f7a33e60SBill Pemberton {
771f7a33e60SBill Pemberton struct usb_device *dev = port->serial->dev;
772f7a33e60SBill Pemberton struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
773f7a33e60SBill Pemberton
774f7a33e60SBill Pemberton /* Disable flow control */
775b2ca6990SJohan Hovold if (!on) {
776b2ca6990SJohan Hovold if (qt2_setregister(dev, port_priv->device_port,
777f7a33e60SBill Pemberton UART_MCR, 0) < 0)
778f7a33e60SBill Pemberton dev_warn(&port->dev, "error from flowcontrol urb\n");
779b2ca6990SJohan Hovold }
780f7a33e60SBill Pemberton /* drop RTS and DTR */
781f7a33e60SBill Pemberton if (on)
782f7a33e60SBill Pemberton update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0);
783f7a33e60SBill Pemberton else
784f7a33e60SBill Pemberton update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS);
785f7a33e60SBill Pemberton }
786f7a33e60SBill Pemberton
qt2_update_msr(struct usb_serial_port * port,unsigned char * ch)787f7a33e60SBill Pemberton static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
788f7a33e60SBill Pemberton {
789f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
790f7a33e60SBill Pemberton u8 newMSR = (u8) *ch;
791f7a33e60SBill Pemberton unsigned long flags;
792f7a33e60SBill Pemberton
7939715a43eSJohan Hovold /* May be called from qt2_process_read_urb() for an unbound port. */
794f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(port);
7959715a43eSJohan Hovold if (!port_priv)
7969715a43eSJohan Hovold return;
797f7a33e60SBill Pemberton
798f7a33e60SBill Pemberton spin_lock_irqsave(&port_priv->lock, flags);
799f7a33e60SBill Pemberton port_priv->shadowMSR = newMSR;
800f7a33e60SBill Pemberton spin_unlock_irqrestore(&port_priv->lock, flags);
801f7a33e60SBill Pemberton
802f7a33e60SBill Pemberton if (newMSR & UART_MSR_ANY_DELTA) {
803f7a33e60SBill Pemberton /* update input line counters */
804f7a33e60SBill Pemberton if (newMSR & UART_MSR_DCTS)
8050a4142fbSJohan Hovold port->icount.cts++;
806f7a33e60SBill Pemberton if (newMSR & UART_MSR_DDSR)
8070a4142fbSJohan Hovold port->icount.dsr++;
808f7a33e60SBill Pemberton if (newMSR & UART_MSR_DDCD)
8090a4142fbSJohan Hovold port->icount.dcd++;
810f7a33e60SBill Pemberton if (newMSR & UART_MSR_TERI)
8110a4142fbSJohan Hovold port->icount.rng++;
812f7a33e60SBill Pemberton
813b5959704SJohan Hovold wake_up_interruptible(&port->port.delta_msr_wait);
814f7a33e60SBill Pemberton }
815f7a33e60SBill Pemberton }
816f7a33e60SBill Pemberton
qt2_update_lsr(struct usb_serial_port * port,unsigned char * ch)817f7a33e60SBill Pemberton static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)
818f7a33e60SBill Pemberton {
819f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
820f7a33e60SBill Pemberton struct async_icount *icount;
821f7a33e60SBill Pemberton unsigned long flags;
822f7a33e60SBill Pemberton u8 newLSR = (u8) *ch;
823f7a33e60SBill Pemberton
8249715a43eSJohan Hovold /* May be called from qt2_process_read_urb() for an unbound port. */
825f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(port);
8269715a43eSJohan Hovold if (!port_priv)
8279715a43eSJohan Hovold return;
828f7a33e60SBill Pemberton
829f7a33e60SBill Pemberton if (newLSR & UART_LSR_BI)
830f7a33e60SBill Pemberton newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI);
831f7a33e60SBill Pemberton
832f7a33e60SBill Pemberton spin_lock_irqsave(&port_priv->lock, flags);
833f7a33e60SBill Pemberton port_priv->shadowLSR = newLSR;
834f7a33e60SBill Pemberton spin_unlock_irqrestore(&port_priv->lock, flags);
835f7a33e60SBill Pemberton
8360a4142fbSJohan Hovold icount = &port->icount;
837f7a33e60SBill Pemberton
838f7a33e60SBill Pemberton if (newLSR & UART_LSR_BRK_ERROR_BITS) {
839f7a33e60SBill Pemberton
840f7a33e60SBill Pemberton if (newLSR & UART_LSR_BI)
841f7a33e60SBill Pemberton icount->brk++;
842f7a33e60SBill Pemberton
843f7a33e60SBill Pemberton if (newLSR & UART_LSR_OE)
844f7a33e60SBill Pemberton icount->overrun++;
845f7a33e60SBill Pemberton
846f7a33e60SBill Pemberton if (newLSR & UART_LSR_PE)
847f7a33e60SBill Pemberton icount->parity++;
848f7a33e60SBill Pemberton
849f7a33e60SBill Pemberton if (newLSR & UART_LSR_FE)
850f7a33e60SBill Pemberton icount->frame++;
851f7a33e60SBill Pemberton }
852f7a33e60SBill Pemberton
853f7a33e60SBill Pemberton }
854f7a33e60SBill Pemberton
qt2_write_room(struct tty_struct * tty)85594cc7aeaSJiri Slaby static unsigned int qt2_write_room(struct tty_struct *tty)
856f7a33e60SBill Pemberton {
857f7a33e60SBill Pemberton struct usb_serial_port *port = tty->driver_data;
858f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
85917cd3a10SJohan Hovold unsigned long flags;
86094cc7aeaSJiri Slaby unsigned int r;
861f7a33e60SBill Pemberton
862f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(port);
863f7a33e60SBill Pemberton
864f7a33e60SBill Pemberton spin_lock_irqsave(&port_priv->urb_lock, flags);
865f7a33e60SBill Pemberton
866f7a33e60SBill Pemberton if (port_priv->urb_in_use)
867f7a33e60SBill Pemberton r = 0;
868f7a33e60SBill Pemberton else
869f7a33e60SBill Pemberton r = QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE;
870f7a33e60SBill Pemberton
871f7a33e60SBill Pemberton spin_unlock_irqrestore(&port_priv->urb_lock, flags);
872f7a33e60SBill Pemberton
873f7a33e60SBill Pemberton return r;
874f7a33e60SBill Pemberton }
875f7a33e60SBill Pemberton
qt2_write(struct tty_struct * tty,struct usb_serial_port * port,const unsigned char * buf,int count)876f7a33e60SBill Pemberton static int qt2_write(struct tty_struct *tty,
877f7a33e60SBill Pemberton struct usb_serial_port *port,
878f7a33e60SBill Pemberton const unsigned char *buf, int count)
879f7a33e60SBill Pemberton {
880f7a33e60SBill Pemberton struct qt2_port_private *port_priv;
881f7a33e60SBill Pemberton struct urb *write_urb;
882f7a33e60SBill Pemberton unsigned char *data;
883f7a33e60SBill Pemberton unsigned long flags;
884f7a33e60SBill Pemberton int status;
885f7a33e60SBill Pemberton int bytes_out = 0;
886f7a33e60SBill Pemberton
887f7a33e60SBill Pemberton port_priv = usb_get_serial_port_data(port);
888f7a33e60SBill Pemberton
889f7a33e60SBill Pemberton if (port_priv->write_urb == NULL) {
890f7a33e60SBill Pemberton dev_err(&port->dev, "%s - no output urb\n", __func__);
891f7a33e60SBill Pemberton return 0;
892f7a33e60SBill Pemberton }
893f7a33e60SBill Pemberton write_urb = port_priv->write_urb;
894f7a33e60SBill Pemberton
895f7a33e60SBill Pemberton count = min(count, QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE);
896f7a33e60SBill Pemberton
897f7a33e60SBill Pemberton data = write_urb->transfer_buffer;
898f7a33e60SBill Pemberton spin_lock_irqsave(&port_priv->urb_lock, flags);
899ce9d8562SMathieu OTHACEHE if (port_priv->urb_in_use) {
900788a661aSGreg Kroah-Hartman dev_err(&port->dev, "qt2_write - urb is in use\n");
901f7a33e60SBill Pemberton goto write_out;
902f7a33e60SBill Pemberton }
903f7a33e60SBill Pemberton
904f7a33e60SBill Pemberton *data++ = QT2_CONTROL_BYTE;
905f7a33e60SBill Pemberton *data++ = QT2_CONTROL_BYTE;
906f7a33e60SBill Pemberton *data++ = port_priv->device_port;
907f7a33e60SBill Pemberton put_unaligned_le16(count, data);
908f7a33e60SBill Pemberton data += 2;
909f7a33e60SBill Pemberton memcpy(data, buf, count);
910f7a33e60SBill Pemberton
911f7a33e60SBill Pemberton write_urb->transfer_buffer_length = count + QT2_WRITE_CONTROL_SIZE;
912f7a33e60SBill Pemberton
913f7a33e60SBill Pemberton status = usb_submit_urb(write_urb, GFP_ATOMIC);
914f7a33e60SBill Pemberton if (status == 0) {
915f7a33e60SBill Pemberton port_priv->urb_in_use = true;
916f7a33e60SBill Pemberton bytes_out += count;
917f7a33e60SBill Pemberton }
918f7a33e60SBill Pemberton
919f7a33e60SBill Pemberton write_out:
920f7a33e60SBill Pemberton spin_unlock_irqrestore(&port_priv->urb_lock, flags);
921f7a33e60SBill Pemberton return bytes_out;
922f7a33e60SBill Pemberton }
923f7a33e60SBill Pemberton
924f7a33e60SBill Pemberton
925f7a33e60SBill Pemberton static struct usb_serial_driver qt2_device = {
926f7a33e60SBill Pemberton .driver = {
927f7a33e60SBill Pemberton .owner = THIS_MODULE,
928f7a33e60SBill Pemberton .name = "quatech-serial",
929f7a33e60SBill Pemberton },
930f7a33e60SBill Pemberton .description = DRIVER_DESC,
931f7a33e60SBill Pemberton .id_table = id_table,
932f7a33e60SBill Pemberton .open = qt2_open,
933f7a33e60SBill Pemberton .close = qt2_close,
934f7a33e60SBill Pemberton .write = qt2_write,
935f7a33e60SBill Pemberton .write_room = qt2_write_room,
936f7a33e60SBill Pemberton .calc_num_ports = qt2_calc_num_ports,
937f7a33e60SBill Pemberton .attach = qt2_attach,
938f7a33e60SBill Pemberton .release = qt2_release,
939f7a33e60SBill Pemberton .disconnect = qt2_disconnect,
94040d04738SJohan Hovold .port_probe = qt2_port_probe,
94140d04738SJohan Hovold .port_remove = qt2_port_remove,
942f7a33e60SBill Pemberton .dtr_rts = qt2_dtr_rts,
943f7a33e60SBill Pemberton .break_ctl = qt2_break_ctl,
944f7a33e60SBill Pemberton .tiocmget = qt2_tiocmget,
945f7a33e60SBill Pemberton .tiocmset = qt2_tiocmset,
946b5959704SJohan Hovold .tiocmiwait = usb_serial_generic_tiocmiwait,
9470a4142fbSJohan Hovold .get_icount = usb_serial_generic_get_icount,
948f7a33e60SBill Pemberton .set_termios = qt2_set_termios,
949f7a33e60SBill Pemberton };
950f7a33e60SBill Pemberton
951f7a33e60SBill Pemberton static struct usb_serial_driver *const serial_drivers[] = {
952f7a33e60SBill Pemberton &qt2_device, NULL
953f7a33e60SBill Pemberton };
954f7a33e60SBill Pemberton
955f7a33e60SBill Pemberton module_usb_serial_driver(serial_drivers, id_table);
956f7a33e60SBill Pemberton
957f7a33e60SBill Pemberton MODULE_DESCRIPTION(DRIVER_DESC);
958627cfa89SJohan Hovold MODULE_LICENSE("GPL v2");
959