blob: d80d5a56adc22b8ebb38f007fdf16c0864c5ee3c [file] [log] [blame]
Pavankumar Kondetie2ba8112013-03-01 09:34:02 +05301/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Hemant Kumar0cac8ed2012-01-31 14:39:23 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Steve Mucklef132c6c2012-06-06 18:30:57 -070013#include <linux/module.h>
Hemant Kumar0cac8ed2012-01-31 14:39:23 -080014#include <linux/slab.h>
15#include <linux/tty.h>
16#include <linux/serial.h>
17#include <linux/tty_flip.h>
18#include <linux/uaccess.h>
19#include <linux/usb.h>
20#include <linux/usb/ch9.h>
21#include <linux/usb/cdc.h>
22#include <linux/usb/serial.h>
23#include <asm/unaligned.h>
24
25
26/* output control lines*/
27#define CSVT_CTRL_DTR 0x01
28#define CSVT_CTRL_RTS 0x02
29
30/* input control lines*/
Pavankumar Kondetie2ba8112013-03-01 09:34:02 +053031#define CSVT_CTRL_CD 0x01
Hemant Kumar0cac8ed2012-01-31 14:39:23 -080032#define CSVT_CTRL_DSR 0x02
Pavankumar Kondetie2ba8112013-03-01 09:34:02 +053033#define CSVT_CTRL_BRK 0x04
34#define CSVT_CTRL_RI 0x08
35
36#define CSVT_CTRL_FRAMING 0x10
37#define CSVT_CTRL_PARITY 0x20
38#define CSVT_CTRL_OVERRUN 0x40
Hemant Kumar0cac8ed2012-01-31 14:39:23 -080039
40static int debug;
41module_param(debug, int, S_IRUGO | S_IWUSR);
42
43struct csvt_ctrl_dev {
44 struct mutex dev_lock;
45
46 /* input control lines (DSR, CTS, CD, RI) */
47 unsigned int cbits_tolocal;
48
49 /* output control lines (DTR, RTS) */
50 unsigned int cbits_tomdm;
51};
52
53static const struct usb_device_id id_table[] = {
Hemant Kumar31aed6a2012-03-05 14:56:26 -080054 { USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x904c, 0xff, 0xfe, 0xff)},
Hemant Kumardd1e5ff2012-12-06 15:52:02 -080055 { USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x9075, 0xff, 0xfe, 0xff)},
Pavankumar Kondeti54a8d3c2013-06-21 13:45:44 +053056 { USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x908A, 0xff, 0xfe, 0xff)},
Hemant Kumar0cac8ed2012-01-31 14:39:23 -080057 {}, /* terminating entry */
58};
59MODULE_DEVICE_TABLE(usb, id_table);
60
61static struct usb_driver csvt_driver = {
62 .name = "qc_csvt",
63 .probe = usb_serial_probe,
64 .disconnect = usb_serial_disconnect,
65 .id_table = id_table,
66 .suspend = usb_serial_suspend,
67 .resume = usb_serial_resume,
68 .supports_autosuspend = true,
69};
70
71#define CSVT_IFC_NUM 4
72
73static int csvt_probe(struct usb_serial *serial, const struct usb_device_id *id)
74{
75 struct usb_host_interface *intf =
76 serial->interface->cur_altsetting;
77
78 pr_debug("%s:\n", __func__);
79
80 if (intf->desc.bInterfaceNumber != CSVT_IFC_NUM)
81 return -ENODEV;
82
83 usb_enable_autosuspend(serial->dev);
84
85 return 0;
86}
87
88static int csvt_ctrl_write_cmd(struct csvt_ctrl_dev *dev,
89 struct usb_serial_port *port)
90{
91 struct usb_device *udev = port->serial->dev;
92 struct usb_interface *iface = port->serial->interface;
93 unsigned int iface_num;
94 int retval = 0;
95
96 retval = usb_autopm_get_interface(iface);
97 if (retval < 0) {
98 dev_err(&port->dev, "%s: Unable to resume interface: %d\n",
99 __func__, retval);
100 return retval;
101 }
102
103 dev_dbg(&port->dev, "%s: cbits to mdm 0x%x\n", __func__,
104 dev->cbits_tomdm);
105
106 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
107
108 retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
109 USB_CDC_REQ_SET_CONTROL_LINE_STATE,
110 (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
111 dev->cbits_tomdm,
112 iface_num,
113 NULL, 0, USB_CTRL_SET_TIMEOUT);
114 usb_autopm_put_interface(iface);
115
116 return retval;
117}
118
119static void csvt_ctrl_dtr_rts(struct usb_serial_port *port, int on)
120{
121 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
122
123 if (!dev)
124 return;
125
126 dev_dbg(&port->dev, "%s", __func__);
127
128 mutex_lock(&dev->dev_lock);
129 if (on) {
130 dev->cbits_tomdm |= CSVT_CTRL_DTR;
131 dev->cbits_tomdm |= CSVT_CTRL_RTS;
132 } else {
133 dev->cbits_tomdm &= ~CSVT_CTRL_DTR;
134 dev->cbits_tomdm &= ~CSVT_CTRL_RTS;
135 }
136 mutex_unlock(&dev->dev_lock);
137
138 csvt_ctrl_write_cmd(dev, port);
139}
140
141static int get_serial_info(struct usb_serial_port *port,
142 struct serial_struct __user *retinfo)
143{
144 struct serial_struct tmp;
145
146 if (!retinfo)
147 return -EFAULT;
148
149 memset(&tmp, 0, sizeof(tmp));
150 tmp.line = port->serial->minor;
151 tmp.port = port->number;
152 tmp.baud_base = tty_get_baud_rate(port->port.tty);
153 tmp.close_delay = port->port.close_delay / 10;
154 tmp.closing_wait =
155 port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
156 ASYNC_CLOSING_WAIT_NONE :
157 port->port.closing_wait / 10;
158
159 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
160 return -EFAULT;
161 return 0;
162}
163
164static int set_serial_info(struct usb_serial_port *port,
165 struct serial_struct __user *newinfo)
166{
167 struct serial_struct new_serial;
168 unsigned int closing_wait;
169 unsigned int close_delay;
170 int retval = 0;
171
172 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
173 return -EFAULT;
174
175 close_delay = new_serial.close_delay * 10;
176 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
177 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
178
179 mutex_lock(&port->port.mutex);
180
181 if (!capable(CAP_SYS_ADMIN)) {
182 if ((close_delay != port->port.close_delay) ||
183 (closing_wait != port->port.closing_wait))
184 retval = -EPERM;
185 else
186 retval = -EOPNOTSUPP;
187 } else {
188 port->port.close_delay = close_delay;
189 port->port.closing_wait = closing_wait;
190 }
191
192 mutex_unlock(&port->port.mutex);
193 return retval;
194}
195
196static int csvt_ctrl_ioctl(struct tty_struct *tty, unsigned int cmd,
197 unsigned long arg)
198{
199 struct usb_serial_port *port = tty->driver_data;
200
201 dev_dbg(&port->dev, "%s cmd 0x%04x", __func__, cmd);
202
203 switch (cmd) {
204 case TIOCGSERIAL:
205 return get_serial_info(port,
206 (struct serial_struct __user *) arg);
207 case TIOCSSERIAL:
208 return set_serial_info(port,
209 (struct serial_struct __user *) arg);
210 default:
211 break;
212 }
213
214 dev_err(&port->dev, "%s arg not supported", __func__);
215
216 return -ENOIOCTLCMD;
217}
218
219static int csvt_ctrl_tiocmget(struct tty_struct *tty)
220{
221 struct usb_serial_port *port = tty->driver_data;
222 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
223 unsigned int control_state = 0;
224
225 if (!dev)
226 return -ENODEV;
227
228 mutex_lock(&dev->dev_lock);
229 control_state = (dev->cbits_tomdm & CSVT_CTRL_DTR ? TIOCM_DTR : 0) |
230 (dev->cbits_tomdm & CSVT_CTRL_RTS ? TIOCM_RTS : 0) |
231 (dev->cbits_tolocal & CSVT_CTRL_DSR ? TIOCM_DSR : 0) |
232 (dev->cbits_tolocal & CSVT_CTRL_RI ? TIOCM_RI : 0) |
233 (dev->cbits_tolocal & CSVT_CTRL_CD ? TIOCM_CD : 0) |
Pavankumar Kondetie2ba8112013-03-01 09:34:02 +0530234 TIOCM_CTS; /* USB CDC spec did not define CTS control signal */
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800235 mutex_unlock(&dev->dev_lock);
236
237 dev_dbg(&port->dev, "%s -- %x", __func__, control_state);
238
239 return control_state;
240}
241
242static int csvt_ctrl_tiocmset(struct tty_struct *tty,
243 unsigned int set, unsigned int clear)
244{
245 struct usb_serial_port *port = tty->driver_data;
246 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
247
248 if (!dev)
249 return -ENODEV;
250
251 dev_dbg(&port->dev, "%s\n", __func__);
252
253 mutex_lock(&dev->dev_lock);
Pavankumar Kondeti06c54032013-04-19 14:23:28 +0530254 if (set & TIOCM_DTR)
255 dev->cbits_tomdm |= CSVT_CTRL_DTR;
256 if (set & TIOCM_RTS)
257 dev->cbits_tomdm |= CSVT_CTRL_RTS;
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800258
Pavankumar Kondeti06c54032013-04-19 14:23:28 +0530259 if (clear & TIOCM_DTR)
260 dev->cbits_tomdm &= ~CSVT_CTRL_DTR;
261 if (clear & TIOCM_RTS)
262 dev->cbits_tomdm &= ~CSVT_CTRL_RTS;
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800263 mutex_unlock(&dev->dev_lock);
264
265 return csvt_ctrl_write_cmd(dev, port);
266}
267
268static void csvt_ctrl_set_termios(struct tty_struct *tty,
269 struct usb_serial_port *port,
270 struct ktermios *old_termios)
271{
272 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
273
274 if (!dev)
275 return;
276
277 dev_dbg(&port->dev, "%s", __func__);
278
279 /* Doesn't support option setting */
280 tty_termios_copy_hw(tty->termios, old_termios);
281
282 csvt_ctrl_write_cmd(dev, port);
283}
284
285static void csvt_ctrl_int_cb(struct urb *urb)
286{
287 int status;
288 struct usb_cdc_notification *ctrl;
289 struct usb_serial_port *port = urb->context;
290 struct csvt_ctrl_dev *dev;
291 unsigned int ctrl_bits;
292 unsigned char *data;
293
294 switch (urb->status) {
295 case 0:
296 /*success*/
297 break;
298 case -ESHUTDOWN:
299 case -ENOENT:
300 case -ECONNRESET:
301 case -EPROTO:
302 /* unplug */
303 return;
304 case -EPIPE:
305 dev_err(&port->dev, "%s: stall on int endpoint\n", __func__);
306 /* TBD : halt to be cleared in work */
307 case -EOVERFLOW:
308 default:
309 pr_debug_ratelimited("%s: non zero urb status = %d\n",
310 __func__, urb->status);
311 goto resubmit_int_urb;
312 }
313
314 dev = usb_get_serial_port_data(port);
315 if (!dev)
316 return;
317
318 ctrl = urb->transfer_buffer;
319 data = (unsigned char *)(ctrl + 1);
320
321 usb_serial_debug_data(debug, &port->dev, __func__,
322 urb->actual_length, data);
323
324 switch (ctrl->bNotificationType) {
325 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
326 dev_dbg(&port->dev, "%s network\n", ctrl->wValue ?
327 "connected to" : "disconnected from");
328 break;
329 case USB_CDC_NOTIFY_SERIAL_STATE:
330 ctrl_bits = get_unaligned_le16(data);
331 dev_dbg(&port->dev, "serial state: %d\n", ctrl_bits);
332 dev->cbits_tolocal = ctrl_bits;
333 break;
334 default:
335 dev_err(&port->dev, "%s: unknown notification %d received:"
336 "index %d len %d data0 %d data1 %d",
337 __func__, ctrl->bNotificationType, ctrl->wIndex,
338 ctrl->wLength, data[0], data[1]);
339 }
340
341resubmit_int_urb:
342 status = usb_submit_urb(urb, GFP_ATOMIC);
343 if (status)
344 dev_err(&port->dev, "%s: Error re-submitting Int URB %d\n",
345 __func__, status);
346
347}
348
349static int csvt_ctrl_open(struct tty_struct *tty,
350 struct usb_serial_port *port)
351{
352 int retval;
353
354 dev_dbg(&port->dev, "%s port %d", __func__, port->number);
355
356 retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
357 if (retval) {
358 dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
359 return retval;
360 }
361
362 retval = usb_serial_generic_open(tty, port);
363 if (retval)
364 usb_kill_urb(port->interrupt_in_urb);
365
366 return retval;
367}
368
369static void csvt_ctrl_close(struct usb_serial_port *port)
370{
371 dev_dbg(&port->dev, "%s port %d", __func__, port->number);
372
373 usb_serial_generic_close(port);
374 usb_kill_urb(port->interrupt_in_urb);
375}
376
377static int csvt_ctrl_attach(struct usb_serial *serial)
378{
379 struct csvt_ctrl_dev *dev;
380
381 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
382 if (!dev)
383 return -ENOMEM;
384
385 mutex_init(&dev->dev_lock);
386 usb_set_serial_port_data(serial->port[0], dev);
387
388 return 0;
389}
390
391static void csvt_ctrl_release(struct usb_serial *serial)
392{
393 struct usb_serial_port *port = serial->port[0];
394 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
395
396 dev_dbg(&port->dev, "%s", __func__);
397
398 kfree(dev);
399 usb_set_serial_port_data(port, NULL);
400}
401
402static struct usb_serial_driver csvt_device = {
403 .driver = {
404 .owner = THIS_MODULE,
405 .name = "qc_csvt",
406 },
407 .description = "qc_csvt",
408 .id_table = id_table,
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800409 .num_ports = 1,
410 .open = csvt_ctrl_open,
411 .close = csvt_ctrl_close,
412 .probe = csvt_probe,
413 .dtr_rts = csvt_ctrl_dtr_rts,
414 .tiocmget = csvt_ctrl_tiocmget,
415 .tiocmset = csvt_ctrl_tiocmset,
416 .ioctl = csvt_ctrl_ioctl,
417 .set_termios = csvt_ctrl_set_termios,
418 .read_int_callback = csvt_ctrl_int_cb,
419 .attach = csvt_ctrl_attach,
420 .release = csvt_ctrl_release,
421};
422
Steve Mucklef132c6c2012-06-06 18:30:57 -0700423static struct usb_serial_driver * const serial_drivers[] = {
424 &csvt_device,
425 NULL,
426};
427
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800428static int __init csvt_init(void)
429{
430 int retval;
431
Steve Mucklef132c6c2012-06-06 18:30:57 -0700432 retval = usb_serial_register_drivers(&csvt_driver, serial_drivers);
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800433 if (retval) {
434 err("%s: usb serial register failed\n", __func__);
435 return retval;
436 }
437
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800438 return 0;
439}
440
441static void __exit csvt_exit(void)
442{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700443 usb_serial_deregister_drivers(&csvt_driver, serial_drivers);
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800444}
445
446module_init(csvt_init);
447module_exit(csvt_exit);
448
449MODULE_LICENSE("GPL v2");