aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorVadim Tsozik <vtsozik@optimum.net>2011-01-09 01:00:11 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-02-04 14:42:51 -0500
commit7af75af2424c3a866041e7981d91f01f93235533 (patch)
treeccca09fa2bdc570947762f0d5ad44a681ab6aa27 /drivers/usb/serial
parent0fe6f1d1f612035d78d8d195bbc3485a341386d5 (diff)
USB: serial: mct_u232: added _ioctl, _msr_to_icount and _get_icount functions
Added mct_u232_ioctl (implements TIOCMIWAIT command), mct_u232_get_icount (implements TIOCGICOUNT command) and mct_u232_msr_to_icount functions. MCT U232 P9 is one of a few usb to serail adapters which converts USB +/-5v voltage levels to COM +/-15 voltages. So it can also power COM interfaced devices. This makes it very usable for legacy COM interfaced data-acquisition hardware. I tested new implementation with AWARE Electronics RM-60 radiation meter, which sends pulse via RNG COM line whenever new particle is registered. Signed-off-by: Vadim Tsozik <tsozik@yahoo.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/mct_u232.c107
1 files changed, 105 insertions, 2 deletions
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 2849f8c32015..1e225aacf46e 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -78,6 +78,8 @@
78#include <asm/unaligned.h> 78#include <asm/unaligned.h>
79#include <linux/usb.h> 79#include <linux/usb.h>
80#include <linux/usb/serial.h> 80#include <linux/usb/serial.h>
81#include <linux/serial.h>
82#include <linux/ioctl.h>
81#include "mct_u232.h" 83#include "mct_u232.h"
82 84
83/* 85/*
@@ -104,6 +106,10 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state);
104static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file); 106static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file);
105static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file, 107static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file,
106 unsigned int set, unsigned int clear); 108 unsigned int set, unsigned int clear);
109static int mct_u232_ioctl(struct tty_struct *tty, struct file *file,
110 unsigned int cmd, unsigned long arg);
111static int mct_u232_get_icount(struct tty_struct *tty,
112 struct serial_icounter_struct *icount);
107static void mct_u232_throttle(struct tty_struct *tty); 113static void mct_u232_throttle(struct tty_struct *tty);
108static void mct_u232_unthrottle(struct tty_struct *tty); 114static void mct_u232_unthrottle(struct tty_struct *tty);
109 115
@@ -150,9 +156,10 @@ static struct usb_serial_driver mct_u232_device = {
150 .tiocmset = mct_u232_tiocmset, 156 .tiocmset = mct_u232_tiocmset,
151 .attach = mct_u232_startup, 157 .attach = mct_u232_startup,
152 .release = mct_u232_release, 158 .release = mct_u232_release,
159 .ioctl = mct_u232_ioctl,
160 .get_icount = mct_u232_get_icount,
153}; 161};
154 162
155
156struct mct_u232_private { 163struct mct_u232_private {
157 spinlock_t lock; 164 spinlock_t lock;
158 unsigned int control_state; /* Modem Line Setting (TIOCM) */ 165 unsigned int control_state; /* Modem Line Setting (TIOCM) */
@@ -160,6 +167,9 @@ struct mct_u232_private {
160 unsigned char last_lsr; /* Line Status Register */ 167 unsigned char last_lsr; /* Line Status Register */
161 unsigned char last_msr; /* Modem Status Register */ 168 unsigned char last_msr; /* Modem Status Register */
162 unsigned int rx_flags; /* Throttling flags */ 169 unsigned int rx_flags; /* Throttling flags */
170 struct async_icount icount;
171 wait_queue_head_t msr_wait; /* for handling sleeping while waiting
172 for msr change to happen */
163}; 173};
164 174
165#define THROTTLED 0x01 175#define THROTTLED 0x01
@@ -386,6 +396,20 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial,
386 return rc; 396 return rc;
387} /* mct_u232_get_modem_stat */ 397} /* mct_u232_get_modem_stat */
388 398
399static void mct_u232_msr_to_icount(struct async_icount *icount,
400 unsigned char msr)
401{
402 /* Translate Control Line states */
403 if (msr & MCT_U232_MSR_DDSR)
404 icount->dsr++;
405 if (msr & MCT_U232_MSR_DCTS)
406 icount->cts++;
407 if (msr & MCT_U232_MSR_DRI)
408 icount->rng++;
409 if (msr & MCT_U232_MSR_DCD)
410 icount->dcd++;
411} /* mct_u232_msr_to_icount */
412
389static void mct_u232_msr_to_state(unsigned int *control_state, 413static void mct_u232_msr_to_state(unsigned int *control_state,
390 unsigned char msr) 414 unsigned char msr)
391{ 415{
@@ -422,6 +446,7 @@ static int mct_u232_startup(struct usb_serial *serial)
422 if (!priv) 446 if (!priv)
423 return -ENOMEM; 447 return -ENOMEM;
424 spin_lock_init(&priv->lock); 448 spin_lock_init(&priv->lock);
449 init_waitqueue_head(&priv->msr_wait);
425 usb_set_serial_port_data(serial->port[0], priv); 450 usb_set_serial_port_data(serial->port[0], priv);
426 451
427 init_waitqueue_head(&serial->port[0]->write_wait); 452 init_waitqueue_head(&serial->port[0]->write_wait);
@@ -621,6 +646,8 @@ static void mct_u232_read_int_callback(struct urb *urb)
621 /* Record Control Line states */ 646 /* Record Control Line states */
622 mct_u232_msr_to_state(&priv->control_state, priv->last_msr); 647 mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
623 648
649 mct_u232_msr_to_icount(&priv->icount, priv->last_msr);
650
624#if 0 651#if 0
625 /* Not yet handled. See belkin_sa.c for further information */ 652 /* Not yet handled. See belkin_sa.c for further information */
626 /* Now to report any errors */ 653 /* Now to report any errors */
@@ -647,6 +674,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
647 tty_kref_put(tty); 674 tty_kref_put(tty);
648 } 675 }
649#endif 676#endif
677 wake_up_interruptible(&priv->msr_wait);
650 spin_unlock_irqrestore(&priv->lock, flags); 678 spin_unlock_irqrestore(&priv->lock, flags);
651exit: 679exit:
652 retval = usb_submit_urb(urb, GFP_ATOMIC); 680 retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -826,7 +854,6 @@ static void mct_u232_throttle(struct tty_struct *tty)
826 } 854 }
827} 855}
828 856
829
830static void mct_u232_unthrottle(struct tty_struct *tty) 857static void mct_u232_unthrottle(struct tty_struct *tty)
831{ 858{
832 struct usb_serial_port *port = tty->driver_data; 859 struct usb_serial_port *port = tty->driver_data;
@@ -847,6 +874,82 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
847 } 874 }
848} 875}
849 876
877static int mct_u232_ioctl(struct tty_struct *tty, struct file *file,
878 unsigned int cmd, unsigned long arg)
879{
880 DEFINE_WAIT(wait);
881 struct usb_serial_port *port = tty->driver_data;
882 struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
883 struct async_icount cnow, cprev;
884 unsigned long flags;
885
886 dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
887
888 switch (cmd) {
889
890 case TIOCMIWAIT:
891
892 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
893
894 spin_lock_irqsave(&mct_u232_port->lock, flags);
895 cprev = mct_u232_port->icount;
896 spin_unlock_irqrestore(&mct_u232_port->lock, flags);
897 for ( ; ; ) {
898 prepare_to_wait(&mct_u232_port->msr_wait,
899 &wait, TASK_INTERRUPTIBLE);
900 schedule();
901 finish_wait(&mct_u232_port->msr_wait, &wait);
902 /* see if a signal did it */
903 if (signal_pending(current))
904 return -ERESTARTSYS;
905 spin_lock_irqsave(&mct_u232_port->lock, flags);
906 cnow = mct_u232_port->icount;
907 spin_unlock_irqrestore(&mct_u232_port->lock, flags);
908 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
909 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
910 return -EIO; /* no change => error */
911 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
912 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
913 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
914 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
915 return 0;
916 }
917 cprev = cnow;
918 }
919
920 }
921 return -ENOIOCTLCMD;
922}
923
924static int mct_u232_get_icount(struct tty_struct *tty,
925 struct serial_icounter_struct *icount)
926{
927 struct usb_serial_port *port = tty->driver_data;
928 struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
929 struct async_icount *ic = &mct_u232_port->icount;
930 unsigned long flags;
931
932 spin_lock_irqsave(&mct_u232_port->lock, flags);
933
934 icount->cts = ic->cts;
935 icount->dsr = ic->dsr;
936 icount->rng = ic->rng;
937 icount->dcd = ic->dcd;
938 icount->rx = ic->rx;
939 icount->tx = ic->tx;
940 icount->frame = ic->frame;
941 icount->overrun = ic->overrun;
942 icount->parity = ic->parity;
943 icount->brk = ic->brk;
944 icount->buf_overrun = ic->buf_overrun;
945
946 spin_unlock_irqrestore(&mct_u232_port->lock, flags);
947
948 dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d",
949 __func__, port->number, icount->rx, icount->tx);
950 return 0;
951}
952
850static int __init mct_u232_init(void) 953static int __init mct_u232_init(void)
851{ 954{
852 int retval; 955 int retval;