diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/usb/serial/mct_u232.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/usb/serial/mct_u232.c')
-rw-r--r-- | drivers/usb/serial/mct_u232.c | 122 |
1 files changed, 114 insertions, 8 deletions
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 7aa01b95b1d4..ba0d28727ccb 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 | /* |
@@ -101,9 +103,13 @@ static void mct_u232_read_int_callback(struct urb *urb); | |||
101 | static void mct_u232_set_termios(struct tty_struct *tty, | 103 | static void mct_u232_set_termios(struct tty_struct *tty, |
102 | struct usb_serial_port *port, struct ktermios *old); | 104 | struct usb_serial_port *port, struct ktermios *old); |
103 | static void mct_u232_break_ctl(struct tty_struct *tty, int break_state); | 105 | 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); |
105 | static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file, | 107 | static int mct_u232_tiocmset(struct tty_struct *tty, |
106 | unsigned int set, unsigned int clear); | 108 | unsigned int set, unsigned int clear); |
109 | static int mct_u232_ioctl(struct tty_struct *tty, | ||
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); |
@@ -549,9 +574,12 @@ static void mct_u232_close(struct usb_serial_port *port) | |||
549 | { | 574 | { |
550 | dbg("%s port %d", __func__, port->number); | 575 | dbg("%s port %d", __func__, port->number); |
551 | 576 | ||
552 | usb_serial_generic_close(port); | 577 | if (port->serial->dev) { |
553 | if (port->serial->dev) | 578 | /* shutdown our urbs */ |
579 | usb_kill_urb(port->write_urb); | ||
580 | usb_kill_urb(port->read_urb); | ||
554 | usb_kill_urb(port->interrupt_in_urb); | 581 | usb_kill_urb(port->interrupt_in_urb); |
582 | } | ||
555 | } /* mct_u232_close */ | 583 | } /* mct_u232_close */ |
556 | 584 | ||
557 | 585 | ||
@@ -618,6 +646,8 @@ static void mct_u232_read_int_callback(struct urb *urb) | |||
618 | /* Record Control Line states */ | 646 | /* Record Control Line states */ |
619 | mct_u232_msr_to_state(&priv->control_state, priv->last_msr); | 647 | mct_u232_msr_to_state(&priv->control_state, priv->last_msr); |
620 | 648 | ||
649 | mct_u232_msr_to_icount(&priv->icount, priv->last_msr); | ||
650 | |||
621 | #if 0 | 651 | #if 0 |
622 | /* Not yet handled. See belkin_sa.c for further information */ | 652 | /* Not yet handled. See belkin_sa.c for further information */ |
623 | /* Now to report any errors */ | 653 | /* Now to report any errors */ |
@@ -644,6 +674,7 @@ static void mct_u232_read_int_callback(struct urb *urb) | |||
644 | tty_kref_put(tty); | 674 | tty_kref_put(tty); |
645 | } | 675 | } |
646 | #endif | 676 | #endif |
677 | wake_up_interruptible(&priv->msr_wait); | ||
647 | spin_unlock_irqrestore(&priv->lock, flags); | 678 | spin_unlock_irqrestore(&priv->lock, flags); |
648 | exit: | 679 | exit: |
649 | retval = usb_submit_urb(urb, GFP_ATOMIC); | 680 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
@@ -759,7 +790,7 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) | |||
759 | } /* mct_u232_break_ctl */ | 790 | } /* mct_u232_break_ctl */ |
760 | 791 | ||
761 | 792 | ||
762 | static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file) | 793 | static int mct_u232_tiocmget(struct tty_struct *tty) |
763 | { | 794 | { |
764 | struct usb_serial_port *port = tty->driver_data; | 795 | struct usb_serial_port *port = tty->driver_data; |
765 | struct mct_u232_private *priv = usb_get_serial_port_data(port); | 796 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
@@ -775,7 +806,7 @@ static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file) | |||
775 | return control_state; | 806 | return control_state; |
776 | } | 807 | } |
777 | 808 | ||
778 | static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file, | 809 | static int mct_u232_tiocmset(struct tty_struct *tty, |
779 | unsigned int set, unsigned int clear) | 810 | unsigned int set, unsigned int clear) |
780 | { | 811 | { |
781 | struct usb_serial_port *port = tty->driver_data; | 812 | struct usb_serial_port *port = tty->driver_data; |
@@ -823,7 +854,6 @@ static void mct_u232_throttle(struct tty_struct *tty) | |||
823 | } | 854 | } |
824 | } | 855 | } |
825 | 856 | ||
826 | |||
827 | static void mct_u232_unthrottle(struct tty_struct *tty) | 857 | static void mct_u232_unthrottle(struct tty_struct *tty) |
828 | { | 858 | { |
829 | struct usb_serial_port *port = tty->driver_data; | 859 | struct usb_serial_port *port = tty->driver_data; |
@@ -844,6 +874,82 @@ static void mct_u232_unthrottle(struct tty_struct *tty) | |||
844 | } | 874 | } |
845 | } | 875 | } |
846 | 876 | ||
877 | static int mct_u232_ioctl(struct tty_struct *tty, | ||
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 | |||
847 | static int __init mct_u232_init(void) | 953 | static int __init mct_u232_init(void) |
848 | { | 954 | { |
849 | int retval; | 955 | int retval; |