提交 7af75af2 编写于 作者: V Vadim Tsozik 提交者: Greg Kroah-Hartman

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: NVadim Tsozik <tsozik@yahoo.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 0fe6f1d1
...@@ -78,6 +78,8 @@ ...@@ -78,6 +78,8 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/serial.h> #include <linux/usb/serial.h>
#include <linux/serial.h>
#include <linux/ioctl.h>
#include "mct_u232.h" #include "mct_u232.h"
/* /*
...@@ -104,6 +106,10 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state); ...@@ -104,6 +106,10 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state);
static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file); static int mct_u232_tiocmget(struct tty_struct *tty, struct file *file);
static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file, static int mct_u232_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear); unsigned int set, unsigned int clear);
static int mct_u232_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
static int mct_u232_get_icount(struct tty_struct *tty,
struct serial_icounter_struct *icount);
static void mct_u232_throttle(struct tty_struct *tty); static void mct_u232_throttle(struct tty_struct *tty);
static void mct_u232_unthrottle(struct tty_struct *tty); static void mct_u232_unthrottle(struct tty_struct *tty);
...@@ -150,9 +156,10 @@ static struct usb_serial_driver mct_u232_device = { ...@@ -150,9 +156,10 @@ static struct usb_serial_driver mct_u232_device = {
.tiocmset = mct_u232_tiocmset, .tiocmset = mct_u232_tiocmset,
.attach = mct_u232_startup, .attach = mct_u232_startup,
.release = mct_u232_release, .release = mct_u232_release,
.ioctl = mct_u232_ioctl,
.get_icount = mct_u232_get_icount,
}; };
struct mct_u232_private { struct mct_u232_private {
spinlock_t lock; spinlock_t lock;
unsigned int control_state; /* Modem Line Setting (TIOCM) */ unsigned int control_state; /* Modem Line Setting (TIOCM) */
...@@ -160,6 +167,9 @@ struct mct_u232_private { ...@@ -160,6 +167,9 @@ struct mct_u232_private {
unsigned char last_lsr; /* Line Status Register */ unsigned char last_lsr; /* Line Status Register */
unsigned char last_msr; /* Modem Status Register */ unsigned char last_msr; /* Modem Status Register */
unsigned int rx_flags; /* Throttling flags */ unsigned int rx_flags; /* Throttling flags */
struct async_icount icount;
wait_queue_head_t msr_wait; /* for handling sleeping while waiting
for msr change to happen */
}; };
#define THROTTLED 0x01 #define THROTTLED 0x01
...@@ -386,6 +396,20 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial, ...@@ -386,6 +396,20 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial,
return rc; return rc;
} /* mct_u232_get_modem_stat */ } /* mct_u232_get_modem_stat */
static void mct_u232_msr_to_icount(struct async_icount *icount,
unsigned char msr)
{
/* Translate Control Line states */
if (msr & MCT_U232_MSR_DDSR)
icount->dsr++;
if (msr & MCT_U232_MSR_DCTS)
icount->cts++;
if (msr & MCT_U232_MSR_DRI)
icount->rng++;
if (msr & MCT_U232_MSR_DCD)
icount->dcd++;
} /* mct_u232_msr_to_icount */
static void mct_u232_msr_to_state(unsigned int *control_state, static void mct_u232_msr_to_state(unsigned int *control_state,
unsigned char msr) unsigned char msr)
{ {
...@@ -422,6 +446,7 @@ static int mct_u232_startup(struct usb_serial *serial) ...@@ -422,6 +446,7 @@ static int mct_u232_startup(struct usb_serial *serial)
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
init_waitqueue_head(&priv->msr_wait);
usb_set_serial_port_data(serial->port[0], priv); usb_set_serial_port_data(serial->port[0], priv);
init_waitqueue_head(&serial->port[0]->write_wait); init_waitqueue_head(&serial->port[0]->write_wait);
...@@ -621,6 +646,8 @@ static void mct_u232_read_int_callback(struct urb *urb) ...@@ -621,6 +646,8 @@ static void mct_u232_read_int_callback(struct urb *urb)
/* Record Control Line states */ /* Record Control Line states */
mct_u232_msr_to_state(&priv->control_state, priv->last_msr); mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
mct_u232_msr_to_icount(&priv->icount, priv->last_msr);
#if 0 #if 0
/* Not yet handled. See belkin_sa.c for further information */ /* Not yet handled. See belkin_sa.c for further information */
/* Now to report any errors */ /* Now to report any errors */
...@@ -647,6 +674,7 @@ static void mct_u232_read_int_callback(struct urb *urb) ...@@ -647,6 +674,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
tty_kref_put(tty); tty_kref_put(tty);
} }
#endif #endif
wake_up_interruptible(&priv->msr_wait);
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
exit: exit:
retval = usb_submit_urb(urb, GFP_ATOMIC); retval = usb_submit_urb(urb, GFP_ATOMIC);
...@@ -826,7 +854,6 @@ static void mct_u232_throttle(struct tty_struct *tty) ...@@ -826,7 +854,6 @@ static void mct_u232_throttle(struct tty_struct *tty)
} }
} }
static void mct_u232_unthrottle(struct tty_struct *tty) static void mct_u232_unthrottle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
...@@ -847,6 +874,82 @@ static void mct_u232_unthrottle(struct tty_struct *tty) ...@@ -847,6 +874,82 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
} }
} }
static int mct_u232_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
DEFINE_WAIT(wait);
struct usb_serial_port *port = tty->driver_data;
struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
struct async_icount cnow, cprev;
unsigned long flags;
dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
switch (cmd) {
case TIOCMIWAIT:
dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
spin_lock_irqsave(&mct_u232_port->lock, flags);
cprev = mct_u232_port->icount;
spin_unlock_irqrestore(&mct_u232_port->lock, flags);
for ( ; ; ) {
prepare_to_wait(&mct_u232_port->msr_wait,
&wait, TASK_INTERRUPTIBLE);
schedule();
finish_wait(&mct_u232_port->msr_wait, &wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
spin_lock_irqsave(&mct_u232_port->lock, flags);
cnow = mct_u232_port->icount;
spin_unlock_irqrestore(&mct_u232_port->lock, flags);
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
return -EIO; /* no change => error */
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
return 0;
}
cprev = cnow;
}
}
return -ENOIOCTLCMD;
}
static int mct_u232_get_icount(struct tty_struct *tty,
struct serial_icounter_struct *icount)
{
struct usb_serial_port *port = tty->driver_data;
struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
struct async_icount *ic = &mct_u232_port->icount;
unsigned long flags;
spin_lock_irqsave(&mct_u232_port->lock, flags);
icount->cts = ic->cts;
icount->dsr = ic->dsr;
icount->rng = ic->rng;
icount->dcd = ic->dcd;
icount->rx = ic->rx;
icount->tx = ic->tx;
icount->frame = ic->frame;
icount->overrun = ic->overrun;
icount->parity = ic->parity;
icount->brk = ic->brk;
icount->buf_overrun = ic->buf_overrun;
spin_unlock_irqrestore(&mct_u232_port->lock, flags);
dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d",
__func__, port->number, icount->rx, icount->tx);
return 0;
}
static int __init mct_u232_init(void) static int __init mct_u232_init(void)
{ {
int retval; int retval;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册