blob: 675b3d3ad095e749d0e69200c7e3688a7165fb08 [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)},
Hemant Kumar0cac8ed2012-01-31 14:39:23 -080056 {}, /* terminating entry */
57};
58MODULE_DEVICE_TABLE(usb, id_table);
59
60static struct usb_driver csvt_driver = {
61 .name = "qc_csvt",
62 .probe = usb_serial_probe,
63 .disconnect = usb_serial_disconnect,
64 .id_table = id_table,
65 .suspend = usb_serial_suspend,
66 .resume = usb_serial_resume,
67 .supports_autosuspend = true,
68};
69
70#define CSVT_IFC_NUM 4
71
72static int csvt_probe(struct usb_serial *serial, const struct usb_device_id *id)
73{
74 struct usb_host_interface *intf =
75 serial->interface->cur_altsetting;
76
77 pr_debug("%s:\n", __func__);
78
79 if (intf->desc.bInterfaceNumber != CSVT_IFC_NUM)
80 return -ENODEV;
81
82 usb_enable_autosuspend(serial->dev);
83
84 return 0;
85}
86
87static int csvt_ctrl_write_cmd(struct csvt_ctrl_dev *dev,
88 struct usb_serial_port *port)
89{
90 struct usb_device *udev = port->serial->dev;
91 struct usb_interface *iface = port->serial->interface;
92 unsigned int iface_num;
93 int retval = 0;
94
95 retval = usb_autopm_get_interface(iface);
96 if (retval < 0) {
97 dev_err(&port->dev, "%s: Unable to resume interface: %d\n",
98 __func__, retval);
99 return retval;
100 }
101
102 dev_dbg(&port->dev, "%s: cbits to mdm 0x%x\n", __func__,
103 dev->cbits_tomdm);
104
105 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
106
107 retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
108 USB_CDC_REQ_SET_CONTROL_LINE_STATE,
109 (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
110 dev->cbits_tomdm,
111 iface_num,
112 NULL, 0, USB_CTRL_SET_TIMEOUT);
113 usb_autopm_put_interface(iface);
114
115 return retval;
116}
117
118static void csvt_ctrl_dtr_rts(struct usb_serial_port *port, int on)
119{
120 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
121
122 if (!dev)
123 return;
124
125 dev_dbg(&port->dev, "%s", __func__);
126
127 mutex_lock(&dev->dev_lock);
128 if (on) {
129 dev->cbits_tomdm |= CSVT_CTRL_DTR;
130 dev->cbits_tomdm |= CSVT_CTRL_RTS;
131 } else {
132 dev->cbits_tomdm &= ~CSVT_CTRL_DTR;
133 dev->cbits_tomdm &= ~CSVT_CTRL_RTS;
134 }
135 mutex_unlock(&dev->dev_lock);
136
137 csvt_ctrl_write_cmd(dev, port);
138}
139
140static int get_serial_info(struct usb_serial_port *port,
141 struct serial_struct __user *retinfo)
142{
143 struct serial_struct tmp;
144
145 if (!retinfo)
146 return -EFAULT;
147
148 memset(&tmp, 0, sizeof(tmp));
149 tmp.line = port->serial->minor;
150 tmp.port = port->number;
151 tmp.baud_base = tty_get_baud_rate(port->port.tty);
152 tmp.close_delay = port->port.close_delay / 10;
153 tmp.closing_wait =
154 port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
155 ASYNC_CLOSING_WAIT_NONE :
156 port->port.closing_wait / 10;
157
158 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
159 return -EFAULT;
160 return 0;
161}
162
163static int set_serial_info(struct usb_serial_port *port,
164 struct serial_struct __user *newinfo)
165{
166 struct serial_struct new_serial;
167 unsigned int closing_wait;
168 unsigned int close_delay;
169 int retval = 0;
170
171 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
172 return -EFAULT;
173
174 close_delay = new_serial.close_delay * 10;
175 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
176 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
177
178 mutex_lock(&port->port.mutex);
179
180 if (!capable(CAP_SYS_ADMIN)) {
181 if ((close_delay != port->port.close_delay) ||
182 (closing_wait != port->port.closing_wait))
183 retval = -EPERM;
184 else
185 retval = -EOPNOTSUPP;
186 } else {
187 port->port.close_delay = close_delay;
188 port->port.closing_wait = closing_wait;
189 }
190
191 mutex_unlock(&port->port.mutex);
192 return retval;
193}
194
195static int csvt_ctrl_ioctl(struct tty_struct *tty, unsigned int cmd,
196 unsigned long arg)
197{
198 struct usb_serial_port *port = tty->driver_data;
199
200 dev_dbg(&port->dev, "%s cmd 0x%04x", __func__, cmd);
201
202 switch (cmd) {
203 case TIOCGSERIAL:
204 return get_serial_info(port,
205 (struct serial_struct __user *) arg);
206 case TIOCSSERIAL:
207 return set_serial_info(port,
208 (struct serial_struct __user *) arg);
209 default:
210 break;
211 }
212
213 dev_err(&port->dev, "%s arg not supported", __func__);
214
215 return -ENOIOCTLCMD;
216}
217
218static int csvt_ctrl_tiocmget(struct tty_struct *tty)
219{
220 struct usb_serial_port *port = tty->driver_data;
221 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
222 unsigned int control_state = 0;
223
224 if (!dev)
225 return -ENODEV;
226
227 mutex_lock(&dev->dev_lock);
228 control_state = (dev->cbits_tomdm & CSVT_CTRL_DTR ? TIOCM_DTR : 0) |
229 (dev->cbits_tomdm & CSVT_CTRL_RTS ? TIOCM_RTS : 0) |
230 (dev->cbits_tolocal & CSVT_CTRL_DSR ? TIOCM_DSR : 0) |
231 (dev->cbits_tolocal & CSVT_CTRL_RI ? TIOCM_RI : 0) |
232 (dev->cbits_tolocal & CSVT_CTRL_CD ? TIOCM_CD : 0) |
Pavankumar Kondetie2ba8112013-03-01 09:34:02 +0530233 TIOCM_CTS; /* USB CDC spec did not define CTS control signal */
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800234 mutex_unlock(&dev->dev_lock);
235
236 dev_dbg(&port->dev, "%s -- %x", __func__, control_state);
237
238 return control_state;
239}
240
241static int csvt_ctrl_tiocmset(struct tty_struct *tty,
242 unsigned int set, unsigned int clear)
243{
244 struct usb_serial_port *port = tty->driver_data;
245 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
246
247 if (!dev)
248 return -ENODEV;
249
250 dev_dbg(&port->dev, "%s\n", __func__);
251
252 mutex_lock(&dev->dev_lock);
Pavankumar Kondeti06c54032013-04-19 14:23:28 +0530253 if (set & TIOCM_DTR)
254 dev->cbits_tomdm |= CSVT_CTRL_DTR;
255 if (set & TIOCM_RTS)
256 dev->cbits_tomdm |= CSVT_CTRL_RTS;
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800257
Pavankumar Kondeti06c54032013-04-19 14:23:28 +0530258 if (clear & TIOCM_DTR)
259 dev->cbits_tomdm &= ~CSVT_CTRL_DTR;
260 if (clear & TIOCM_RTS)
261 dev->cbits_tomdm &= ~CSVT_CTRL_RTS;
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800262 mutex_unlock(&dev->dev_lock);
263
264 return csvt_ctrl_write_cmd(dev, port);
265}
266
267static void csvt_ctrl_set_termios(struct tty_struct *tty,
268 struct usb_serial_port *port,
269 struct ktermios *old_termios)
270{
271 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
272
273 if (!dev)
274 return;
275
276 dev_dbg(&port->dev, "%s", __func__);
277
278 /* Doesn't support option setting */
279 tty_termios_copy_hw(tty->termios, old_termios);
280
281 csvt_ctrl_write_cmd(dev, port);
282}
283
284static void csvt_ctrl_int_cb(struct urb *urb)
285{
286 int status;
287 struct usb_cdc_notification *ctrl;
288 struct usb_serial_port *port = urb->context;
289 struct csvt_ctrl_dev *dev;
290 unsigned int ctrl_bits;
291 unsigned char *data;
292
293 switch (urb->status) {
294 case 0:
295 /*success*/
296 break;
297 case -ESHUTDOWN:
298 case -ENOENT:
299 case -ECONNRESET:
300 case -EPROTO:
301 /* unplug */
302 return;
303 case -EPIPE:
304 dev_err(&port->dev, "%s: stall on int endpoint\n", __func__);
305 /* TBD : halt to be cleared in work */
306 case -EOVERFLOW:
307 default:
308 pr_debug_ratelimited("%s: non zero urb status = %d\n",
309 __func__, urb->status);
310 goto resubmit_int_urb;
311 }
312
313 dev = usb_get_serial_port_data(port);
314 if (!dev)
315 return;
316
317 ctrl = urb->transfer_buffer;
318 data = (unsigned char *)(ctrl + 1);
319
320 usb_serial_debug_data(debug, &port->dev, __func__,
321 urb->actual_length, data);
322
323 switch (ctrl->bNotificationType) {
324 case USB_CDC_NOTIFY_NETWORK_CONNECTION:
325 dev_dbg(&port->dev, "%s network\n", ctrl->wValue ?
326 "connected to" : "disconnected from");
327 break;
328 case USB_CDC_NOTIFY_SERIAL_STATE:
329 ctrl_bits = get_unaligned_le16(data);
330 dev_dbg(&port->dev, "serial state: %d\n", ctrl_bits);
331 dev->cbits_tolocal = ctrl_bits;
332 break;
333 default:
334 dev_err(&port->dev, "%s: unknown notification %d received:"
335 "index %d len %d data0 %d data1 %d",
336 __func__, ctrl->bNotificationType, ctrl->wIndex,
337 ctrl->wLength, data[0], data[1]);
338 }
339
340resubmit_int_urb:
341 status = usb_submit_urb(urb, GFP_ATOMIC);
342 if (status)
343 dev_err(&port->dev, "%s: Error re-submitting Int URB %d\n",
344 __func__, status);
345
346}
347
348static int csvt_ctrl_open(struct tty_struct *tty,
349 struct usb_serial_port *port)
350{
351 int retval;
352
353 dev_dbg(&port->dev, "%s port %d", __func__, port->number);
354
355 retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
356 if (retval) {
357 dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
358 return retval;
359 }
360
361 retval = usb_serial_generic_open(tty, port);
362 if (retval)
363 usb_kill_urb(port->interrupt_in_urb);
364
365 return retval;
366}
367
368static void csvt_ctrl_close(struct usb_serial_port *port)
369{
370 dev_dbg(&port->dev, "%s port %d", __func__, port->number);
371
372 usb_serial_generic_close(port);
373 usb_kill_urb(port->interrupt_in_urb);
374}
375
376static int csvt_ctrl_attach(struct usb_serial *serial)
377{
378 struct csvt_ctrl_dev *dev;
379
380 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
381 if (!dev)
382 return -ENOMEM;
383
384 mutex_init(&dev->dev_lock);
385 usb_set_serial_port_data(serial->port[0], dev);
386
387 return 0;
388}
389
390static void csvt_ctrl_release(struct usb_serial *serial)
391{
392 struct usb_serial_port *port = serial->port[0];
393 struct csvt_ctrl_dev *dev = usb_get_serial_port_data(port);
394
395 dev_dbg(&port->dev, "%s", __func__);
396
397 kfree(dev);
398 usb_set_serial_port_data(port, NULL);
399}
400
401static struct usb_serial_driver csvt_device = {
402 .driver = {
403 .owner = THIS_MODULE,
404 .name = "qc_csvt",
405 },
406 .description = "qc_csvt",
407 .id_table = id_table,
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800408 .num_ports = 1,
409 .open = csvt_ctrl_open,
410 .close = csvt_ctrl_close,
411 .probe = csvt_probe,
412 .dtr_rts = csvt_ctrl_dtr_rts,
413 .tiocmget = csvt_ctrl_tiocmget,
414 .tiocmset = csvt_ctrl_tiocmset,
415 .ioctl = csvt_ctrl_ioctl,
416 .set_termios = csvt_ctrl_set_termios,
417 .read_int_callback = csvt_ctrl_int_cb,
418 .attach = csvt_ctrl_attach,
419 .release = csvt_ctrl_release,
420};
421
Steve Mucklef132c6c2012-06-06 18:30:57 -0700422static struct usb_serial_driver * const serial_drivers[] = {
423 &csvt_device,
424 NULL,
425};
426
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800427static int __init csvt_init(void)
428{
429 int retval;
430
Steve Mucklef132c6c2012-06-06 18:30:57 -0700431 retval = usb_serial_register_drivers(&csvt_driver, serial_drivers);
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800432 if (retval) {
433 err("%s: usb serial register failed\n", __func__);
434 return retval;
435 }
436
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800437 return 0;
438}
439
440static void __exit csvt_exit(void)
441{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700442 usb_serial_deregister_drivers(&csvt_driver, serial_drivers);
Hemant Kumar0cac8ed2012-01-31 14:39:23 -0800443}
444
445module_init(csvt_init);
446module_exit(csvt_exit);
447
448MODULE_LICENSE("GPL v2");