diff options
author | Vadim Tsozik <vtsozik@optimum.net> | 2011-01-09 01:00:11 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-02-04 14:42:51 -0500 |
commit | 7af75af2424c3a866041e7981d91f01f93235533 (patch) | |
tree | ccca09fa2bdc570947762f0d5ad44a681ab6aa27 | |
parent | 0fe6f1d1f612035d78d8d195bbc3485a341386d5 (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>
-rw-r--r-- | drivers/usb/serial/mct_u232.c | 107 |
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); | |||
104 | static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file); | 106 | static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file); |
105 | static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file, | 107 | static 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); |
109 | static int mct_u232_ioctl(struct tty_struct *tty, struct file *file, | ||
110 | unsigned int cmd, unsigned long arg); | ||
111 | static int mct_u232_get_icount(struct tty_struct *tty, | ||
112 | struct serial_icounter_struct *icount); | ||
107 | static void mct_u232_throttle(struct tty_struct *tty); | 113 | static void mct_u232_throttle(struct tty_struct *tty); |
108 | static void mct_u232_unthrottle(struct tty_struct *tty); | 114 | static 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 | |||
156 | struct mct_u232_private { | 163 | struct 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 | ||
399 | static 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 | |||
389 | static void mct_u232_msr_to_state(unsigned int *control_state, | 413 | static 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); |
651 | exit: | 679 | exit: |
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 | |||
830 | static void mct_u232_unthrottle(struct tty_struct *tty) | 857 | static 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 | ||
877 | static 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 | |||
924 | static 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 | |||
850 | static int __init mct_u232_init(void) | 953 | static int __init mct_u232_init(void) |
851 | { | 954 | { |
852 | int retval; | 955 | int retval; |