plug various tty/serial stack leaks
This commit is contained in:
		
							parent
							
								
									e7fe04dcca
								
							
						
					
					
						commit
						9a17bea44f
					
				
							
								
								
									
										10
									
								
								kernel.spec
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								kernel.spec
									
									
									
									
									
								
							| @ -742,6 +742,9 @@ Patch12406: posix-cpu-timers-workaround-to-suppress-problems-with-mt-exec.patch | ||||
| 
 | ||||
| Patch12407: hda_realtek-handle-unset-external-amp-bits.patch | ||||
| 
 | ||||
| Patch12410: tty-make-tiocgicount-a-handler.patch | ||||
| Patch12411: tty-icount-changeover-for-other-main-devices.patch | ||||
| 
 | ||||
| %endif | ||||
| 
 | ||||
| BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root | ||||
| @ -1384,6 +1387,10 @@ ApplyPatch posix-cpu-timers-workaround-to-suppress-problems-with-mt-exec.patch | ||||
| # rhbz#657388 | ||||
| ApplyPatch hda_realtek-handle-unset-external-amp-bits.patch | ||||
| 
 | ||||
| # CVE-2010-4077, CVE-2010-4075 (rhbz#648660, #648663) | ||||
| ApplyPatch tty-make-tiocgicount-a-handler.patch | ||||
| ApplyPatch tty-icount-changeover-for-other-main-devices.patch | ||||
| 
 | ||||
| # END OF PATCH APPLICATIONS | ||||
| 
 | ||||
| %endif | ||||
| @ -1997,6 +2004,9 @@ fi | ||||
| #                 ||     || | ||||
| 
 | ||||
| %changelog | ||||
| * Fri Nov 26 2010 Kyle McMartin <kyle@redhat.com> | ||||
| - Plug stack leaks in tty/serial drivers. (#648663, #648660) | ||||
| 
 | ||||
| * Fri Nov 26 2010 Kyle McMartin <kyle@redhat.com> | ||||
| - hda/realtek: handle unset external amp config (#657388) | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										980
									
								
								tty-icount-changeover-for-other-main-devices.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										980
									
								
								tty-icount-changeover-for-other-main-devices.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,980 @@ | ||||
| From 9f13e0aa6e05b9b773f952a435afdc0b4d10e5dc Mon Sep 17 00:00:00 2001 | ||||
| From: Alan Cox <alan@linux.intel.com> | ||||
| Date: Thu, 16 Sep 2010 18:21:52 +0100 | ||||
| Subject: [PATCH 2/2] tty: icount changeover for other main devices | ||||
| 
 | ||||
| Again basically cut and paste | ||||
| 
 | ||||
| Convert the main driver set to use the hooks for GICOUNT | ||||
| 
 | ||||
| Signed-off-by: Alan Cox <alan@linux.intel.com> | ||||
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | ||||
| ---
 | ||||
|  arch/ia64/hp/sim/simserial.c      |   12 +------ | ||||
|  drivers/char/amiserial.c          |   56 ++++++++++++++++------------- | ||||
|  drivers/char/cyclades.c           |   49 +++++++++++++------------ | ||||
|  drivers/char/ip2/ip2main.c        |   72 ++++++++++++++++++++++--------------- | ||||
|  drivers/char/mxser.c              |   62 ++++++++++++++++++-------------- | ||||
|  drivers/char/nozomi.c             |   37 +++++++++---------- | ||||
|  drivers/char/pcmcia/synclink_cs.c |   60 ++++++++++++++----------------- | ||||
|  drivers/char/synclink.c           |   73 +++++++++++++++++-------------------- | ||||
|  drivers/char/synclink_gt.c        |   55 +++++++++++++++------------- | ||||
|  drivers/char/synclinkmp.c         |   61 ++++++++++++++----------------- | ||||
|  drivers/serial/68360serial.c      |   51 +++++++++++++------------- | ||||
|  net/bluetooth/rfcomm/tty.c        |    4 -- | ||||
|  12 files changed, 297 insertions(+), 295 deletions(-) | ||||
| 
 | ||||
| diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
 | ||||
| index 1e8d71a..13633da 100644
 | ||||
| --- a/arch/ia64/hp/sim/simserial.c
 | ||||
| +++ b/arch/ia64/hp/sim/simserial.c
 | ||||
| @@ -395,7 +395,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|  { | ||||
|  	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||||
|  	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && | ||||
| -	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 | ||||
| +	    (cmd != TIOCMIWAIT)) {
 | ||||
|  		if (tty->flags & (1 << TTY_IO_ERROR)) | ||||
|  		    return -EIO; | ||||
|  	} | ||||
| @@ -433,16 +433,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|  		case TIOCMIWAIT: | ||||
|  			printk(KERN_INFO "rs_ioctl: TIOCMIWAIT: called\n"); | ||||
|  			return 0; | ||||
| -		/*
 | ||||
| -		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| -		 * Return: write counters to the user passed counter struct
 | ||||
| -		 * NB: both 1->0 and 0->1 transitions are counted except for
 | ||||
| -		 *     RI where only 0->1 is counted.
 | ||||
| -		 */
 | ||||
| -		case TIOCGICOUNT:
 | ||||
| -			printk(KERN_INFO "rs_ioctl: TIOCGICOUNT called\n");
 | ||||
| -			return 0;
 | ||||
| -
 | ||||
|  		case TIOCSERGWILD: | ||||
|  		case TIOCSERSWILD: | ||||
|  			/* "setserial -W" is called in Debian boot */ | ||||
| diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
 | ||||
| index a11c8c9..b0a7046 100644
 | ||||
| --- a/drivers/char/amiserial.c
 | ||||
| +++ b/drivers/char/amiserial.c
 | ||||
| @@ -1263,6 +1263,36 @@ static int rs_break(struct tty_struct *tty, int break_state)
 | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
| +/*
 | ||||
| + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| + * Return: write counters to the user passed counter struct
 | ||||
| + * NB: both 1->0 and 0->1 transitions are counted except for
 | ||||
| + *     RI where only 0->1 is counted.
 | ||||
| + */
 | ||||
| +static int rs_get_icount(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *icount)
 | ||||
| +{
 | ||||
| +	struct async_struct *info = tty->driver_data;
 | ||||
| +	struct async_icount cnow;
 | ||||
| +	unsigned long flags;
 | ||||
| +
 | ||||
| +	local_irq_save(flags);
 | ||||
| +	cnow = info->state->icount;
 | ||||
| +	local_irq_restore(flags);
 | ||||
| +	icount->cts = cnow.cts;
 | ||||
| +	icount->dsr = cnow.dsr;
 | ||||
| +	icount->rng = cnow.rng;
 | ||||
| +	icount->dcd = cnow.dcd;
 | ||||
| +	icount->rx = cnow.rx;
 | ||||
| +	icount->tx = cnow.tx;
 | ||||
| +	icount->frame = cnow.frame;
 | ||||
| +	icount->overrun = cnow.overrun;
 | ||||
| +	icount->parity = cnow.parity;
 | ||||
| +	icount->brk = cnow.brk;
 | ||||
| +	icount->buf_overrun = cnow.buf_overrun;
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
|   | ||||
|  static int rs_ioctl(struct tty_struct *tty, struct file * file, | ||||
|  		    unsigned int cmd, unsigned long arg) | ||||
| @@ -1332,31 +1362,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|  			} | ||||
|  			/* NOTREACHED */ | ||||
|   | ||||
| -		/* 
 | ||||
| -		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| -		 * Return: write counters to the user passed counter struct
 | ||||
| -		 * NB: both 1->0 and 0->1 transitions are counted except for
 | ||||
| -		 *     RI where only 0->1 is counted.
 | ||||
| -		 */
 | ||||
| -		case TIOCGICOUNT:
 | ||||
| -			local_irq_save(flags);
 | ||||
| -			cnow = info->state->icount;
 | ||||
| -			local_irq_restore(flags);
 | ||||
| -			icount.cts = cnow.cts;
 | ||||
| -			icount.dsr = cnow.dsr;
 | ||||
| -			icount.rng = cnow.rng;
 | ||||
| -			icount.dcd = cnow.dcd;
 | ||||
| -			icount.rx = cnow.rx;
 | ||||
| -			icount.tx = cnow.tx;
 | ||||
| -			icount.frame = cnow.frame;
 | ||||
| -			icount.overrun = cnow.overrun;
 | ||||
| -			icount.parity = cnow.parity;
 | ||||
| -			icount.brk = cnow.brk;
 | ||||
| -			icount.buf_overrun = cnow.buf_overrun;
 | ||||
| -
 | ||||
| -			if (copy_to_user(argp, &icount, sizeof(icount)))
 | ||||
| -				return -EFAULT;
 | ||||
| -			return 0;
 | ||||
|  		case TIOCSERGWILD: | ||||
|  		case TIOCSERSWILD: | ||||
|  			/* "setserial -W" is called in Debian boot */ | ||||
| @@ -1958,6 +1963,7 @@ static const struct tty_operations serial_ops = {
 | ||||
|  	.wait_until_sent = rs_wait_until_sent, | ||||
|  	.tiocmget = rs_tiocmget, | ||||
|  	.tiocmset = rs_tiocmset, | ||||
| +	.get_icount = rs_get_icount,
 | ||||
|  	.proc_fops = &rs_proc_fops, | ||||
|  }; | ||||
|   | ||||
| diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
 | ||||
| index 27aad94..4f152c2 100644
 | ||||
| --- a/drivers/char/cyclades.c
 | ||||
| +++ b/drivers/char/cyclades.c
 | ||||
| @@ -2790,29 +2790,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  		 * NB: both 1->0 and 0->1 transitions are counted except for | ||||
|  		 *     RI where only 0->1 is counted. | ||||
|  		 */ | ||||
| -	case TIOCGICOUNT: {
 | ||||
| -		struct serial_icounter_struct sic = { };
 | ||||
| -
 | ||||
| -		spin_lock_irqsave(&info->card->card_lock, flags);
 | ||||
| -		cnow = info->icount;
 | ||||
| -		spin_unlock_irqrestore(&info->card->card_lock, flags);
 | ||||
| -
 | ||||
| -		sic.cts = cnow.cts;
 | ||||
| -		sic.dsr = cnow.dsr;
 | ||||
| -		sic.rng = cnow.rng;
 | ||||
| -		sic.dcd = cnow.dcd;
 | ||||
| -		sic.rx = cnow.rx;
 | ||||
| -		sic.tx = cnow.tx;
 | ||||
| -		sic.frame = cnow.frame;
 | ||||
| -		sic.overrun = cnow.overrun;
 | ||||
| -		sic.parity = cnow.parity;
 | ||||
| -		sic.brk = cnow.brk;
 | ||||
| -		sic.buf_overrun = cnow.buf_overrun;
 | ||||
| -
 | ||||
| -		if (copy_to_user(argp, &sic, sizeof(sic)))
 | ||||
| -			ret_val = -EFAULT;
 | ||||
| -		break;
 | ||||
| -	}
 | ||||
|  	default: | ||||
|  		ret_val = -ENOIOCTLCMD; | ||||
|  	} | ||||
| @@ -2823,6 +2800,31 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  	return ret_val; | ||||
|  }				/* cy_ioctl */ | ||||
|   | ||||
| +static int cy_get_icount(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *sic)
 | ||||
| +{
 | ||||
| +	struct cyclades_port *info = tty->driver_data;
 | ||||
| +	struct cyclades_icount cnow;	/* Used to snapshot */
 | ||||
| +	unsigned long flags;
 | ||||
| +
 | ||||
| +	spin_lock_irqsave(&info->card->card_lock, flags);
 | ||||
| +	cnow = info->icount;
 | ||||
| +	spin_unlock_irqrestore(&info->card->card_lock, flags);
 | ||||
| +
 | ||||
| +	sic->cts = cnow.cts;
 | ||||
| +	sic->dsr = cnow.dsr;
 | ||||
| +	sic->rng = cnow.rng;
 | ||||
| +	sic->dcd = cnow.dcd;
 | ||||
| +	sic->rx = cnow.rx;
 | ||||
| +	sic->tx = cnow.tx;
 | ||||
| +	sic->frame = cnow.frame;
 | ||||
| +	sic->overrun = cnow.overrun;
 | ||||
| +	sic->parity = cnow.parity;
 | ||||
| +	sic->brk = cnow.brk;
 | ||||
| +	sic->buf_overrun = cnow.buf_overrun;
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* | ||||
|   * This routine allows the tty driver to be notified when | ||||
|   * device's termios settings have changed.  Note that a | ||||
| @@ -4084,6 +4086,7 @@ static const struct tty_operations cy_ops = {
 | ||||
|  	.wait_until_sent = cy_wait_until_sent, | ||||
|  	.tiocmget = cy_tiocmget, | ||||
|  	.tiocmset = cy_tiocmset, | ||||
| +	.get_icount = cy_get_icount,
 | ||||
|  	.proc_fops = &cyclades_proc_fops, | ||||
|  }; | ||||
|   | ||||
| diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
 | ||||
| index d4b71e8..438272c 100644
 | ||||
| --- a/drivers/char/ip2/ip2main.c
 | ||||
| +++ b/drivers/char/ip2/ip2main.c
 | ||||
| @@ -183,6 +183,8 @@ static void ip2_hangup(PTTY);
 | ||||
|  static int  ip2_tiocmget(struct tty_struct *tty, struct file *file); | ||||
|  static int  ip2_tiocmset(struct tty_struct *tty, struct file *file, | ||||
|  			 unsigned int set, unsigned int clear); | ||||
| +static int ip2_get_icount(struct tty_struct *tty,
 | ||||
| +		struct serial_icounter_struct *icount);
 | ||||
|   | ||||
|  static void set_irq(int, int); | ||||
|  static void ip2_interrupt_bh(struct work_struct *work); | ||||
| @@ -454,6 +456,7 @@ static const struct tty_operations ip2_ops = {
 | ||||
|  	.hangup          = ip2_hangup, | ||||
|  	.tiocmget	 = ip2_tiocmget, | ||||
|  	.tiocmset	 = ip2_tiocmset, | ||||
| +	.get_icount	 = ip2_get_icount,
 | ||||
|  	.proc_fops	 = &ip2_proc_fops, | ||||
|  }; | ||||
|   | ||||
| @@ -2128,7 +2131,6 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
 | ||||
|  	i2ChanStrPtr pCh = DevTable[tty->index]; | ||||
|  	i2eBordStrPtr pB; | ||||
|  	struct async_icount cprev, cnow;	/* kernel counter temps */ | ||||
| -	struct serial_icounter_struct __user *p_cuser;
 | ||||
|  	int rc = 0; | ||||
|  	unsigned long flags; | ||||
|  	void __user *argp = (void __user *)arg; | ||||
| @@ -2297,34 +2299,6 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
 | ||||
|  		break; | ||||
|   | ||||
|  	/* | ||||
| -	 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| -	 * Return: write counters to the user passed counter struct
 | ||||
| -	 * NB: both 1->0 and 0->1 transitions are counted except for RI where
 | ||||
| -	 * only 0->1 is counted. The controller is quite capable of counting
 | ||||
| -	 * both, but this done to preserve compatibility with the standard
 | ||||
| -	 * serial driver.
 | ||||
| -	 */
 | ||||
| -	case TIOCGICOUNT:
 | ||||
| -		ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
 | ||||
| -
 | ||||
| -		write_lock_irqsave(&pB->read_fifo_spinlock, flags);
 | ||||
| -		cnow = pCh->icount;
 | ||||
| -		write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
 | ||||
| -		p_cuser = argp;
 | ||||
| -		rc = put_user(cnow.cts, &p_cuser->cts);
 | ||||
| -		rc = put_user(cnow.dsr, &p_cuser->dsr);
 | ||||
| -		rc = put_user(cnow.rng, &p_cuser->rng);
 | ||||
| -		rc = put_user(cnow.dcd, &p_cuser->dcd);
 | ||||
| -		rc = put_user(cnow.rx, &p_cuser->rx);
 | ||||
| -		rc = put_user(cnow.tx, &p_cuser->tx);
 | ||||
| -		rc = put_user(cnow.frame, &p_cuser->frame);
 | ||||
| -		rc = put_user(cnow.overrun, &p_cuser->overrun);
 | ||||
| -		rc = put_user(cnow.parity, &p_cuser->parity);
 | ||||
| -		rc = put_user(cnow.brk, &p_cuser->brk);
 | ||||
| -		rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
 | ||||
| -		break;
 | ||||
| -
 | ||||
| -	/*
 | ||||
|  	 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they | ||||
|  	 * will be passed to the line discipline for it to handle. | ||||
|  	 */ | ||||
| @@ -2348,6 +2322,46 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
 | ||||
|  	return rc; | ||||
|  } | ||||
|   | ||||
| +static int ip2_get_icount(struct tty_struct *tty,
 | ||||
| +		struct serial_icounter_struct *icount)
 | ||||
| +{
 | ||||
| +	i2ChanStrPtr pCh = DevTable[tty->index];
 | ||||
| +	i2eBordStrPtr pB;
 | ||||
| +	struct async_icount cnow;	/* kernel counter temp */
 | ||||
| +	unsigned long flags;
 | ||||
| +
 | ||||
| +	if ( pCh == NULL )
 | ||||
| +		return -ENODEV;
 | ||||
| +
 | ||||
| +	pB = pCh->pMyBord;
 | ||||
| +
 | ||||
| +	/*
 | ||||
| +	 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| +	 * Return: write counters to the user passed counter struct
 | ||||
| +	 * NB: both 1->0 and 0->1 transitions are counted except for RI where
 | ||||
| +	 * only 0->1 is counted. The controller is quite capable of counting
 | ||||
| +	 * both, but this done to preserve compatibility with the standard
 | ||||
| +	 * serial driver.
 | ||||
| +	 */
 | ||||
| +
 | ||||
| +	write_lock_irqsave(&pB->read_fifo_spinlock, flags);
 | ||||
| +	cnow = pCh->icount;
 | ||||
| +	write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
 | ||||
| +
 | ||||
| +	icount->cts = cnow.cts;
 | ||||
| +	icount->dsr = cnow.dsr;
 | ||||
| +	icount->rng = cnow.rng;
 | ||||
| +	icount->dcd = cnow.dcd;
 | ||||
| +	icount->rx = cnow.rx;
 | ||||
| +	icount->tx = cnow.tx;
 | ||||
| +	icount->frame = cnow.frame;
 | ||||
| +	icount->overrun = cnow.overrun;
 | ||||
| +	icount->parity = cnow.parity;
 | ||||
| +	icount->brk = cnow.brk;
 | ||||
| +	icount->buf_overrun = cnow.buf_overrun;
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  /******************************************************************************/ | ||||
|  /* Function:   GetSerialInfo()                                                */ | ||||
|  /* Parameters: Pointer to channel structure                                   */ | ||||
| diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
 | ||||
| index 3fc89da..b3704ae7 100644
 | ||||
| --- a/drivers/char/mxser.c
 | ||||
| +++ b/drivers/char/mxser.c
 | ||||
| @@ -1700,7 +1700,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  		return 0; | ||||
|  	} | ||||
|   | ||||
| -	if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
 | ||||
| +	if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT &&
 | ||||
|  			test_bit(TTY_IO_ERROR, &tty->flags)) | ||||
|  		return -EIO; | ||||
|   | ||||
| @@ -1730,32 +1730,6 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|   | ||||
|  		return wait_event_interruptible(info->port.delta_msr_wait, | ||||
|  				mxser_cflags_changed(info, arg, &cnow)); | ||||
| -	/*
 | ||||
| -	 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| -	 * Return: write counters to the user passed counter struct
 | ||||
| -	 * NB: both 1->0 and 0->1 transitions are counted except for
 | ||||
| -	 *     RI where only 0->1 is counted.
 | ||||
| -	 */
 | ||||
| -	case TIOCGICOUNT: {
 | ||||
| -		struct serial_icounter_struct icnt = { 0 };
 | ||||
| -		spin_lock_irqsave(&info->slock, flags);
 | ||||
| -		cnow = info->icount;
 | ||||
| -		spin_unlock_irqrestore(&info->slock, flags);
 | ||||
| -
 | ||||
| -		icnt.frame = cnow.frame;
 | ||||
| -		icnt.brk = cnow.brk;
 | ||||
| -		icnt.overrun = cnow.overrun;
 | ||||
| -		icnt.buf_overrun = cnow.buf_overrun;
 | ||||
| -		icnt.parity = cnow.parity;
 | ||||
| -		icnt.rx = cnow.rx;
 | ||||
| -		icnt.tx = cnow.tx;
 | ||||
| -		icnt.cts = cnow.cts;
 | ||||
| -		icnt.dsr = cnow.dsr;
 | ||||
| -		icnt.rng = cnow.rng;
 | ||||
| -		icnt.dcd = cnow.dcd;
 | ||||
| -
 | ||||
| -		return copy_to_user(argp, &icnt, sizeof(icnt)) ? -EFAULT : 0;
 | ||||
| -	}
 | ||||
|  	case MOXA_HighSpeedOn: | ||||
|  		return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); | ||||
|  	case MOXA_SDS_RSTICOUNTER: | ||||
| @@ -1828,6 +1802,39 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
| +	/*
 | ||||
| +	 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| +	 * Return: write counters to the user passed counter struct
 | ||||
| +	 * NB: both 1->0 and 0->1 transitions are counted except for
 | ||||
| +	 *     RI where only 0->1 is counted.
 | ||||
| +	 */
 | ||||
| +
 | ||||
| +static int mxser_get_icount(struct tty_struct *tty,
 | ||||
| +		struct serial_icounter_struct *icount)
 | ||||
| +
 | ||||
| +{
 | ||||
| +	struct mxser_port *info = tty->driver_data;
 | ||||
| +	struct async_icount cnow;
 | ||||
| +	unsigned long flags;
 | ||||
| +
 | ||||
| +	spin_lock_irqsave(&info->slock, flags);
 | ||||
| +	cnow = info->icount;
 | ||||
| +	spin_unlock_irqrestore(&info->slock, flags);
 | ||||
| +
 | ||||
| +	icount->frame = cnow.frame;
 | ||||
| +	icount->brk = cnow.brk;
 | ||||
| +	icount->overrun = cnow.overrun;
 | ||||
| +	icount->buf_overrun = cnow.buf_overrun;
 | ||||
| +	icount->parity = cnow.parity;
 | ||||
| +	icount->rx = cnow.rx;
 | ||||
| +	icount->tx = cnow.tx;
 | ||||
| +	icount->cts = cnow.cts;
 | ||||
| +	icount->dsr = cnow.dsr;
 | ||||
| +	icount->rng = cnow.rng;
 | ||||
| +	icount->dcd = cnow.dcd;
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static void mxser_stoprx(struct tty_struct *tty) | ||||
|  { | ||||
|  	struct mxser_port *info = tty->driver_data; | ||||
| @@ -2326,6 +2333,7 @@ static const struct tty_operations mxser_ops = {
 | ||||
|  	.wait_until_sent = mxser_wait_until_sent, | ||||
|  	.tiocmget = mxser_tiocmget, | ||||
|  	.tiocmset = mxser_tiocmset, | ||||
| +	.get_icount = mxser_get_icount,
 | ||||
|  }; | ||||
|   | ||||
|  struct tty_port_operations mxser_port_ops = { | ||||
| diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
 | ||||
| index 817169c..dd3f9b1 100644
 | ||||
| --- a/drivers/char/nozomi.c
 | ||||
| +++ b/drivers/char/nozomi.c
 | ||||
| @@ -1804,24 +1804,24 @@ static int ntty_cflags_changed(struct port *port, unsigned long flags,
 | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| -static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp)
 | ||||
| +static int ntty_tiocgicount(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *icount)
 | ||||
|  { | ||||
| +	struct port *port = tty->driver_data;
 | ||||
|  	const struct async_icount cnow = port->tty_icount; | ||||
| -	struct serial_icounter_struct icount;
 | ||||
| -
 | ||||
| -	icount.cts = cnow.cts;
 | ||||
| -	icount.dsr = cnow.dsr;
 | ||||
| -	icount.rng = cnow.rng;
 | ||||
| -	icount.dcd = cnow.dcd;
 | ||||
| -	icount.rx = cnow.rx;
 | ||||
| -	icount.tx = cnow.tx;
 | ||||
| -	icount.frame = cnow.frame;
 | ||||
| -	icount.overrun = cnow.overrun;
 | ||||
| -	icount.parity = cnow.parity;
 | ||||
| -	icount.brk = cnow.brk;
 | ||||
| -	icount.buf_overrun = cnow.buf_overrun;
 | ||||
| -
 | ||||
| -	return copy_to_user(argp, &icount, sizeof(icount)) ? -EFAULT : 0;
 | ||||
| +
 | ||||
| +	icount->cts = cnow.cts;
 | ||||
| +	icount->dsr = cnow.dsr;
 | ||||
| +	icount->rng = cnow.rng;
 | ||||
| +	icount->dcd = cnow.dcd;
 | ||||
| +	icount->rx = cnow.rx;
 | ||||
| +	icount->tx = cnow.tx;
 | ||||
| +	icount->frame = cnow.frame;
 | ||||
| +	icount->overrun = cnow.overrun;
 | ||||
| +	icount->parity = cnow.parity;
 | ||||
| +	icount->brk = cnow.brk;
 | ||||
| +	icount->buf_overrun = cnow.buf_overrun;
 | ||||
| +	return 0;
 | ||||
|  } | ||||
|   | ||||
|  static int ntty_ioctl(struct tty_struct *tty, struct file *file, | ||||
| @@ -1840,9 +1840,7 @@ static int ntty_ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  		rval = wait_event_interruptible(port->tty_wait, | ||||
|  				ntty_cflags_changed(port, arg, &cprev)); | ||||
|  		break; | ||||
| -	} case TIOCGICOUNT:
 | ||||
| -		rval = ntty_ioctl_tiocgicount(port, argp);
 | ||||
| -		break;
 | ||||
| +	}
 | ||||
|  	default: | ||||
|  		DBG1("ERR: 0x%08X, %d", cmd, cmd); | ||||
|  		break; | ||||
| @@ -1922,6 +1920,7 @@ static const struct tty_operations tty_ops = {
 | ||||
|  	.chars_in_buffer = ntty_chars_in_buffer, | ||||
|  	.tiocmget = ntty_tiocmget, | ||||
|  	.tiocmset = ntty_tiocmset, | ||||
| +	.get_icount = ntty_tiocgicount,
 | ||||
|  	.install = ntty_install, | ||||
|  	.cleanup = ntty_cleanup, | ||||
|  }; | ||||
| diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
 | ||||
| index 45f9fad..7404809 100644
 | ||||
| --- a/drivers/char/pcmcia/synclink_cs.c
 | ||||
| +++ b/drivers/char/pcmcia/synclink_cs.c
 | ||||
| @@ -2215,6 +2215,32 @@ static int mgslpc_break(struct tty_struct *tty, int break_state)
 | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
| +static int mgslpc_get_icount(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *icount)
 | ||||
| +{
 | ||||
| +	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
 | ||||
| +	struct mgsl_icount cnow;	/* kernel counter temps */
 | ||||
| +	unsigned long flags;
 | ||||
| +
 | ||||
| +	spin_lock_irqsave(&info->lock,flags);
 | ||||
| +	cnow = info->icount;
 | ||||
| +	spin_unlock_irqrestore(&info->lock,flags);
 | ||||
| +
 | ||||
| +	icount->cts = cnow.cts;
 | ||||
| +	icount->dsr = cnow.dsr;
 | ||||
| +	icount->rng = cnow.rng;
 | ||||
| +	icount->dcd = cnow.dcd;
 | ||||
| +	icount->rx = cnow.rx;
 | ||||
| +	icount->tx = cnow.tx;
 | ||||
| +	icount->frame = cnow.frame;
 | ||||
| +	icount->overrun = cnow.overrun;
 | ||||
| +	icount->parity = cnow.parity;
 | ||||
| +	icount->brk = cnow.brk;
 | ||||
| +	icount->buf_overrun = cnow.buf_overrun;
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* Service an IOCTL request | ||||
|   * | ||||
|   * Arguments: | ||||
| @@ -2230,11 +2256,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|  			unsigned int cmd, unsigned long arg) | ||||
|  { | ||||
|  	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; | ||||
| -	int error;
 | ||||
| -	struct mgsl_icount cnow;	/* kernel counter temps */
 | ||||
| -	struct serial_icounter_struct __user *p_cuser;	/* user space */
 | ||||
|  	void __user *argp = (void __user *)arg; | ||||
| -	unsigned long flags;
 | ||||
|   | ||||
|  	if (debug_level >= DEBUG_LEVEL_INFO) | ||||
|  		printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__, | ||||
| @@ -2244,7 +2266,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|  		return -ENODEV; | ||||
|   | ||||
|  	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||||
| -	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 | ||||
| +	    (cmd != TIOCMIWAIT)) {
 | ||||
|  		if (tty->flags & (1 << TTY_IO_ERROR)) | ||||
|  		    return -EIO; | ||||
|  	} | ||||
| @@ -2274,34 +2296,6 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|  		return wait_events(info, argp); | ||||
|  	case TIOCMIWAIT: | ||||
|  		return modem_input_wait(info,(int)arg); | ||||
| -	case TIOCGICOUNT:
 | ||||
| -		spin_lock_irqsave(&info->lock,flags);
 | ||||
| -		cnow = info->icount;
 | ||||
| -		spin_unlock_irqrestore(&info->lock,flags);
 | ||||
| -		p_cuser = argp;
 | ||||
| -		PUT_USER(error,cnow.cts, &p_cuser->cts);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.dsr, &p_cuser->dsr);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.rng, &p_cuser->rng);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.dcd, &p_cuser->dcd);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.rx, &p_cuser->rx);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.tx, &p_cuser->tx);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.frame, &p_cuser->frame);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.overrun, &p_cuser->overrun);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.parity, &p_cuser->parity);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.brk, &p_cuser->brk);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
 | ||||
| -		if (error) return error;
 | ||||
| -		return 0;
 | ||||
|  	default: | ||||
|  		return -ENOIOCTLCMD; | ||||
|  	} | ||||
| diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
 | ||||
| index a2a5800..3a6824f 100644
 | ||||
| --- a/drivers/char/synclink.c
 | ||||
| +++ b/drivers/char/synclink.c
 | ||||
| @@ -2925,6 +2925,38 @@ static int mgsl_break(struct tty_struct *tty, int break_state)
 | ||||
|  	 | ||||
|  }	/* end of mgsl_break() */ | ||||
|   | ||||
| +/*
 | ||||
| + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| + * Return: write counters to the user passed counter struct
 | ||||
| + * NB: both 1->0 and 0->1 transitions are counted except for
 | ||||
| + *     RI where only 0->1 is counted.
 | ||||
| + */
 | ||||
| +static int msgl_get_icount(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *icount)
 | ||||
| +
 | ||||
| +{
 | ||||
| +	struct mgsl_struct * info = tty->driver_data;
 | ||||
| +	struct mgsl_icount cnow;	/* kernel counter temps */
 | ||||
| +	unsigned long flags;
 | ||||
| +
 | ||||
| +	spin_lock_irqsave(&info->irq_spinlock,flags);
 | ||||
| +	cnow = info->icount;
 | ||||
| +	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 | ||||
| +
 | ||||
| +	icount->cts = cnow.cts;
 | ||||
| +	icount->dsr = cnow.dsr;
 | ||||
| +	icount->rng = cnow.rng;
 | ||||
| +	icount->dcd = cnow.dcd;
 | ||||
| +	icount->rx = cnow.rx;
 | ||||
| +	icount->tx = cnow.tx;
 | ||||
| +	icount->frame = cnow.frame;
 | ||||
| +	icount->overrun = cnow.overrun;
 | ||||
| +	icount->parity = cnow.parity;
 | ||||
| +	icount->brk = cnow.brk;
 | ||||
| +	icount->buf_overrun = cnow.buf_overrun;
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* mgsl_ioctl()	Service an IOCTL request | ||||
|   * 	 | ||||
|   * Arguments: | ||||
| @@ -2949,7 +2981,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|  		return -ENODEV; | ||||
|   | ||||
|  	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||||
| -	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 | ||||
| +	    (cmd != TIOCMIWAIT)) {
 | ||||
|  		if (tty->flags & (1 << TTY_IO_ERROR)) | ||||
|  		    return -EIO; | ||||
|  	} | ||||
| @@ -2959,11 +2991,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|   | ||||
|  static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) | ||||
|  { | ||||
| -	int error;
 | ||||
| -	struct mgsl_icount cnow;	/* kernel counter temps */
 | ||||
|  	void __user *argp = (void __user *)arg; | ||||
| -	struct serial_icounter_struct __user *p_cuser;	/* user space */
 | ||||
| -	unsigned long flags;
 | ||||
|  	 | ||||
|  	switch (cmd) { | ||||
|  		case MGSL_IOCGPARAMS: | ||||
| @@ -2992,40 +3020,6 @@ static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigne
 | ||||
|  		case TIOCMIWAIT: | ||||
|  			return modem_input_wait(info,(int)arg); | ||||
|   | ||||
| -		/* 
 | ||||
| -		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| -		 * Return: write counters to the user passed counter struct
 | ||||
| -		 * NB: both 1->0 and 0->1 transitions are counted except for
 | ||||
| -		 *     RI where only 0->1 is counted.
 | ||||
| -		 */
 | ||||
| -		case TIOCGICOUNT:
 | ||||
| -			spin_lock_irqsave(&info->irq_spinlock,flags);
 | ||||
| -			cnow = info->icount;
 | ||||
| -			spin_unlock_irqrestore(&info->irq_spinlock,flags);
 | ||||
| -			p_cuser = argp;
 | ||||
| -			PUT_USER(error,cnow.cts, &p_cuser->cts);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.dsr, &p_cuser->dsr);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.rng, &p_cuser->rng);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.dcd, &p_cuser->dcd);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.rx, &p_cuser->rx);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.tx, &p_cuser->tx);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.frame, &p_cuser->frame);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.overrun, &p_cuser->overrun);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.parity, &p_cuser->parity);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.brk, &p_cuser->brk);
 | ||||
| -			if (error) return error;
 | ||||
| -			PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
 | ||||
| -			if (error) return error;
 | ||||
| -			return 0;
 | ||||
|  		default: | ||||
|  			return -ENOIOCTLCMD; | ||||
|  	} | ||||
| @@ -4328,6 +4322,7 @@ static const struct tty_operations mgsl_ops = {
 | ||||
|  	.hangup = mgsl_hangup, | ||||
|  	.tiocmget = tiocmget, | ||||
|  	.tiocmset = tiocmset, | ||||
| +	.get_icount = msgl_get_icount,
 | ||||
|  	.proc_fops = &mgsl_proc_fops, | ||||
|  }; | ||||
|   | ||||
| diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
 | ||||
| index e63b830..1746d91 100644
 | ||||
| --- a/drivers/char/synclink_gt.c
 | ||||
| +++ b/drivers/char/synclink_gt.c
 | ||||
| @@ -1032,9 +1032,6 @@ static int ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  		 unsigned int cmd, unsigned long arg) | ||||
|  { | ||||
|  	struct slgt_info *info = tty->driver_data; | ||||
| -	struct mgsl_icount cnow;	/* kernel counter temps */
 | ||||
| -	struct serial_icounter_struct __user *p_cuser;	/* user space */
 | ||||
| -	unsigned long flags;
 | ||||
|  	void __user *argp = (void __user *)arg; | ||||
|  	int ret; | ||||
|   | ||||
| @@ -1043,7 +1040,7 @@ static int ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  	DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); | ||||
|   | ||||
|  	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||||
| -	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 | ||||
| +	    (cmd != TIOCMIWAIT)) {
 | ||||
|  		if (tty->flags & (1 << TTY_IO_ERROR)) | ||||
|  		    return -EIO; | ||||
|  	} | ||||
| @@ -1053,24 +1050,6 @@ static int ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  		return wait_mgsl_event(info, argp); | ||||
|  	case TIOCMIWAIT: | ||||
|  		return modem_input_wait(info,(int)arg); | ||||
| -	case TIOCGICOUNT:
 | ||||
| -		spin_lock_irqsave(&info->lock,flags);
 | ||||
| -		cnow = info->icount;
 | ||||
| -		spin_unlock_irqrestore(&info->lock,flags);
 | ||||
| -		p_cuser = argp;
 | ||||
| -		if (put_user(cnow.cts, &p_cuser->cts) ||
 | ||||
| -		    put_user(cnow.dsr, &p_cuser->dsr) ||
 | ||||
| -		    put_user(cnow.rng, &p_cuser->rng) ||
 | ||||
| -		    put_user(cnow.dcd, &p_cuser->dcd) ||
 | ||||
| -		    put_user(cnow.rx, &p_cuser->rx) ||
 | ||||
| -		    put_user(cnow.tx, &p_cuser->tx) ||
 | ||||
| -		    put_user(cnow.frame, &p_cuser->frame) ||
 | ||||
| -		    put_user(cnow.overrun, &p_cuser->overrun) ||
 | ||||
| -		    put_user(cnow.parity, &p_cuser->parity) ||
 | ||||
| -		    put_user(cnow.brk, &p_cuser->brk) ||
 | ||||
| -		    put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
 | ||||
| -			return -EFAULT;
 | ||||
| -		return 0;
 | ||||
|  	case MGSL_IOCSGPIO: | ||||
|  		return set_gpio(info, argp); | ||||
|  	case MGSL_IOCGGPIO: | ||||
| @@ -1117,6 +1096,33 @@ static int ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  	return ret; | ||||
|  } | ||||
|   | ||||
| +static int get_icount(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *icount)
 | ||||
| +
 | ||||
| +{
 | ||||
| +	struct slgt_info *info = tty->driver_data;
 | ||||
| +	struct mgsl_icount cnow;	/* kernel counter temps */
 | ||||
| +	unsigned long flags;
 | ||||
| +
 | ||||
| +	spin_lock_irqsave(&info->lock,flags);
 | ||||
| +	cnow = info->icount;
 | ||||
| +	spin_unlock_irqrestore(&info->lock,flags);
 | ||||
| +
 | ||||
| +	icount->cts = cnow.cts;
 | ||||
| +	icount->dsr = cnow.dsr;
 | ||||
| +	icount->rng = cnow.rng;
 | ||||
| +	icount->dcd = cnow.dcd;
 | ||||
| +	icount->rx = cnow.rx;
 | ||||
| +	icount->tx = cnow.tx;
 | ||||
| +	icount->frame = cnow.frame;
 | ||||
| +	icount->overrun = cnow.overrun;
 | ||||
| +	icount->parity = cnow.parity;
 | ||||
| +	icount->brk = cnow.brk;
 | ||||
| +	icount->buf_overrun = cnow.buf_overrun;
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* | ||||
|   * support for 32 bit ioctl calls on 64 bit systems | ||||
|   */ | ||||
| @@ -1206,10 +1212,6 @@ static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  	case MGSL_IOCSGPIO: | ||||
|  	case MGSL_IOCGGPIO: | ||||
|  	case MGSL_IOCWAITGPIO: | ||||
| -	case TIOCGICOUNT:
 | ||||
| -		rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg)));
 | ||||
| -		break;
 | ||||
| -
 | ||||
|  	case MGSL_IOCSTXIDLE: | ||||
|  	case MGSL_IOCTXENABLE: | ||||
|  	case MGSL_IOCRXENABLE: | ||||
| @@ -3642,6 +3644,7 @@ static const struct tty_operations ops = {
 | ||||
|  	.hangup = hangup, | ||||
|  	.tiocmget = tiocmget, | ||||
|  	.tiocmset = tiocmset, | ||||
| +	.get_icount = get_icount,
 | ||||
|  	.proc_fops = &synclink_gt_proc_fops, | ||||
|  }; | ||||
|   | ||||
| diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
 | ||||
| index e56caf7..2f9eb4b 100644
 | ||||
| --- a/drivers/char/synclinkmp.c
 | ||||
| +++ b/drivers/char/synclinkmp.c
 | ||||
| @@ -1258,10 +1258,6 @@ static int ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  		 unsigned int cmd, unsigned long arg) | ||||
|  { | ||||
|  	SLMP_INFO *info = tty->driver_data; | ||||
| -	int error;
 | ||||
| -	struct mgsl_icount cnow;	/* kernel counter temps */
 | ||||
| -	struct serial_icounter_struct __user *p_cuser;	/* user space */
 | ||||
| -	unsigned long flags;
 | ||||
|  	void __user *argp = (void __user *)arg; | ||||
|   | ||||
|  	if (debug_level >= DEBUG_LEVEL_INFO) | ||||
| @@ -1272,7 +1268,7 @@ static int ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  		return -ENODEV; | ||||
|   | ||||
|  	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||||
| -	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 | ||||
| +	    (cmd != TIOCMIWAIT)) {
 | ||||
|  		if (tty->flags & (1 << TTY_IO_ERROR)) | ||||
|  		    return -EIO; | ||||
|  	} | ||||
| @@ -1310,40 +1306,38 @@ static int ioctl(struct tty_struct *tty, struct file *file,
 | ||||
|  		 * NB: both 1->0 and 0->1 transitions are counted except for | ||||
|  		 *     RI where only 0->1 is counted. | ||||
|  		 */ | ||||
| -	case TIOCGICOUNT:
 | ||||
| -		spin_lock_irqsave(&info->lock,flags);
 | ||||
| -		cnow = info->icount;
 | ||||
| -		spin_unlock_irqrestore(&info->lock,flags);
 | ||||
| -		p_cuser = argp;
 | ||||
| -		PUT_USER(error,cnow.cts, &p_cuser->cts);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.dsr, &p_cuser->dsr);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.rng, &p_cuser->rng);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.dcd, &p_cuser->dcd);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.rx, &p_cuser->rx);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.tx, &p_cuser->tx);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.frame, &p_cuser->frame);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.overrun, &p_cuser->overrun);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.parity, &p_cuser->parity);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.brk, &p_cuser->brk);
 | ||||
| -		if (error) return error;
 | ||||
| -		PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
 | ||||
| -		if (error) return error;
 | ||||
| -		return 0;
 | ||||
|  	default: | ||||
|  		return -ENOIOCTLCMD; | ||||
|  	} | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
| +static int get_icount(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *icount)
 | ||||
| +{
 | ||||
| +	SLMP_INFO *info = tty->driver_data;
 | ||||
| +	struct mgsl_icount cnow;	/* kernel counter temps */
 | ||||
| +	unsigned long flags;
 | ||||
| +
 | ||||
| +	spin_lock_irqsave(&info->lock,flags);
 | ||||
| +	cnow = info->icount;
 | ||||
| +	spin_unlock_irqrestore(&info->lock,flags);
 | ||||
| +
 | ||||
| +	icount->cts = cnow.cts;
 | ||||
| +	icount->dsr = cnow.dsr;
 | ||||
| +	icount->rng = cnow.rng;
 | ||||
| +	icount->dcd = cnow.dcd;
 | ||||
| +	icount->rx = cnow.rx;
 | ||||
| +	icount->tx = cnow.tx;
 | ||||
| +	icount->frame = cnow.frame;
 | ||||
| +	icount->overrun = cnow.overrun;
 | ||||
| +	icount->parity = cnow.parity;
 | ||||
| +	icount->brk = cnow.brk;
 | ||||
| +	icount->buf_overrun = cnow.buf_overrun;
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* | ||||
|   * /proc fs routines.... | ||||
|   */ | ||||
| @@ -3909,6 +3903,7 @@ static const struct tty_operations ops = {
 | ||||
|  	.hangup = hangup, | ||||
|  	.tiocmget = tiocmget, | ||||
|  	.tiocmset = tiocmset, | ||||
| +	.get_icount = get_icount,
 | ||||
|  	.proc_fops = &synclinkmp_proc_fops, | ||||
|  }; | ||||
|   | ||||
| diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
 | ||||
| index 0dff3bb..88b1335 100644
 | ||||
| --- a/drivers/serial/68360serial.c
 | ||||
| +++ b/drivers/serial/68360serial.c
 | ||||
| @@ -1381,6 +1381,30 @@ static void send_break(ser_info_t *info, unsigned int duration)
 | ||||
|  } | ||||
|   | ||||
|   | ||||
| +/*
 | ||||
| + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| + * Return: write counters to the user passed counter struct
 | ||||
| + * NB: both 1->0 and 0->1 transitions are counted except for
 | ||||
| + *     RI where only 0->1 is counted.
 | ||||
| + */
 | ||||
| +static int rs_360_get_icount(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *icount)
 | ||||
| +{
 | ||||
| +	ser_info_t *info = (ser_info_t *)tty->driver_data;
 | ||||
| +	struct async_icount cnow;
 | ||||
| +
 | ||||
| +	local_irq_disable();
 | ||||
| +	cnow = info->state->icount;
 | ||||
| +	local_irq_enable();
 | ||||
| +
 | ||||
| +	icount->cts = cnow.cts;
 | ||||
| +	icount->dsr = cnow.dsr;
 | ||||
| +	icount->rng = cnow.rng;
 | ||||
| +	icount->dcd = cnow.dcd;
 | ||||
| +
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static int rs_360_ioctl(struct tty_struct *tty, struct file * file, | ||||
|  		    unsigned int cmd, unsigned long arg) | ||||
|  { | ||||
| @@ -1394,7 +1418,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|  	if (serial_paranoia_check(info, tty->name, "rs_ioctl")) | ||||
|  		return -ENODEV; | ||||
|   | ||||
| -	if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
 | ||||
| +	if (cmd != TIOCMIWAIT) {
 | ||||
|  		if (tty->flags & (1 << TTY_IO_ERROR)) | ||||
|  		    return -EIO; | ||||
|  	} | ||||
| @@ -1477,31 +1501,6 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
 | ||||
|  			return 0; | ||||
|  #endif | ||||
|   | ||||
| -		/* 
 | ||||
| -		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
 | ||||
| -		 * Return: write counters to the user passed counter struct
 | ||||
| -		 * NB: both 1->0 and 0->1 transitions are counted except for
 | ||||
| -		 *     RI where only 0->1 is counted.
 | ||||
| -		 */
 | ||||
| -		case TIOCGICOUNT:
 | ||||
| -			local_irq_disable();
 | ||||
| -			cnow = info->state->icount;
 | ||||
| -			local_irq_enable();
 | ||||
| -			p_cuser = (struct serial_icounter_struct *) arg;
 | ||||
| -/* 			error = put_user(cnow.cts, &p_cuser->cts); */
 | ||||
| -/* 			if (error) return error; */
 | ||||
| -/* 			error = put_user(cnow.dsr, &p_cuser->dsr); */
 | ||||
| -/* 			if (error) return error; */
 | ||||
| -/* 			error = put_user(cnow.rng, &p_cuser->rng); */
 | ||||
| -/* 			if (error) return error; */
 | ||||
| -/* 			error = put_user(cnow.dcd, &p_cuser->dcd); */
 | ||||
| -/* 			if (error) return error; */
 | ||||
| -
 | ||||
| -			put_user(cnow.cts, &p_cuser->cts);
 | ||||
| -			put_user(cnow.dsr, &p_cuser->dsr);
 | ||||
| -			put_user(cnow.rng, &p_cuser->rng);
 | ||||
| -			put_user(cnow.dcd, &p_cuser->dcd);
 | ||||
| -			return 0;
 | ||||
|   | ||||
|  		default: | ||||
|  			return -ENOIOCTLCMD; | ||||
| diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
 | ||||
| index befc3a5..84c2a4d 100644
 | ||||
| --- a/net/bluetooth/rfcomm/tty.c
 | ||||
| +++ b/net/bluetooth/rfcomm/tty.c
 | ||||
| @@ -844,10 +844,6 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned
 | ||||
|  		BT_DBG("TIOCMIWAIT"); | ||||
|  		break; | ||||
|   | ||||
| -	case TIOCGICOUNT:
 | ||||
| -		BT_DBG("TIOCGICOUNT");
 | ||||
| -		break;
 | ||||
| -
 | ||||
|  	case TIOCGSERIAL: | ||||
|  		BT_ERR("TIOCGSERIAL is not supported"); | ||||
|  		return -ENOIOCTLCMD; | ||||
| -- 
 | ||||
| 1.7.3.2 | ||||
| 
 | ||||
							
								
								
									
										218
									
								
								tty-make-tiocgicount-a-handler.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								tty-make-tiocgicount-a-handler.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,218 @@ | ||||
| From e2047e3ffc61042a3228cd4228cd95ab0dad1d72 Mon Sep 17 00:00:00 2001 | ||||
| From: Alan Cox <alan@linux.intel.com> | ||||
| Date: Thu, 16 Sep 2010 18:21:24 +0100 | ||||
| Subject: [PATCH 1/2] tty: Make tiocgicount a handler | ||||
| 
 | ||||
| Dan Rosenberg noted that various drivers return the struct with uncleared | ||||
| fields. Instead of spending forever trying to stomp all the drivers that | ||||
| get it wrong (and every new driver) do the job in one place. | ||||
| 
 | ||||
| This first patch adds the needed operations and hooks them up, including | ||||
| the needed USB midlayer and serial core plumbing. | ||||
| 
 | ||||
| Signed-off-by: Alan Cox <alan@linux.intel.com> | ||||
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | ||||
| ---
 | ||||
|  drivers/char/tty_io.c           |   21 +++++++++++++++++++++ | ||||
|  drivers/serial/serial_core.c    |   37 +++++++++++++++++-------------------- | ||||
|  drivers/usb/serial/usb-serial.c |   13 +++++++++++++ | ||||
|  include/linux/tty_driver.h      |    9 +++++++++ | ||||
|  include/linux/usb/serial.h      |    2 ++ | ||||
|  5 files changed, 62 insertions(+), 20 deletions(-) | ||||
| 
 | ||||
| diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
 | ||||
| index 613c852..68d7713 100644
 | ||||
| --- a/drivers/char/tty_io.c
 | ||||
| +++ b/drivers/char/tty_io.c
 | ||||
| @@ -96,6 +96,7 @@
 | ||||
|  #include <linux/bitops.h> | ||||
|  #include <linux/delay.h> | ||||
|  #include <linux/seq_file.h> | ||||
| +#include <linux/serial.h>
 | ||||
|   | ||||
|  #include <linux/uaccess.h> | ||||
|  #include <asm/system.h> | ||||
| @@ -2502,6 +2503,20 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
 | ||||
|  	return tty->ops->tiocmset(tty, file, set, clear); | ||||
|  } | ||||
|   | ||||
| +static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
 | ||||
| +{
 | ||||
| +	int retval = -EINVAL;
 | ||||
| +	struct serial_icounter_struct icount;
 | ||||
| +	memset(&icount, 0, sizeof(icount));
 | ||||
| +	if (tty->ops->get_icount)
 | ||||
| +		retval = tty->ops->get_icount(tty, &icount);
 | ||||
| +	if (retval != 0)
 | ||||
| +		return retval;
 | ||||
| +	if (copy_to_user(arg, &icount, sizeof(icount)))
 | ||||
| +		return -EFAULT;
 | ||||
| +	return 0;
 | ||||
| +}
 | ||||
| +
 | ||||
|  struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) | ||||
|  { | ||||
|  	if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | ||||
| @@ -2622,6 +2637,12 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 | ||||
|  	case TIOCMBIC: | ||||
|  	case TIOCMBIS: | ||||
|  		return tty_tiocmset(tty, file, cmd, p); | ||||
| +	case TIOCGICOUNT:
 | ||||
| +		retval = tty_tiocgicount(tty, p);
 | ||||
| +		/* For the moment allow fall through to the old method */
 | ||||
| +        	if (retval != -EINVAL)
 | ||||
| +			return retval;
 | ||||
| +		break;
 | ||||
|  	case TCFLSH: | ||||
|  		switch (arg) { | ||||
|  		case TCIFLUSH: | ||||
| diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
 | ||||
| index cd85112..2ee0aec 100644
 | ||||
| --- a/drivers/serial/serial_core.c
 | ||||
| +++ b/drivers/serial/serial_core.c
 | ||||
| @@ -1074,10 +1074,10 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
 | ||||
|   * NB: both 1->0 and 0->1 transitions are counted except for | ||||
|   *     RI where only 0->1 is counted. | ||||
|   */ | ||||
| -static int uart_get_count(struct uart_state *state,
 | ||||
| -			  struct serial_icounter_struct __user *icnt)
 | ||||
| +static int uart_get_icount(struct tty_struct *tty,
 | ||||
| +			  struct serial_icounter_struct *icount)
 | ||||
|  { | ||||
| -	struct serial_icounter_struct icount;
 | ||||
| +	struct uart_state *state = tty->driver_data;
 | ||||
|  	struct uart_icount cnow; | ||||
|  	struct uart_port *uport = state->uart_port; | ||||
|   | ||||
| @@ -1085,19 +1085,19 @@ static int uart_get_count(struct uart_state *state,
 | ||||
|  	memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); | ||||
|  	spin_unlock_irq(&uport->lock); | ||||
|   | ||||
| -	icount.cts         = cnow.cts;
 | ||||
| -	icount.dsr         = cnow.dsr;
 | ||||
| -	icount.rng         = cnow.rng;
 | ||||
| -	icount.dcd         = cnow.dcd;
 | ||||
| -	icount.rx          = cnow.rx;
 | ||||
| -	icount.tx          = cnow.tx;
 | ||||
| -	icount.frame       = cnow.frame;
 | ||||
| -	icount.overrun     = cnow.overrun;
 | ||||
| -	icount.parity      = cnow.parity;
 | ||||
| -	icount.brk         = cnow.brk;
 | ||||
| -	icount.buf_overrun = cnow.buf_overrun;
 | ||||
| +	icount->cts         = cnow.cts;
 | ||||
| +	icount->dsr         = cnow.dsr;
 | ||||
| +	icount->rng         = cnow.rng;
 | ||||
| +	icount->dcd         = cnow.dcd;
 | ||||
| +	icount->rx          = cnow.rx;
 | ||||
| +	icount->tx          = cnow.tx;
 | ||||
| +	icount->frame       = cnow.frame;
 | ||||
| +	icount->overrun     = cnow.overrun;
 | ||||
| +	icount->parity      = cnow.parity;
 | ||||
| +	icount->brk         = cnow.brk;
 | ||||
| +	icount->buf_overrun = cnow.buf_overrun;
 | ||||
|   | ||||
| -	return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
 | ||||
| +	return 0;
 | ||||
|  } | ||||
|   | ||||
|  /* | ||||
| @@ -1150,10 +1150,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
 | ||||
|  	case TIOCMIWAIT: | ||||
|  		ret = uart_wait_modem_status(state, arg); | ||||
|  		break; | ||||
| -
 | ||||
| -	case TIOCGICOUNT:
 | ||||
| -		ret = uart_get_count(state, uarg);
 | ||||
| -		break;
 | ||||
|  	} | ||||
|   | ||||
|  	if (ret != -ENOIOCTLCMD) | ||||
| @@ -2283,6 +2279,7 @@ static const struct tty_operations uart_ops = {
 | ||||
|  #endif | ||||
|  	.tiocmget	= uart_tiocmget, | ||||
|  	.tiocmset	= uart_tiocmset, | ||||
| +	.get_icount	= uart_get_icount,
 | ||||
|  #ifdef CONFIG_CONSOLE_POLL | ||||
|  	.poll_init	= uart_poll_init, | ||||
|  	.poll_get_char	= uart_poll_get_char, | ||||
| diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
 | ||||
| index 7a2177c..e64da74 100644
 | ||||
| --- a/drivers/usb/serial/usb-serial.c
 | ||||
| +++ b/drivers/usb/serial/usb-serial.c
 | ||||
| @@ -519,6 +519,18 @@ static int serial_tiocmset(struct tty_struct *tty, struct file *file,
 | ||||
|  	return -EINVAL; | ||||
|  } | ||||
|   | ||||
| +static int serial_get_icount(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *icount)
 | ||||
| +{
 | ||||
| +	struct usb_serial_port *port = tty->driver_data;
 | ||||
| +
 | ||||
| +	dbg("%s - port %d", __func__, port->number);
 | ||||
| +
 | ||||
| +	if (port->serial->type->get_icount)
 | ||||
| +		return port->serial->type->get_icount(tty, icount);
 | ||||
| +	return -EINVAL;
 | ||||
| +}
 | ||||
| +
 | ||||
|  /* | ||||
|   * We would be calling tty_wakeup here, but unfortunately some line | ||||
|   * disciplines have an annoying habit of calling tty->write from | ||||
| @@ -1195,6 +1207,7 @@ static const struct tty_operations serial_ops = {
 | ||||
|  	.chars_in_buffer =	serial_chars_in_buffer, | ||||
|  	.tiocmget =		serial_tiocmget, | ||||
|  	.tiocmset =		serial_tiocmset, | ||||
| +	.get_icount = 		serial_get_icount,
 | ||||
|  	.cleanup = 		serial_cleanup, | ||||
|  	.install = 		serial_install, | ||||
|  	.proc_fops =		&serial_proc_fops, | ||||
| diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
 | ||||
| index b086779..db2d227 100644
 | ||||
| --- a/include/linux/tty_driver.h
 | ||||
| +++ b/include/linux/tty_driver.h
 | ||||
| @@ -224,6 +224,12 @@
 | ||||
|   *	unless the tty also has a valid tty->termiox pointer. | ||||
|   * | ||||
|   *	Optional: Called under the termios lock | ||||
| + *
 | ||||
| + * int (*get_icount)(struct tty_struct *tty, struct serial_icounter *icount);
 | ||||
| + *
 | ||||
| + *	Called when the device receives a TIOCGICOUNT ioctl. Passed a kernel
 | ||||
| + *	structure to complete. This method is optional and will only be called
 | ||||
| + *	if provided (otherwise EINVAL will be returned).
 | ||||
|   */ | ||||
|   | ||||
|  #include <linux/fs.h> | ||||
| @@ -232,6 +238,7 @@
 | ||||
|   | ||||
|  struct tty_struct; | ||||
|  struct tty_driver; | ||||
| +struct serial_icounter_struct;
 | ||||
|   | ||||
|  struct tty_operations { | ||||
|  	struct tty_struct * (*lookup)(struct tty_driver *driver, | ||||
| @@ -268,6 +275,8 @@ struct tty_operations {
 | ||||
|  			unsigned int set, unsigned int clear); | ||||
|  	int (*resize)(struct tty_struct *tty, struct winsize *ws); | ||||
|  	int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); | ||||
| +	int (*get_icount)(struct tty_struct *tty,
 | ||||
| +				struct serial_icounter_struct *icount);
 | ||||
|  #ifdef CONFIG_CONSOLE_POLL | ||||
|  	int (*poll_init)(struct tty_driver *driver, int line, char *options); | ||||
|  	int (*poll_get_char)(struct tty_driver *driver, int line); | ||||
| diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
 | ||||
| index 55675b1..16d682f 100644
 | ||||
| --- a/include/linux/usb/serial.h
 | ||||
| +++ b/include/linux/usb/serial.h
 | ||||
| @@ -271,6 +271,8 @@ struct usb_serial_driver {
 | ||||
|  	int  (*tiocmget)(struct tty_struct *tty, struct file *file); | ||||
|  	int  (*tiocmset)(struct tty_struct *tty, struct file *file, | ||||
|  			 unsigned int set, unsigned int clear); | ||||
| +	int  (*get_icount)(struct tty_struct *tty,
 | ||||
| +			struct serial_icounter_struct *icount);
 | ||||
|  	/* Called by the tty layer for port level work. There may or may not | ||||
|  	   be an attached tty at this point */ | ||||
|  	void (*dtr_rts)(struct usb_serial_port *port, int on); | ||||
| -- 
 | ||||
| 1.7.3.2 | ||||
| 
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user