]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/usb/serial/f81232.c
USB: f81232: implement read IIR/MSR with endpoint
[karo-tx-linux.git] / drivers / usb / serial / f81232.c
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/slab.h>
16 #include <linux/tty.h>
17 #include <linux/tty_driver.h>
18 #include <linux/tty_flip.h>
19 #include <linux/serial.h>
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/mutex.h>
23 #include <linux/uaccess.h>
24 #include <linux/usb.h>
25 #include <linux/usb/serial.h>
26 #include <linux/serial_reg.h>
27
28 static const struct usb_device_id id_table[] = {
29         { USB_DEVICE(0x1934, 0x0706) },
30         { }                                     /* Terminating entry */
31 };
32 MODULE_DEVICE_TABLE(usb, id_table);
33
34 /* USB Control EP parameter */
35 #define F81232_REGISTER_REQUEST 0xa0
36 #define F81232_GET_REGISTER             0xc0
37
38 #define SERIAL_BASE_ADDRESS                     0x0120
39 #define MODEM_STATUS_REGISTER           (0x06 + SERIAL_BASE_ADDRESS)
40
41 #define CONTROL_DTR                     0x01
42 #define CONTROL_RTS                     0x02
43
44 #define UART_STATE                      0x08
45 #define UART_STATE_TRANSIENT_MASK       0x74
46 #define UART_DCD                        0x01
47 #define UART_DSR                        0x02
48 #define UART_BREAK_ERROR                0x04
49 #define UART_RING                       0x08
50 #define UART_FRAME_ERROR                0x10
51 #define UART_PARITY_ERROR               0x20
52 #define UART_OVERRUN_ERROR              0x40
53 #define UART_CTS                        0x80
54
55 struct f81232_private {
56         struct mutex lock;
57         u8 line_control;
58         u8 modem_status;
59         struct work_struct interrupt_work;
60         struct usb_serial_port *port;
61 };
62
63 static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
64 {
65         int status;
66         u8 *tmp;
67         struct usb_device *dev = port->serial->dev;
68
69         tmp = kmalloc(sizeof(*val), GFP_KERNEL);
70         if (!tmp)
71                 return -ENOMEM;
72
73         status = usb_control_msg(dev,
74                                 usb_rcvctrlpipe(dev, 0),
75                                 F81232_REGISTER_REQUEST,
76                                 F81232_GET_REGISTER,
77                                 reg,
78                                 0,
79                                 tmp,
80                                 sizeof(*val),
81                                 USB_CTRL_GET_TIMEOUT);
82         if (status != sizeof(*val)) {
83                 dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
84
85                 if (status < 0)
86                         status = usb_translate_errors(status);
87                 else
88                         status = -EIO;
89         } else {
90                 status = 0;
91                 *val = *tmp;
92         }
93
94         kfree(tmp);
95         return status;
96 }
97
98 static void f81232_read_msr(struct usb_serial_port *port)
99 {
100         int status;
101         u8 current_msr;
102         struct tty_struct *tty;
103         struct f81232_private *priv = usb_get_serial_port_data(port);
104
105         mutex_lock(&priv->lock);
106         status = f81232_get_register(port, MODEM_STATUS_REGISTER,
107                         &current_msr);
108         if (status) {
109                 dev_err(&port->dev, "%s fail, status: %d\n", __func__, status);
110                 mutex_unlock(&priv->lock);
111                 return;
112         }
113
114         if (!(current_msr & UART_MSR_ANY_DELTA)) {
115                 mutex_unlock(&priv->lock);
116                 return;
117         }
118
119         priv->modem_status = current_msr;
120
121         if (current_msr & UART_MSR_DCTS)
122                 port->icount.cts++;
123         if (current_msr & UART_MSR_DDSR)
124                 port->icount.dsr++;
125         if (current_msr & UART_MSR_TERI)
126                 port->icount.rng++;
127         if (current_msr & UART_MSR_DDCD) {
128                 port->icount.dcd++;
129                 tty = tty_port_tty_get(&port->port);
130                 if (tty) {
131                         usb_serial_handle_dcd_change(port, tty,
132                                         current_msr & UART_MSR_DCD);
133
134                         tty_kref_put(tty);
135                 }
136         }
137
138         wake_up_interruptible(&port->port.delta_msr_wait);
139         mutex_unlock(&priv->lock);
140 }
141
142 static void f81232_update_line_status(struct usb_serial_port *port,
143                                       unsigned char *data,
144                                       size_t actual_length)
145 {
146         struct f81232_private *priv = usb_get_serial_port_data(port);
147
148         if (!actual_length)
149                 return;
150
151         switch (data[0] & 0x07) {
152         case 0x00: /* msr change */
153                 dev_dbg(&port->dev, "IIR: MSR Change: %02x\n", data[0]);
154                 schedule_work(&priv->interrupt_work);
155                 break;
156         case 0x02: /* tx-empty */
157                 break;
158         case 0x04: /* rx data available */
159                 break;
160         case 0x06: /* lsr change */
161                 /* we can forget it. the LSR will read from bulk-in */
162                 dev_dbg(&port->dev, "IIR: LSR Change: %02x\n", data[0]);
163                 break;
164         }
165 }
166
167 static void f81232_read_int_callback(struct urb *urb)
168 {
169         struct usb_serial_port *port =  urb->context;
170         unsigned char *data = urb->transfer_buffer;
171         unsigned int actual_length = urb->actual_length;
172         int status = urb->status;
173         int retval;
174
175         switch (status) {
176         case 0:
177                 /* success */
178                 break;
179         case -ECONNRESET:
180         case -ENOENT:
181         case -ESHUTDOWN:
182                 /* this urb is terminated, clean up */
183                 dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
184                         __func__, status);
185                 return;
186         default:
187                 dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
188                         __func__, status);
189                 goto exit;
190         }
191
192         usb_serial_debug_data(&port->dev, __func__,
193                               urb->actual_length, urb->transfer_buffer);
194
195         f81232_update_line_status(port, data, actual_length);
196
197 exit:
198         retval = usb_submit_urb(urb, GFP_ATOMIC);
199         if (retval)
200                 dev_err(&urb->dev->dev,
201                         "%s - usb_submit_urb failed with result %d\n",
202                         __func__, retval);
203 }
204
205 static void f81232_process_read_urb(struct urb *urb)
206 {
207         struct usb_serial_port *port = urb->context;
208         unsigned char *data = urb->transfer_buffer;
209         char tty_flag;
210         unsigned int i;
211         u8 lsr;
212
213         /*
214          * When opening the port we get a 1-byte packet with the current LSR,
215          * which we discard.
216          */
217         if ((urb->actual_length < 2) || (urb->actual_length % 2))
218                 return;
219
220         /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */
221
222         for (i = 0; i < urb->actual_length; i += 2) {
223                 tty_flag = TTY_NORMAL;
224                 lsr = data[i];
225
226                 if (lsr & UART_LSR_BRK_ERROR_BITS) {
227                         if (lsr & UART_LSR_BI) {
228                                 tty_flag = TTY_BREAK;
229                                 port->icount.brk++;
230                                 usb_serial_handle_break(port);
231                         } else if (lsr & UART_LSR_PE) {
232                                 tty_flag = TTY_PARITY;
233                                 port->icount.parity++;
234                         } else if (lsr & UART_LSR_FE) {
235                                 tty_flag = TTY_FRAME;
236                                 port->icount.frame++;
237                         }
238
239                         if (lsr & UART_LSR_OE) {
240                                 port->icount.overrun++;
241                                 tty_insert_flip_char(&port->port, 0,
242                                                 TTY_OVERRUN);
243                         }
244                 }
245
246                 if (port->port.console && port->sysrq) {
247                         if (usb_serial_handle_sysrq_char(port, data[i + 1]))
248                                 continue;
249                 }
250
251                 tty_insert_flip_char(&port->port, data[i + 1], tty_flag);
252         }
253
254         tty_flip_buffer_push(&port->port);
255 }
256
257 static int set_control_lines(struct usb_device *dev, u8 value)
258 {
259         /* FIXME - Stubbed out for now */
260         return 0;
261 }
262
263 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
264 {
265         /* FIXME - Stubbed out for now */
266
267         /*
268          * break_state = -1 to turn on break, and 0 to turn off break
269          * see drivers/char/tty_io.c to see it used.
270          * last_set_data_urb_value NEVER has the break bit set in it.
271          */
272 }
273
274 static void f81232_set_termios(struct tty_struct *tty,
275                 struct usb_serial_port *port, struct ktermios *old_termios)
276 {
277         /* FIXME - Stubbed out for now */
278
279         /* Don't change anything if nothing has changed */
280         if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
281                 return;
282
283         /* Do the real work here... */
284         if (old_termios)
285                 tty_termios_copy_hw(&tty->termios, old_termios);
286 }
287
288 static int f81232_tiocmget(struct tty_struct *tty)
289 {
290         /* FIXME - Stubbed out for now */
291         return 0;
292 }
293
294 static int f81232_tiocmset(struct tty_struct *tty,
295                         unsigned int set, unsigned int clear)
296 {
297         /* FIXME - Stubbed out for now */
298         return 0;
299 }
300
301 static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
302 {
303         int result;
304
305         /* Setup termios */
306         if (tty)
307                 f81232_set_termios(tty, port, NULL);
308
309         result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
310         if (result) {
311                 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
312                         " error %d\n", __func__, result);
313                 return result;
314         }
315
316         result = usb_serial_generic_open(tty, port);
317         if (result) {
318                 usb_kill_urb(port->interrupt_in_urb);
319                 return result;
320         }
321
322         return 0;
323 }
324
325 static void f81232_close(struct usb_serial_port *port)
326 {
327         usb_serial_generic_close(port);
328         usb_kill_urb(port->interrupt_in_urb);
329 }
330
331 static void f81232_dtr_rts(struct usb_serial_port *port, int on)
332 {
333         struct f81232_private *priv = usb_get_serial_port_data(port);
334         u8 control;
335
336         mutex_lock(&priv->lock);
337         /* Change DTR and RTS */
338         if (on)
339                 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
340         else
341                 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
342         control = priv->line_control;
343         mutex_unlock(&priv->lock);
344         set_control_lines(port->serial->dev, control);
345 }
346
347 static int f81232_carrier_raised(struct usb_serial_port *port)
348 {
349         struct f81232_private *priv = usb_get_serial_port_data(port);
350         if (priv->modem_status & UART_DCD)
351                 return 1;
352         return 0;
353 }
354
355 static int f81232_ioctl(struct tty_struct *tty,
356                         unsigned int cmd, unsigned long arg)
357 {
358         struct serial_struct ser;
359         struct usb_serial_port *port = tty->driver_data;
360
361         switch (cmd) {
362         case TIOCGSERIAL:
363                 memset(&ser, 0, sizeof ser);
364                 ser.type = PORT_16654;
365                 ser.line = port->minor;
366                 ser.port = port->port_number;
367                 ser.baud_base = 460800;
368
369                 if (copy_to_user((void __user *)arg, &ser, sizeof ser))
370                         return -EFAULT;
371
372                 return 0;
373         default:
374                 break;
375         }
376         return -ENOIOCTLCMD;
377 }
378
379 static void  f81232_interrupt_work(struct work_struct *work)
380 {
381         struct f81232_private *priv =
382                 container_of(work, struct f81232_private, interrupt_work);
383
384         f81232_read_msr(priv->port);
385 }
386
387 static int f81232_port_probe(struct usb_serial_port *port)
388 {
389         struct f81232_private *priv;
390
391         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
392         if (!priv)
393                 return -ENOMEM;
394
395         mutex_init(&priv->lock);
396         INIT_WORK(&priv->interrupt_work,  f81232_interrupt_work);
397
398         usb_set_serial_port_data(port, priv);
399
400         port->port.drain_delay = 256;
401         priv->port = port;
402
403         return 0;
404 }
405
406 static int f81232_port_remove(struct usb_serial_port *port)
407 {
408         struct f81232_private *priv;
409
410         priv = usb_get_serial_port_data(port);
411         kfree(priv);
412
413         return 0;
414 }
415
416 static struct usb_serial_driver f81232_device = {
417         .driver = {
418                 .owner =        THIS_MODULE,
419                 .name =         "f81232",
420         },
421         .id_table =             id_table,
422         .num_ports =            1,
423         .bulk_in_size =         256,
424         .bulk_out_size =        256,
425         .open =                 f81232_open,
426         .close =                f81232_close,
427         .dtr_rts =              f81232_dtr_rts,
428         .carrier_raised =       f81232_carrier_raised,
429         .ioctl =                f81232_ioctl,
430         .break_ctl =            f81232_break_ctl,
431         .set_termios =          f81232_set_termios,
432         .tiocmget =             f81232_tiocmget,
433         .tiocmset =             f81232_tiocmset,
434         .tiocmiwait =           usb_serial_generic_tiocmiwait,
435         .process_read_urb =     f81232_process_read_urb,
436         .read_int_callback =    f81232_read_int_callback,
437         .port_probe =           f81232_port_probe,
438         .port_remove =          f81232_port_remove,
439 };
440
441 static struct usb_serial_driver * const serial_drivers[] = {
442         &f81232_device,
443         NULL,
444 };
445
446 module_usb_serial_driver(serial_drivers, id_table);
447
448 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
449 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org");
450 MODULE_LICENSE("GPL v2");