aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/serial/Kconfig9
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/f81232.c405
3 files changed, 415 insertions, 0 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 677f577c0243..434df7f2a4bd 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -238,6 +238,15 @@ config USB_SERIAL_EDGEPORT_TI
238 To compile this driver as a module, choose M here: the 238 To compile this driver as a module, choose M here: the
239 module will be called io_ti. 239 module will be called io_ti.
240 240
241config USB_SERIAL_F81232
242 tristate "USB Fintek F81232 Single Port Serial Driver"
243 help
244 Say Y here if you want to use the Fintek F81232 single
245 port usb to serial adapter.
246
247 To compile this driver as a module, choose M here: the
248 module will be called f81232.
249
241config USB_SERIAL_GARMIN 250config USB_SERIAL_GARMIN
242 tristate "USB Garmin GPS driver" 251 tristate "USB Garmin GPS driver"
243 help 252 help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 9e536eefb32c..5ac438b40270 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o
23obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o 23obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o
24obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o 24obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o
25obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o 25obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
26obj-$(CONFIG_USB_SERIAL_F81232) += f81232.o
26obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o 27obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o
27obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o 28obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o
28obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o 29obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
new file mode 100644
index 000000000000..88c0b1963920
--- /dev/null
+++ b/drivers/usb/serial/f81232.c
@@ -0,0 +1,405 @@
1/*
2 * Fintek F81232 USB to serial adaptor driver
3 *
4 * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org)
5 * Copyright (C) 2012 Linux Foundation
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 */
12
13#include <linux/kernel.h>
14#include <linux/errno.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/tty.h>
18#include <linux/tty_driver.h>
19#include <linux/tty_flip.h>
20#include <linux/serial.h>
21#include <linux/module.h>
22#include <linux/moduleparam.h>
23#include <linux/spinlock.h>
24#include <linux/uaccess.h>
25#include <linux/usb.h>
26#include <linux/usb/serial.h>
27
28static bool debug;
29
30static const struct usb_device_id id_table[] = {
31 { USB_DEVICE(0x1934, 0x0706) },
32 { } /* Terminating entry */
33};
34MODULE_DEVICE_TABLE(usb, id_table);
35
36#define CONTROL_DTR 0x01
37#define CONTROL_RTS 0x02
38
39#define UART_STATE 0x08
40#define UART_STATE_TRANSIENT_MASK 0x74
41#define UART_DCD 0x01
42#define UART_DSR 0x02
43#define UART_BREAK_ERROR 0x04
44#define UART_RING 0x08
45#define UART_FRAME_ERROR 0x10
46#define UART_PARITY_ERROR 0x20
47#define UART_OVERRUN_ERROR 0x40
48#define UART_CTS 0x80
49
50struct f81232_private {
51 spinlock_t lock;
52 wait_queue_head_t delta_msr_wait;
53 u8 line_control;
54 u8 line_status;
55};
56
57static void f81232_update_line_status(struct usb_serial_port *port,
58 unsigned char *data,
59 unsigned int actual_length)
60{
61}
62
63static void f81232_read_int_callback(struct urb *urb)
64{
65 struct usb_serial_port *port = urb->context;
66 unsigned char *data = urb->transfer_buffer;
67 unsigned int actual_length = urb->actual_length;
68 int status = urb->status;
69 int retval;
70
71 dbg("%s (%d)", __func__, port->number);
72
73 switch (status) {
74 case 0:
75 /* success */
76 break;
77 case -ECONNRESET:
78 case -ENOENT:
79 case -ESHUTDOWN:
80 /* this urb is terminated, clean up */
81 dbg("%s - urb shutting down with status: %d", __func__,
82 status);
83 return;
84 default:
85 dbg("%s - nonzero urb status received: %d", __func__,
86 status);
87 goto exit;
88 }
89
90 usb_serial_debug_data(debug, &port->dev, __func__,
91 urb->actual_length, urb->transfer_buffer);
92
93 f81232_update_line_status(port, data, actual_length);
94
95exit:
96 retval = usb_submit_urb(urb, GFP_ATOMIC);
97 if (retval)
98 dev_err(&urb->dev->dev,
99 "%s - usb_submit_urb failed with result %d\n",
100 __func__, retval);
101}
102
103static void f81232_process_read_urb(struct urb *urb)
104{
105 struct usb_serial_port *port = urb->context;
106 struct f81232_private *priv = usb_get_serial_port_data(port);
107 struct tty_struct *tty;
108 unsigned char *data = urb->transfer_buffer;
109 char tty_flag = TTY_NORMAL;
110 unsigned long flags;
111 u8 line_status;
112 int i;
113
114 /* update line status */
115 spin_lock_irqsave(&priv->lock, flags);
116 line_status = priv->line_status;
117 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
118 spin_unlock_irqrestore(&priv->lock, flags);
119 wake_up_interruptible(&priv->delta_msr_wait);
120
121 if (!urb->actual_length)
122 return;
123
124 tty = tty_port_tty_get(&port->port);
125 if (!tty)
126 return;
127
128 /* break takes precedence over parity, */
129 /* which takes precedence over framing errors */
130 if (line_status & UART_BREAK_ERROR)
131 tty_flag = TTY_BREAK;
132 else if (line_status & UART_PARITY_ERROR)
133 tty_flag = TTY_PARITY;
134 else if (line_status & UART_FRAME_ERROR)
135 tty_flag = TTY_FRAME;
136 dbg("%s - tty_flag = %d", __func__, tty_flag);
137
138 /* overrun is special, not associated with a char */
139 if (line_status & UART_OVERRUN_ERROR)
140 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
141
142 if (port->port.console && port->sysrq) {
143 for (i = 0; i < urb->actual_length; ++i)
144 if (!usb_serial_handle_sysrq_char(port, data[i]))
145 tty_insert_flip_char(tty, data[i], tty_flag);
146 } else {
147 tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
148 urb->actual_length);
149 }
150
151 tty_flip_buffer_push(tty);
152 tty_kref_put(tty);
153}
154
155static int set_control_lines(struct usb_device *dev, u8 value)
156{
157 /* FIXME - Stubbed out for now */
158 return 0;
159}
160
161static void f81232_break_ctl(struct tty_struct *tty, int break_state)
162{
163 /* FIXME - Stubbed out for now */
164
165 /*
166 * break_state = -1 to turn on break, and 0 to turn off break
167 * see drivers/char/tty_io.c to see it used.
168 * last_set_data_urb_value NEVER has the break bit set in it.
169 */
170}
171
172static void f81232_set_termios(struct tty_struct *tty,
173 struct usb_serial_port *port, struct ktermios *old_termios)
174{
175 /* FIXME - Stubbed out for now */
176
177 /* Don't change anything if nothing has changed */
178 if (!tty_termios_hw_change(tty->termios, old_termios))
179 return;
180
181 /* Do the real work here... */
182}
183
184static int f81232_tiocmget(struct tty_struct *tty)
185{
186 /* FIXME - Stubbed out for now */
187 return 0;
188}
189
190static int f81232_tiocmset(struct tty_struct *tty,
191 unsigned int set, unsigned int clear)
192{
193 /* FIXME - Stubbed out for now */
194 return 0;
195}
196
197static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
198{
199 struct ktermios tmp_termios;
200 int result;
201
202 /* Setup termios */
203 if (tty)
204 f81232_set_termios(tty, port, &tmp_termios);
205
206 dbg("%s - submitting interrupt urb", __func__);
207 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
208 if (result) {
209 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
210 " error %d\n", __func__, result);
211 return result;
212 }
213
214 result = usb_serial_generic_open(tty, port);
215 if (result) {
216 usb_kill_urb(port->interrupt_in_urb);
217 return result;
218 }
219
220 port->port.drain_delay = 256;
221 return 0;
222}
223
224static void f81232_close(struct usb_serial_port *port)
225{
226 usb_serial_generic_close(port);
227 usb_kill_urb(port->interrupt_in_urb);
228}
229
230static void f81232_dtr_rts(struct usb_serial_port *port, int on)
231{
232 struct f81232_private *priv = usb_get_serial_port_data(port);
233 unsigned long flags;
234 u8 control;
235
236 spin_lock_irqsave(&priv->lock, flags);
237 /* Change DTR and RTS */
238 if (on)
239 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
240 else
241 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
242 control = priv->line_control;
243 spin_unlock_irqrestore(&priv->lock, flags);
244 set_control_lines(port->serial->dev, control);
245}
246
247static int f81232_carrier_raised(struct usb_serial_port *port)
248{
249 struct f81232_private *priv = usb_get_serial_port_data(port);
250 if (priv->line_status & UART_DCD)
251 return 1;
252 return 0;
253}
254
255static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
256{
257 struct f81232_private *priv = usb_get_serial_port_data(port);
258 unsigned long flags;
259 unsigned int prevstatus;
260 unsigned int status;
261 unsigned int changed;
262
263 spin_lock_irqsave(&priv->lock, flags);
264 prevstatus = priv->line_status;
265 spin_unlock_irqrestore(&priv->lock, flags);
266
267 while (1) {
268 interruptible_sleep_on(&priv->delta_msr_wait);
269 /* see if a signal did it */
270 if (signal_pending(current))
271 return -ERESTARTSYS;
272
273 spin_lock_irqsave(&priv->lock, flags);
274 status = priv->line_status;
275 spin_unlock_irqrestore(&priv->lock, flags);
276
277 changed = prevstatus ^ status;
278
279 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
280 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
281 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
282 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
283 return 0;
284 }
285 prevstatus = status;
286 }
287 /* NOTREACHED */
288 return 0;
289}
290
291static int f81232_ioctl(struct tty_struct *tty,
292 unsigned int cmd, unsigned long arg)
293{
294 struct serial_struct ser;
295 struct usb_serial_port *port = tty->driver_data;
296 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
297
298 switch (cmd) {
299 case TIOCGSERIAL:
300 memset(&ser, 0, sizeof ser);
301 ser.type = PORT_16654;
302 ser.line = port->serial->minor;
303 ser.port = port->number;
304 ser.baud_base = 460800;
305
306 if (copy_to_user((void __user *)arg, &ser, sizeof ser))
307 return -EFAULT;
308
309 return 0;
310
311 case TIOCMIWAIT:
312 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
313 return wait_modem_info(port, arg);
314 default:
315 dbg("%s not supported = 0x%04x", __func__, cmd);
316 break;
317 }
318 return -ENOIOCTLCMD;
319}
320
321static int f81232_startup(struct usb_serial *serial)
322{
323 struct f81232_private *priv;
324 int i;
325
326 for (i = 0; i < serial->num_ports; ++i) {
327 priv = kzalloc(sizeof(struct f81232_private), GFP_KERNEL);
328 if (!priv)
329 goto cleanup;
330 spin_lock_init(&priv->lock);
331 init_waitqueue_head(&priv->delta_msr_wait);
332 usb_set_serial_port_data(serial->port[i], priv);
333 }
334 return 0;
335
336cleanup:
337 for (--i; i >= 0; --i) {
338 priv = usb_get_serial_port_data(serial->port[i]);
339 kfree(priv);
340 usb_set_serial_port_data(serial->port[i], NULL);
341 }
342 return -ENOMEM;
343}
344
345static void f81232_release(struct usb_serial *serial)
346{
347 int i;
348 struct f81232_private *priv;
349
350 for (i = 0; i < serial->num_ports; ++i) {
351 priv = usb_get_serial_port_data(serial->port[i]);
352 kfree(priv);
353 }
354}
355
356static struct usb_driver f81232_driver = {
357 .name = "f81232",
358 .probe = usb_serial_probe,
359 .disconnect = usb_serial_disconnect,
360 .id_table = id_table,
361 .suspend = usb_serial_suspend,
362 .resume = usb_serial_resume,
363 .no_dynamic_id = 1,
364 .supports_autosuspend = 1,
365};
366
367static struct usb_serial_driver f81232_device = {
368 .driver = {
369 .owner = THIS_MODULE,
370 .name = "f81232",
371 },
372 .id_table = id_table,
373 .usb_driver = &f81232_driver,
374 .num_ports = 1,
375 .bulk_in_size = 256,
376 .bulk_out_size = 256,
377 .open = f81232_open,
378 .close = f81232_close,
379 .dtr_rts = f81232_dtr_rts,
380 .carrier_raised = f81232_carrier_raised,
381 .ioctl = f81232_ioctl,
382 .break_ctl = f81232_break_ctl,
383 .set_termios = f81232_set_termios,
384 .tiocmget = f81232_tiocmget,
385 .tiocmset = f81232_tiocmset,
386 .process_read_urb = f81232_process_read_urb,
387 .read_int_callback = f81232_read_int_callback,
388 .attach = f81232_startup,
389 .release = f81232_release,
390};
391
392static struct usb_serial_driver * const serial_drivers[] = {
393 &f81232_device,
394 NULL,
395};
396
397module_usb_serial_driver(f81232_driver, serial_drivers);
398
399MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
400MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org");
401MODULE_LICENSE("GPL v2");
402
403module_param(debug, bool, S_IRUGO | S_IWUSR);
404MODULE_PARM_DESC(debug, "Debug enabled or not");
405