diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 22:59:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 22:59:04 -0400 |
commit | 73ecf3a6e3f0206bf56a0fefe3b3eda042fb7034 (patch) | |
tree | 866f0ebb2b148479e93b5ac955097b1cc94ceb4e /drivers/char | |
parent | b9da0571050c09863e59f94d0b8594a290d61b88 (diff) | |
parent | cd3ecad19aea8debae9a48b53de2ec7a571f24e9 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: (49 commits)
serial8250: ratelimit "too much work" error
serial: bfin_sport_uart: speed up sport RX sample rate to be 3% faster
serial: abstraction for 8250 legacy ports
serial/imx: check that the buffer is non-empty before sending it out
serial: mfd: add more baud rates support
jsm: Remove the uart port on errors
Alchemy: Add UART PM methods.
8250: allow platforms to override PM hook.
altera_uart: Don't use plain integer as NULL pointer
altera_uart: Fix missing prototype for registering an early console
altera_uart: Fixup type usage of port flags
altera_uart: Make it possible to use Altera UART and 8250 ports together
altera_uart: Add support for different address strides
altera_uart: Add support for getting mapbase and IRQ from resources
altera_uart: Add support for polling mode (IRQ-less)
serial: Factor out uart_poll_timeout() from 8250 driver
serial: mark the 8250 driver as maintained
serial: 8250: Don't delay after transmitter is ready.
tty: MAINTAINERS: add drivers/serial/jsm/ as maintained driver
vcs: invoke the vt update callback when /dev/vcs* is written to
...
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Kconfig | 15 | ||||
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/amiserial.c | 56 | ||||
-rw-r--r-- | drivers/char/cyclades.c | 49 | ||||
-rw-r--r-- | drivers/char/ip2/ip2main.c | 72 | ||||
-rw-r--r-- | drivers/char/mxser.c | 109 | ||||
-rw-r--r-- | drivers/char/nozomi.c | 37 | ||||
-rw-r--r-- | drivers/char/pcmcia/synclink_cs.c | 60 | ||||
-rw-r--r-- | drivers/char/pty.c | 4 | ||||
-rw-r--r-- | drivers/char/synclink.c | 73 | ||||
-rw-r--r-- | drivers/char/synclink_gt.c | 55 | ||||
-rw-r--r-- | drivers/char/synclinkmp.c | 61 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 77 | ||||
-rw-r--r-- | drivers/char/ttyprintk.c | 225 | ||||
-rw-r--r-- | drivers/char/vc_screen.c | 135 | ||||
-rw-r--r-- | drivers/char/vt.c | 5 |
16 files changed, 748 insertions, 286 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 3d44ec724c17..43d3395325c5 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
@@ -493,6 +493,21 @@ config LEGACY_PTY_COUNT | |||
493 | When not in use, each legacy PTY occupies 12 bytes on 32-bit | 493 | When not in use, each legacy PTY occupies 12 bytes on 32-bit |
494 | architectures and 24 bytes on 64-bit architectures. | 494 | architectures and 24 bytes on 64-bit architectures. |
495 | 495 | ||
496 | config TTY_PRINTK | ||
497 | bool "TTY driver to output user messages via printk" | ||
498 | depends on EMBEDDED | ||
499 | default n | ||
500 | ---help--- | ||
501 | If you say Y here, the support for writing user messages (i.e. | ||
502 | console messages) via printk is available. | ||
503 | |||
504 | The feature is useful to inline user messages with kernel | ||
505 | messages. | ||
506 | In order to use this feature, you should output user messages | ||
507 | to /dev/ttyprintk or redirect console to this TTY. | ||
508 | |||
509 | If unsure, say N. | ||
510 | |||
496 | config BRIQ_PANEL | 511 | config BRIQ_PANEL |
497 | tristate 'Total Impact briQ front panel driver' | 512 | tristate 'Total Impact briQ front panel driver' |
498 | depends on PPC_CHRP | 513 | depends on PPC_CHRP |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index dc9641660605..3a9c01416839 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -12,6 +12,7 @@ obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o t | |||
12 | obj-y += tty_mutex.o | 12 | obj-y += tty_mutex.o |
13 | obj-$(CONFIG_LEGACY_PTYS) += pty.o | 13 | obj-$(CONFIG_LEGACY_PTYS) += pty.o |
14 | obj-$(CONFIG_UNIX98_PTYS) += pty.o | 14 | obj-$(CONFIG_UNIX98_PTYS) += pty.o |
15 | obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o | ||
15 | obj-y += misc.o | 16 | obj-y += misc.o |
16 | obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o | 17 | obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o |
17 | obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o | 18 | obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o |
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index a11c8c9ca3d4..b0a70461a12c 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) | |||
1263 | return 0; | 1263 | return 0; |
1264 | } | 1264 | } |
1265 | 1265 | ||
1266 | /* | ||
1267 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
1268 | * Return: write counters to the user passed counter struct | ||
1269 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1270 | * RI where only 0->1 is counted. | ||
1271 | */ | ||
1272 | static int rs_get_icount(struct tty_struct *tty, | ||
1273 | struct serial_icounter_struct *icount) | ||
1274 | { | ||
1275 | struct async_struct *info = tty->driver_data; | ||
1276 | struct async_icount cnow; | ||
1277 | unsigned long flags; | ||
1278 | |||
1279 | local_irq_save(flags); | ||
1280 | cnow = info->state->icount; | ||
1281 | local_irq_restore(flags); | ||
1282 | icount->cts = cnow.cts; | ||
1283 | icount->dsr = cnow.dsr; | ||
1284 | icount->rng = cnow.rng; | ||
1285 | icount->dcd = cnow.dcd; | ||
1286 | icount->rx = cnow.rx; | ||
1287 | icount->tx = cnow.tx; | ||
1288 | icount->frame = cnow.frame; | ||
1289 | icount->overrun = cnow.overrun; | ||
1290 | icount->parity = cnow.parity; | ||
1291 | icount->brk = cnow.brk; | ||
1292 | icount->buf_overrun = cnow.buf_overrun; | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1266 | 1296 | ||
1267 | static int rs_ioctl(struct tty_struct *tty, struct file * file, | 1297 | static int rs_ioctl(struct tty_struct *tty, struct file * file, |
1268 | unsigned int cmd, unsigned long arg) | 1298 | unsigned int cmd, unsigned long arg) |
@@ -1332,31 +1362,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, | |||
1332 | } | 1362 | } |
1333 | /* NOTREACHED */ | 1363 | /* NOTREACHED */ |
1334 | 1364 | ||
1335 | /* | ||
1336 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
1337 | * Return: write counters to the user passed counter struct | ||
1338 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1339 | * RI where only 0->1 is counted. | ||
1340 | */ | ||
1341 | case TIOCGICOUNT: | ||
1342 | local_irq_save(flags); | ||
1343 | cnow = info->state->icount; | ||
1344 | local_irq_restore(flags); | ||
1345 | icount.cts = cnow.cts; | ||
1346 | icount.dsr = cnow.dsr; | ||
1347 | icount.rng = cnow.rng; | ||
1348 | icount.dcd = cnow.dcd; | ||
1349 | icount.rx = cnow.rx; | ||
1350 | icount.tx = cnow.tx; | ||
1351 | icount.frame = cnow.frame; | ||
1352 | icount.overrun = cnow.overrun; | ||
1353 | icount.parity = cnow.parity; | ||
1354 | icount.brk = cnow.brk; | ||
1355 | icount.buf_overrun = cnow.buf_overrun; | ||
1356 | |||
1357 | if (copy_to_user(argp, &icount, sizeof(icount))) | ||
1358 | return -EFAULT; | ||
1359 | return 0; | ||
1360 | case TIOCSERGWILD: | 1365 | case TIOCSERGWILD: |
1361 | case TIOCSERSWILD: | 1366 | case TIOCSERSWILD: |
1362 | /* "setserial -W" is called in Debian boot */ | 1367 | /* "setserial -W" is called in Debian boot */ |
@@ -1958,6 +1963,7 @@ static const struct tty_operations serial_ops = { | |||
1958 | .wait_until_sent = rs_wait_until_sent, | 1963 | .wait_until_sent = rs_wait_until_sent, |
1959 | .tiocmget = rs_tiocmget, | 1964 | .tiocmget = rs_tiocmget, |
1960 | .tiocmset = rs_tiocmset, | 1965 | .tiocmset = rs_tiocmset, |
1966 | .get_icount = rs_get_icount, | ||
1961 | .proc_fops = &rs_proc_fops, | 1967 | .proc_fops = &rs_proc_fops, |
1962 | }; | 1968 | }; |
1963 | 1969 | ||
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 27aad9422332..4f152c28f40e 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
@@ -2790,29 +2790,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file, | |||
2790 | * NB: both 1->0 and 0->1 transitions are counted except for | 2790 | * NB: both 1->0 and 0->1 transitions are counted except for |
2791 | * RI where only 0->1 is counted. | 2791 | * RI where only 0->1 is counted. |
2792 | */ | 2792 | */ |
2793 | case TIOCGICOUNT: { | ||
2794 | struct serial_icounter_struct sic = { }; | ||
2795 | |||
2796 | spin_lock_irqsave(&info->card->card_lock, flags); | ||
2797 | cnow = info->icount; | ||
2798 | spin_unlock_irqrestore(&info->card->card_lock, flags); | ||
2799 | |||
2800 | sic.cts = cnow.cts; | ||
2801 | sic.dsr = cnow.dsr; | ||
2802 | sic.rng = cnow.rng; | ||
2803 | sic.dcd = cnow.dcd; | ||
2804 | sic.rx = cnow.rx; | ||
2805 | sic.tx = cnow.tx; | ||
2806 | sic.frame = cnow.frame; | ||
2807 | sic.overrun = cnow.overrun; | ||
2808 | sic.parity = cnow.parity; | ||
2809 | sic.brk = cnow.brk; | ||
2810 | sic.buf_overrun = cnow.buf_overrun; | ||
2811 | |||
2812 | if (copy_to_user(argp, &sic, sizeof(sic))) | ||
2813 | ret_val = -EFAULT; | ||
2814 | break; | ||
2815 | } | ||
2816 | default: | 2793 | default: |
2817 | ret_val = -ENOIOCTLCMD; | 2794 | ret_val = -ENOIOCTLCMD; |
2818 | } | 2795 | } |
@@ -2823,6 +2800,31 @@ cy_ioctl(struct tty_struct *tty, struct file *file, | |||
2823 | return ret_val; | 2800 | return ret_val; |
2824 | } /* cy_ioctl */ | 2801 | } /* cy_ioctl */ |
2825 | 2802 | ||
2803 | static int cy_get_icount(struct tty_struct *tty, | ||
2804 | struct serial_icounter_struct *sic) | ||
2805 | { | ||
2806 | struct cyclades_port *info = tty->driver_data; | ||
2807 | struct cyclades_icount cnow; /* Used to snapshot */ | ||
2808 | unsigned long flags; | ||
2809 | |||
2810 | spin_lock_irqsave(&info->card->card_lock, flags); | ||
2811 | cnow = info->icount; | ||
2812 | spin_unlock_irqrestore(&info->card->card_lock, flags); | ||
2813 | |||
2814 | sic->cts = cnow.cts; | ||
2815 | sic->dsr = cnow.dsr; | ||
2816 | sic->rng = cnow.rng; | ||
2817 | sic->dcd = cnow.dcd; | ||
2818 | sic->rx = cnow.rx; | ||
2819 | sic->tx = cnow.tx; | ||
2820 | sic->frame = cnow.frame; | ||
2821 | sic->overrun = cnow.overrun; | ||
2822 | sic->parity = cnow.parity; | ||
2823 | sic->brk = cnow.brk; | ||
2824 | sic->buf_overrun = cnow.buf_overrun; | ||
2825 | return 0; | ||
2826 | } | ||
2827 | |||
2826 | /* | 2828 | /* |
2827 | * This routine allows the tty driver to be notified when | 2829 | * This routine allows the tty driver to be notified when |
2828 | * device's termios settings have changed. Note that a | 2830 | * device's termios settings have changed. Note that a |
@@ -4084,6 +4086,7 @@ static const struct tty_operations cy_ops = { | |||
4084 | .wait_until_sent = cy_wait_until_sent, | 4086 | .wait_until_sent = cy_wait_until_sent, |
4085 | .tiocmget = cy_tiocmget, | 4087 | .tiocmget = cy_tiocmget, |
4086 | .tiocmset = cy_tiocmset, | 4088 | .tiocmset = cy_tiocmset, |
4089 | .get_icount = cy_get_icount, | ||
4087 | .proc_fops = &cyclades_proc_fops, | 4090 | .proc_fops = &cyclades_proc_fops, |
4088 | }; | 4091 | }; |
4089 | 4092 | ||
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 64a439ce2f89..fcd02baa7d65 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c | |||
@@ -184,6 +184,8 @@ static void ip2_hangup(PTTY); | |||
184 | static int ip2_tiocmget(struct tty_struct *tty, struct file *file); | 184 | static int ip2_tiocmget(struct tty_struct *tty, struct file *file); |
185 | static int ip2_tiocmset(struct tty_struct *tty, struct file *file, | 185 | static int ip2_tiocmset(struct tty_struct *tty, struct file *file, |
186 | unsigned int set, unsigned int clear); | 186 | unsigned int set, unsigned int clear); |
187 | static int ip2_get_icount(struct tty_struct *tty, | ||
188 | struct serial_icounter_struct *icount); | ||
187 | 189 | ||
188 | static void set_irq(int, int); | 190 | static void set_irq(int, int); |
189 | static void ip2_interrupt_bh(struct work_struct *work); | 191 | static void ip2_interrupt_bh(struct work_struct *work); |
@@ -456,6 +458,7 @@ static const struct tty_operations ip2_ops = { | |||
456 | .hangup = ip2_hangup, | 458 | .hangup = ip2_hangup, |
457 | .tiocmget = ip2_tiocmget, | 459 | .tiocmget = ip2_tiocmget, |
458 | .tiocmset = ip2_tiocmset, | 460 | .tiocmset = ip2_tiocmset, |
461 | .get_icount = ip2_get_icount, | ||
459 | .proc_fops = &ip2_proc_fops, | 462 | .proc_fops = &ip2_proc_fops, |
460 | }; | 463 | }; |
461 | 464 | ||
@@ -2130,7 +2133,6 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg ) | |||
2130 | i2ChanStrPtr pCh = DevTable[tty->index]; | 2133 | i2ChanStrPtr pCh = DevTable[tty->index]; |
2131 | i2eBordStrPtr pB; | 2134 | i2eBordStrPtr pB; |
2132 | struct async_icount cprev, cnow; /* kernel counter temps */ | 2135 | struct async_icount cprev, cnow; /* kernel counter temps */ |
2133 | struct serial_icounter_struct __user *p_cuser; | ||
2134 | int rc = 0; | 2136 | int rc = 0; |
2135 | unsigned long flags; | 2137 | unsigned long flags; |
2136 | void __user *argp = (void __user *)arg; | 2138 | void __user *argp = (void __user *)arg; |
@@ -2299,34 +2301,6 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg ) | |||
2299 | break; | 2301 | break; |
2300 | 2302 | ||
2301 | /* | 2303 | /* |
2302 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
2303 | * Return: write counters to the user passed counter struct | ||
2304 | * NB: both 1->0 and 0->1 transitions are counted except for RI where | ||
2305 | * only 0->1 is counted. The controller is quite capable of counting | ||
2306 | * both, but this done to preserve compatibility with the standard | ||
2307 | * serial driver. | ||
2308 | */ | ||
2309 | case TIOCGICOUNT: | ||
2310 | ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc ); | ||
2311 | |||
2312 | write_lock_irqsave(&pB->read_fifo_spinlock, flags); | ||
2313 | cnow = pCh->icount; | ||
2314 | write_unlock_irqrestore(&pB->read_fifo_spinlock, flags); | ||
2315 | p_cuser = argp; | ||
2316 | rc = put_user(cnow.cts, &p_cuser->cts); | ||
2317 | rc = put_user(cnow.dsr, &p_cuser->dsr); | ||
2318 | rc = put_user(cnow.rng, &p_cuser->rng); | ||
2319 | rc = put_user(cnow.dcd, &p_cuser->dcd); | ||
2320 | rc = put_user(cnow.rx, &p_cuser->rx); | ||
2321 | rc = put_user(cnow.tx, &p_cuser->tx); | ||
2322 | rc = put_user(cnow.frame, &p_cuser->frame); | ||
2323 | rc = put_user(cnow.overrun, &p_cuser->overrun); | ||
2324 | rc = put_user(cnow.parity, &p_cuser->parity); | ||
2325 | rc = put_user(cnow.brk, &p_cuser->brk); | ||
2326 | rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun); | ||
2327 | break; | ||
2328 | |||
2329 | /* | ||
2330 | * The rest are not supported by this driver. By returning -ENOIOCTLCMD they | 2304 | * The rest are not supported by this driver. By returning -ENOIOCTLCMD they |
2331 | * will be passed to the line discipline for it to handle. | 2305 | * will be passed to the line discipline for it to handle. |
2332 | */ | 2306 | */ |
@@ -2350,6 +2324,46 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg ) | |||
2350 | return rc; | 2324 | return rc; |
2351 | } | 2325 | } |
2352 | 2326 | ||
2327 | static int ip2_get_icount(struct tty_struct *tty, | ||
2328 | struct serial_icounter_struct *icount) | ||
2329 | { | ||
2330 | i2ChanStrPtr pCh = DevTable[tty->index]; | ||
2331 | i2eBordStrPtr pB; | ||
2332 | struct async_icount cnow; /* kernel counter temp */ | ||
2333 | unsigned long flags; | ||
2334 | |||
2335 | if ( pCh == NULL ) | ||
2336 | return -ENODEV; | ||
2337 | |||
2338 | pB = pCh->pMyBord; | ||
2339 | |||
2340 | /* | ||
2341 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
2342 | * Return: write counters to the user passed counter struct | ||
2343 | * NB: both 1->0 and 0->1 transitions are counted except for RI where | ||
2344 | * only 0->1 is counted. The controller is quite capable of counting | ||
2345 | * both, but this done to preserve compatibility with the standard | ||
2346 | * serial driver. | ||
2347 | */ | ||
2348 | |||
2349 | write_lock_irqsave(&pB->read_fifo_spinlock, flags); | ||
2350 | cnow = pCh->icount; | ||
2351 | write_unlock_irqrestore(&pB->read_fifo_spinlock, flags); | ||
2352 | |||
2353 | icount->cts = cnow.cts; | ||
2354 | icount->dsr = cnow.dsr; | ||
2355 | icount->rng = cnow.rng; | ||
2356 | icount->dcd = cnow.dcd; | ||
2357 | icount->rx = cnow.rx; | ||
2358 | icount->tx = cnow.tx; | ||
2359 | icount->frame = cnow.frame; | ||
2360 | icount->overrun = cnow.overrun; | ||
2361 | icount->parity = cnow.parity; | ||
2362 | icount->brk = cnow.brk; | ||
2363 | icount->buf_overrun = cnow.buf_overrun; | ||
2364 | return 0; | ||
2365 | } | ||
2366 | |||
2353 | /******************************************************************************/ | 2367 | /******************************************************************************/ |
2354 | /* Function: GetSerialInfo() */ | 2368 | /* Function: GetSerialInfo() */ |
2355 | /* Parameters: Pointer to channel structure */ | 2369 | /* Parameters: Pointer to channel structure */ |
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 3fc89da856ae..463df27494bd 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, | |||
1700 | return 0; | 1700 | return 0; |
1701 | } | 1701 | } |
1702 | 1702 | ||
1703 | if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT && | 1703 | if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && |
1704 | test_bit(TTY_IO_ERROR, &tty->flags)) | 1704 | test_bit(TTY_IO_ERROR, &tty->flags)) |
1705 | return -EIO; | 1705 | return -EIO; |
1706 | 1706 | ||
@@ -1730,32 +1730,6 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1730 | 1730 | ||
1731 | return wait_event_interruptible(info->port.delta_msr_wait, | 1731 | return wait_event_interruptible(info->port.delta_msr_wait, |
1732 | mxser_cflags_changed(info, arg, &cnow)); | 1732 | mxser_cflags_changed(info, arg, &cnow)); |
1733 | /* | ||
1734 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
1735 | * Return: write counters to the user passed counter struct | ||
1736 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1737 | * RI where only 0->1 is counted. | ||
1738 | */ | ||
1739 | case TIOCGICOUNT: { | ||
1740 | struct serial_icounter_struct icnt = { 0 }; | ||
1741 | spin_lock_irqsave(&info->slock, flags); | ||
1742 | cnow = info->icount; | ||
1743 | spin_unlock_irqrestore(&info->slock, flags); | ||
1744 | |||
1745 | icnt.frame = cnow.frame; | ||
1746 | icnt.brk = cnow.brk; | ||
1747 | icnt.overrun = cnow.overrun; | ||
1748 | icnt.buf_overrun = cnow.buf_overrun; | ||
1749 | icnt.parity = cnow.parity; | ||
1750 | icnt.rx = cnow.rx; | ||
1751 | icnt.tx = cnow.tx; | ||
1752 | icnt.cts = cnow.cts; | ||
1753 | icnt.dsr = cnow.dsr; | ||
1754 | icnt.rng = cnow.rng; | ||
1755 | icnt.dcd = cnow.dcd; | ||
1756 | |||
1757 | return copy_to_user(argp, &icnt, sizeof(icnt)) ? -EFAULT : 0; | ||
1758 | } | ||
1759 | case MOXA_HighSpeedOn: | 1733 | case MOXA_HighSpeedOn: |
1760 | return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); | 1734 | return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); |
1761 | case MOXA_SDS_RSTICOUNTER: | 1735 | case MOXA_SDS_RSTICOUNTER: |
@@ -1828,6 +1802,39 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, | |||
1828 | return 0; | 1802 | return 0; |
1829 | } | 1803 | } |
1830 | 1804 | ||
1805 | /* | ||
1806 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
1807 | * Return: write counters to the user passed counter struct | ||
1808 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1809 | * RI where only 0->1 is counted. | ||
1810 | */ | ||
1811 | |||
1812 | static int mxser_get_icount(struct tty_struct *tty, | ||
1813 | struct serial_icounter_struct *icount) | ||
1814 | |||
1815 | { | ||
1816 | struct mxser_port *info = tty->driver_data; | ||
1817 | struct async_icount cnow; | ||
1818 | unsigned long flags; | ||
1819 | |||
1820 | spin_lock_irqsave(&info->slock, flags); | ||
1821 | cnow = info->icount; | ||
1822 | spin_unlock_irqrestore(&info->slock, flags); | ||
1823 | |||
1824 | icount->frame = cnow.frame; | ||
1825 | icount->brk = cnow.brk; | ||
1826 | icount->overrun = cnow.overrun; | ||
1827 | icount->buf_overrun = cnow.buf_overrun; | ||
1828 | icount->parity = cnow.parity; | ||
1829 | icount->rx = cnow.rx; | ||
1830 | icount->tx = cnow.tx; | ||
1831 | icount->cts = cnow.cts; | ||
1832 | icount->dsr = cnow.dsr; | ||
1833 | icount->rng = cnow.rng; | ||
1834 | icount->dcd = cnow.dcd; | ||
1835 | return 0; | ||
1836 | } | ||
1837 | |||
1831 | static void mxser_stoprx(struct tty_struct *tty) | 1838 | static void mxser_stoprx(struct tty_struct *tty) |
1832 | { | 1839 | { |
1833 | struct mxser_port *info = tty->driver_data; | 1840 | struct mxser_port *info = tty->driver_data; |
@@ -2326,6 +2333,7 @@ static const struct tty_operations mxser_ops = { | |||
2326 | .wait_until_sent = mxser_wait_until_sent, | 2333 | .wait_until_sent = mxser_wait_until_sent, |
2327 | .tiocmget = mxser_tiocmget, | 2334 | .tiocmget = mxser_tiocmget, |
2328 | .tiocmset = mxser_tiocmset, | 2335 | .tiocmset = mxser_tiocmset, |
2336 | .get_icount = mxser_get_icount, | ||
2329 | }; | 2337 | }; |
2330 | 2338 | ||
2331 | struct tty_port_operations mxser_port_ops = { | 2339 | struct tty_port_operations mxser_port_ops = { |
@@ -2339,20 +2347,11 @@ struct tty_port_operations mxser_port_ops = { | |||
2339 | * The MOXA Smartio/Industio serial driver boot-time initialization code! | 2347 | * The MOXA Smartio/Industio serial driver boot-time initialization code! |
2340 | */ | 2348 | */ |
2341 | 2349 | ||
2342 | static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev, | 2350 | static void mxser_release_ISA_res(struct mxser_board *brd) |
2343 | unsigned int irq) | ||
2344 | { | 2351 | { |
2345 | if (irq) | 2352 | free_irq(brd->irq, brd); |
2346 | free_irq(brd->irq, brd); | 2353 | release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); |
2347 | if (pdev != NULL) { /* PCI */ | 2354 | release_region(brd->vector, 1); |
2348 | #ifdef CONFIG_PCI | ||
2349 | pci_release_region(pdev, 2); | ||
2350 | pci_release_region(pdev, 3); | ||
2351 | #endif | ||
2352 | } else { | ||
2353 | release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); | ||
2354 | release_region(brd->vector, 1); | ||
2355 | } | ||
2356 | } | 2355 | } |
2357 | 2356 | ||
2358 | static int __devinit mxser_initbrd(struct mxser_board *brd, | 2357 | static int __devinit mxser_initbrd(struct mxser_board *brd, |
@@ -2397,13 +2396,11 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, | |||
2397 | 2396 | ||
2398 | retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser", | 2397 | retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser", |
2399 | brd); | 2398 | brd); |
2400 | if (retval) { | 2399 | if (retval) |
2401 | printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " | 2400 | printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " |
2402 | "conflict with another device.\n", | 2401 | "conflict with another device.\n", |
2403 | brd->info->name, brd->irq); | 2402 | brd->info->name, brd->irq); |
2404 | /* We hold resources, we need to release them. */ | 2403 | |
2405 | mxser_release_res(brd, pdev, 0); | ||
2406 | } | ||
2407 | return retval; | 2404 | return retval; |
2408 | } | 2405 | } |
2409 | 2406 | ||
@@ -2555,7 +2552,7 @@ static int __devinit mxser_probe(struct pci_dev *pdev, | |||
2555 | ioaddress = pci_resource_start(pdev, 2); | 2552 | ioaddress = pci_resource_start(pdev, 2); |
2556 | retval = pci_request_region(pdev, 2, "mxser(IO)"); | 2553 | retval = pci_request_region(pdev, 2, "mxser(IO)"); |
2557 | if (retval) | 2554 | if (retval) |
2558 | goto err; | 2555 | goto err_dis; |
2559 | 2556 | ||
2560 | brd->info = &mxser_cards[ent->driver_data]; | 2557 | brd->info = &mxser_cards[ent->driver_data]; |
2561 | for (i = 0; i < brd->info->nports; i++) | 2558 | for (i = 0; i < brd->info->nports; i++) |
@@ -2565,7 +2562,7 @@ static int __devinit mxser_probe(struct pci_dev *pdev, | |||
2565 | ioaddress = pci_resource_start(pdev, 3); | 2562 | ioaddress = pci_resource_start(pdev, 3); |
2566 | retval = pci_request_region(pdev, 3, "mxser(vector)"); | 2563 | retval = pci_request_region(pdev, 3, "mxser(vector)"); |
2567 | if (retval) | 2564 | if (retval) |
2568 | goto err_relio; | 2565 | goto err_zero; |
2569 | brd->vector = ioaddress; | 2566 | brd->vector = ioaddress; |
2570 | 2567 | ||
2571 | /* irq */ | 2568 | /* irq */ |
@@ -2608,7 +2605,7 @@ static int __devinit mxser_probe(struct pci_dev *pdev, | |||
2608 | /* mxser_initbrd will hook ISR. */ | 2605 | /* mxser_initbrd will hook ISR. */ |
2609 | retval = mxser_initbrd(brd, pdev); | 2606 | retval = mxser_initbrd(brd, pdev); |
2610 | if (retval) | 2607 | if (retval) |
2611 | goto err_null; | 2608 | goto err_rel3; |
2612 | 2609 | ||
2613 | for (i = 0; i < brd->info->nports; i++) | 2610 | for (i = 0; i < brd->info->nports; i++) |
2614 | tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev); | 2611 | tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev); |
@@ -2616,10 +2613,13 @@ static int __devinit mxser_probe(struct pci_dev *pdev, | |||
2616 | pci_set_drvdata(pdev, brd); | 2613 | pci_set_drvdata(pdev, brd); |
2617 | 2614 | ||
2618 | return 0; | 2615 | return 0; |
2619 | err_relio: | 2616 | err_rel3: |
2620 | pci_release_region(pdev, 2); | 2617 | pci_release_region(pdev, 3); |
2621 | err_null: | 2618 | err_zero: |
2622 | brd->info = NULL; | 2619 | brd->info = NULL; |
2620 | pci_release_region(pdev, 2); | ||
2621 | err_dis: | ||
2622 | pci_disable_device(pdev); | ||
2623 | err: | 2623 | err: |
2624 | return retval; | 2624 | return retval; |
2625 | #else | 2625 | #else |
@@ -2629,14 +2629,19 @@ err: | |||
2629 | 2629 | ||
2630 | static void __devexit mxser_remove(struct pci_dev *pdev) | 2630 | static void __devexit mxser_remove(struct pci_dev *pdev) |
2631 | { | 2631 | { |
2632 | #ifdef CONFIG_PCI | ||
2632 | struct mxser_board *brd = pci_get_drvdata(pdev); | 2633 | struct mxser_board *brd = pci_get_drvdata(pdev); |
2633 | unsigned int i; | 2634 | unsigned int i; |
2634 | 2635 | ||
2635 | for (i = 0; i < brd->info->nports; i++) | 2636 | for (i = 0; i < brd->info->nports; i++) |
2636 | tty_unregister_device(mxvar_sdriver, brd->idx + i); | 2637 | tty_unregister_device(mxvar_sdriver, brd->idx + i); |
2637 | 2638 | ||
2638 | mxser_release_res(brd, pdev, 1); | 2639 | free_irq(pdev->irq, brd); |
2640 | pci_release_region(pdev, 2); | ||
2641 | pci_release_region(pdev, 3); | ||
2642 | pci_disable_device(pdev); | ||
2639 | brd->info = NULL; | 2643 | brd->info = NULL; |
2644 | #endif | ||
2640 | } | 2645 | } |
2641 | 2646 | ||
2642 | static struct pci_driver mxser_driver = { | 2647 | static struct pci_driver mxser_driver = { |
@@ -2741,7 +2746,7 @@ static void __exit mxser_module_exit(void) | |||
2741 | 2746 | ||
2742 | for (i = 0; i < MXSER_BOARDS; i++) | 2747 | for (i = 0; i < MXSER_BOARDS; i++) |
2743 | if (mxser_boards[i].info != NULL) | 2748 | if (mxser_boards[i].info != NULL) |
2744 | mxser_release_res(&mxser_boards[i], NULL, 1); | 2749 | mxser_release_ISA_res(&mxser_boards[i]); |
2745 | } | 2750 | } |
2746 | 2751 | ||
2747 | module_init(mxser_module_init); | 2752 | module_init(mxser_module_init); |
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index 817169cbb245..dd3f9b1f11b4 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, | |||
1804 | return ret; | 1804 | return ret; |
1805 | } | 1805 | } |
1806 | 1806 | ||
1807 | static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp) | 1807 | static int ntty_tiocgicount(struct tty_struct *tty, |
1808 | struct serial_icounter_struct *icount) | ||
1808 | { | 1809 | { |
1810 | struct port *port = tty->driver_data; | ||
1809 | const struct async_icount cnow = port->tty_icount; | 1811 | const struct async_icount cnow = port->tty_icount; |
1810 | struct serial_icounter_struct icount; | 1812 | |
1811 | 1813 | icount->cts = cnow.cts; | |
1812 | icount.cts = cnow.cts; | 1814 | icount->dsr = cnow.dsr; |
1813 | icount.dsr = cnow.dsr; | 1815 | icount->rng = cnow.rng; |
1814 | icount.rng = cnow.rng; | 1816 | icount->dcd = cnow.dcd; |
1815 | icount.dcd = cnow.dcd; | 1817 | icount->rx = cnow.rx; |
1816 | icount.rx = cnow.rx; | 1818 | icount->tx = cnow.tx; |
1817 | icount.tx = cnow.tx; | 1819 | icount->frame = cnow.frame; |
1818 | icount.frame = cnow.frame; | 1820 | icount->overrun = cnow.overrun; |
1819 | icount.overrun = cnow.overrun; | 1821 | icount->parity = cnow.parity; |
1820 | icount.parity = cnow.parity; | 1822 | icount->brk = cnow.brk; |
1821 | icount.brk = cnow.brk; | 1823 | icount->buf_overrun = cnow.buf_overrun; |
1822 | icount.buf_overrun = cnow.buf_overrun; | 1824 | return 0; |
1823 | |||
1824 | return copy_to_user(argp, &icount, sizeof(icount)) ? -EFAULT : 0; | ||
1825 | } | 1825 | } |
1826 | 1826 | ||
1827 | static int ntty_ioctl(struct tty_struct *tty, struct file *file, | 1827 | 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, | |||
1840 | rval = wait_event_interruptible(port->tty_wait, | 1840 | rval = wait_event_interruptible(port->tty_wait, |
1841 | ntty_cflags_changed(port, arg, &cprev)); | 1841 | ntty_cflags_changed(port, arg, &cprev)); |
1842 | break; | 1842 | break; |
1843 | } case TIOCGICOUNT: | 1843 | } |
1844 | rval = ntty_ioctl_tiocgicount(port, argp); | ||
1845 | break; | ||
1846 | default: | 1844 | default: |
1847 | DBG1("ERR: 0x%08X, %d", cmd, cmd); | 1845 | DBG1("ERR: 0x%08X, %d", cmd, cmd); |
1848 | break; | 1846 | break; |
@@ -1922,6 +1920,7 @@ static const struct tty_operations tty_ops = { | |||
1922 | .chars_in_buffer = ntty_chars_in_buffer, | 1920 | .chars_in_buffer = ntty_chars_in_buffer, |
1923 | .tiocmget = ntty_tiocmget, | 1921 | .tiocmget = ntty_tiocmget, |
1924 | .tiocmset = ntty_tiocmset, | 1922 | .tiocmset = ntty_tiocmset, |
1923 | .get_icount = ntty_tiocgicount, | ||
1925 | .install = ntty_install, | 1924 | .install = ntty_install, |
1926 | .cleanup = ntty_cleanup, | 1925 | .cleanup = ntty_cleanup, |
1927 | }; | 1926 | }; |
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index be1810057607..bfc10f89d951 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c | |||
@@ -2191,6 +2191,32 @@ static int mgslpc_break(struct tty_struct *tty, int break_state) | |||
2191 | return 0; | 2191 | return 0; |
2192 | } | 2192 | } |
2193 | 2193 | ||
2194 | static int mgslpc_get_icount(struct tty_struct *tty, | ||
2195 | struct serial_icounter_struct *icount) | ||
2196 | { | ||
2197 | MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; | ||
2198 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
2199 | unsigned long flags; | ||
2200 | |||
2201 | spin_lock_irqsave(&info->lock,flags); | ||
2202 | cnow = info->icount; | ||
2203 | spin_unlock_irqrestore(&info->lock,flags); | ||
2204 | |||
2205 | icount->cts = cnow.cts; | ||
2206 | icount->dsr = cnow.dsr; | ||
2207 | icount->rng = cnow.rng; | ||
2208 | icount->dcd = cnow.dcd; | ||
2209 | icount->rx = cnow.rx; | ||
2210 | icount->tx = cnow.tx; | ||
2211 | icount->frame = cnow.frame; | ||
2212 | icount->overrun = cnow.overrun; | ||
2213 | icount->parity = cnow.parity; | ||
2214 | icount->brk = cnow.brk; | ||
2215 | icount->buf_overrun = cnow.buf_overrun; | ||
2216 | |||
2217 | return 0; | ||
2218 | } | ||
2219 | |||
2194 | /* Service an IOCTL request | 2220 | /* Service an IOCTL request |
2195 | * | 2221 | * |
2196 | * Arguments: | 2222 | * Arguments: |
@@ -2206,11 +2232,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file, | |||
2206 | unsigned int cmd, unsigned long arg) | 2232 | unsigned int cmd, unsigned long arg) |
2207 | { | 2233 | { |
2208 | MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; | 2234 | MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data; |
2209 | int error; | ||
2210 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
2211 | struct serial_icounter_struct __user *p_cuser; /* user space */ | ||
2212 | void __user *argp = (void __user *)arg; | 2235 | void __user *argp = (void __user *)arg; |
2213 | unsigned long flags; | ||
2214 | 2236 | ||
2215 | if (debug_level >= DEBUG_LEVEL_INFO) | 2237 | if (debug_level >= DEBUG_LEVEL_INFO) |
2216 | printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__, | 2238 | printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__, |
@@ -2220,7 +2242,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file, | |||
2220 | return -ENODEV; | 2242 | return -ENODEV; |
2221 | 2243 | ||
2222 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | 2244 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && |
2223 | (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { | 2245 | (cmd != TIOCMIWAIT)) { |
2224 | if (tty->flags & (1 << TTY_IO_ERROR)) | 2246 | if (tty->flags & (1 << TTY_IO_ERROR)) |
2225 | return -EIO; | 2247 | return -EIO; |
2226 | } | 2248 | } |
@@ -2250,34 +2272,6 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file, | |||
2250 | return wait_events(info, argp); | 2272 | return wait_events(info, argp); |
2251 | case TIOCMIWAIT: | 2273 | case TIOCMIWAIT: |
2252 | return modem_input_wait(info,(int)arg); | 2274 | return modem_input_wait(info,(int)arg); |
2253 | case TIOCGICOUNT: | ||
2254 | spin_lock_irqsave(&info->lock,flags); | ||
2255 | cnow = info->icount; | ||
2256 | spin_unlock_irqrestore(&info->lock,flags); | ||
2257 | p_cuser = argp; | ||
2258 | PUT_USER(error,cnow.cts, &p_cuser->cts); | ||
2259 | if (error) return error; | ||
2260 | PUT_USER(error,cnow.dsr, &p_cuser->dsr); | ||
2261 | if (error) return error; | ||
2262 | PUT_USER(error,cnow.rng, &p_cuser->rng); | ||
2263 | if (error) return error; | ||
2264 | PUT_USER(error,cnow.dcd, &p_cuser->dcd); | ||
2265 | if (error) return error; | ||
2266 | PUT_USER(error,cnow.rx, &p_cuser->rx); | ||
2267 | if (error) return error; | ||
2268 | PUT_USER(error,cnow.tx, &p_cuser->tx); | ||
2269 | if (error) return error; | ||
2270 | PUT_USER(error,cnow.frame, &p_cuser->frame); | ||
2271 | if (error) return error; | ||
2272 | PUT_USER(error,cnow.overrun, &p_cuser->overrun); | ||
2273 | if (error) return error; | ||
2274 | PUT_USER(error,cnow.parity, &p_cuser->parity); | ||
2275 | if (error) return error; | ||
2276 | PUT_USER(error,cnow.brk, &p_cuser->brk); | ||
2277 | if (error) return error; | ||
2278 | PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun); | ||
2279 | if (error) return error; | ||
2280 | return 0; | ||
2281 | default: | 2275 | default: |
2282 | return -ENOIOCTLCMD; | 2276 | return -ENOIOCTLCMD; |
2283 | } | 2277 | } |
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index c350d01716bd..923a48585501 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
@@ -676,7 +676,9 @@ static int ptmx_open(struct inode *inode, struct file *filp) | |||
676 | 676 | ||
677 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ | 677 | set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ |
678 | 678 | ||
679 | tty_add_file(tty, filp); | 679 | retval = tty_add_file(tty, filp); |
680 | if (retval) | ||
681 | goto out; | ||
680 | 682 | ||
681 | retval = devpts_pty_new(inode, tty->link); | 683 | retval = devpts_pty_new(inode, tty->link); |
682 | if (retval) | 684 | if (retval) |
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index a2a58004e188..3a6824f12be2 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) | |||
2925 | 2925 | ||
2926 | } /* end of mgsl_break() */ | 2926 | } /* end of mgsl_break() */ |
2927 | 2927 | ||
2928 | /* | ||
2929 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
2930 | * Return: write counters to the user passed counter struct | ||
2931 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
2932 | * RI where only 0->1 is counted. | ||
2933 | */ | ||
2934 | static int msgl_get_icount(struct tty_struct *tty, | ||
2935 | struct serial_icounter_struct *icount) | ||
2936 | |||
2937 | { | ||
2938 | struct mgsl_struct * info = tty->driver_data; | ||
2939 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
2940 | unsigned long flags; | ||
2941 | |||
2942 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2943 | cnow = info->icount; | ||
2944 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2945 | |||
2946 | icount->cts = cnow.cts; | ||
2947 | icount->dsr = cnow.dsr; | ||
2948 | icount->rng = cnow.rng; | ||
2949 | icount->dcd = cnow.dcd; | ||
2950 | icount->rx = cnow.rx; | ||
2951 | icount->tx = cnow.tx; | ||
2952 | icount->frame = cnow.frame; | ||
2953 | icount->overrun = cnow.overrun; | ||
2954 | icount->parity = cnow.parity; | ||
2955 | icount->brk = cnow.brk; | ||
2956 | icount->buf_overrun = cnow.buf_overrun; | ||
2957 | return 0; | ||
2958 | } | ||
2959 | |||
2928 | /* mgsl_ioctl() Service an IOCTL request | 2960 | /* mgsl_ioctl() Service an IOCTL request |
2929 | * | 2961 | * |
2930 | * Arguments: | 2962 | * Arguments: |
@@ -2949,7 +2981,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file, | |||
2949 | return -ENODEV; | 2981 | return -ENODEV; |
2950 | 2982 | ||
2951 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | 2983 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && |
2952 | (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { | 2984 | (cmd != TIOCMIWAIT)) { |
2953 | if (tty->flags & (1 << TTY_IO_ERROR)) | 2985 | if (tty->flags & (1 << TTY_IO_ERROR)) |
2954 | return -EIO; | 2986 | return -EIO; |
2955 | } | 2987 | } |
@@ -2959,11 +2991,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file, | |||
2959 | 2991 | ||
2960 | static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) | 2992 | static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) |
2961 | { | 2993 | { |
2962 | int error; | ||
2963 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
2964 | void __user *argp = (void __user *)arg; | 2994 | void __user *argp = (void __user *)arg; |
2965 | struct serial_icounter_struct __user *p_cuser; /* user space */ | ||
2966 | unsigned long flags; | ||
2967 | 2995 | ||
2968 | switch (cmd) { | 2996 | switch (cmd) { |
2969 | case MGSL_IOCGPARAMS: | 2997 | case MGSL_IOCGPARAMS: |
@@ -2992,40 +3020,6 @@ static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigne | |||
2992 | case TIOCMIWAIT: | 3020 | case TIOCMIWAIT: |
2993 | return modem_input_wait(info,(int)arg); | 3021 | return modem_input_wait(info,(int)arg); |
2994 | 3022 | ||
2995 | /* | ||
2996 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
2997 | * Return: write counters to the user passed counter struct | ||
2998 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
2999 | * RI where only 0->1 is counted. | ||
3000 | */ | ||
3001 | case TIOCGICOUNT: | ||
3002 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
3003 | cnow = info->icount; | ||
3004 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
3005 | p_cuser = argp; | ||
3006 | PUT_USER(error,cnow.cts, &p_cuser->cts); | ||
3007 | if (error) return error; | ||
3008 | PUT_USER(error,cnow.dsr, &p_cuser->dsr); | ||
3009 | if (error) return error; | ||
3010 | PUT_USER(error,cnow.rng, &p_cuser->rng); | ||
3011 | if (error) return error; | ||
3012 | PUT_USER(error,cnow.dcd, &p_cuser->dcd); | ||
3013 | if (error) return error; | ||
3014 | PUT_USER(error,cnow.rx, &p_cuser->rx); | ||
3015 | if (error) return error; | ||
3016 | PUT_USER(error,cnow.tx, &p_cuser->tx); | ||
3017 | if (error) return error; | ||
3018 | PUT_USER(error,cnow.frame, &p_cuser->frame); | ||
3019 | if (error) return error; | ||
3020 | PUT_USER(error,cnow.overrun, &p_cuser->overrun); | ||
3021 | if (error) return error; | ||
3022 | PUT_USER(error,cnow.parity, &p_cuser->parity); | ||
3023 | if (error) return error; | ||
3024 | PUT_USER(error,cnow.brk, &p_cuser->brk); | ||
3025 | if (error) return error; | ||
3026 | PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun); | ||
3027 | if (error) return error; | ||
3028 | return 0; | ||
3029 | default: | 3023 | default: |
3030 | return -ENOIOCTLCMD; | 3024 | return -ENOIOCTLCMD; |
3031 | } | 3025 | } |
@@ -4328,6 +4322,7 @@ static const struct tty_operations mgsl_ops = { | |||
4328 | .hangup = mgsl_hangup, | 4322 | .hangup = mgsl_hangup, |
4329 | .tiocmget = tiocmget, | 4323 | .tiocmget = tiocmget, |
4330 | .tiocmset = tiocmset, | 4324 | .tiocmset = tiocmset, |
4325 | .get_icount = msgl_get_icount, | ||
4331 | .proc_fops = &mgsl_proc_fops, | 4326 | .proc_fops = &mgsl_proc_fops, |
4332 | }; | 4327 | }; |
4333 | 4328 | ||
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index e63b830c86cc..1746d91205f7 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, | |||
1032 | unsigned int cmd, unsigned long arg) | 1032 | unsigned int cmd, unsigned long arg) |
1033 | { | 1033 | { |
1034 | struct slgt_info *info = tty->driver_data; | 1034 | struct slgt_info *info = tty->driver_data; |
1035 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
1036 | struct serial_icounter_struct __user *p_cuser; /* user space */ | ||
1037 | unsigned long flags; | ||
1038 | void __user *argp = (void __user *)arg; | 1035 | void __user *argp = (void __user *)arg; |
1039 | int ret; | 1036 | int ret; |
1040 | 1037 | ||
@@ -1043,7 +1040,7 @@ static int ioctl(struct tty_struct *tty, struct file *file, | |||
1043 | DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); | 1040 | DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); |
1044 | 1041 | ||
1045 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | 1042 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && |
1046 | (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { | 1043 | (cmd != TIOCMIWAIT)) { |
1047 | if (tty->flags & (1 << TTY_IO_ERROR)) | 1044 | if (tty->flags & (1 << TTY_IO_ERROR)) |
1048 | return -EIO; | 1045 | return -EIO; |
1049 | } | 1046 | } |
@@ -1053,24 +1050,6 @@ static int ioctl(struct tty_struct *tty, struct file *file, | |||
1053 | return wait_mgsl_event(info, argp); | 1050 | return wait_mgsl_event(info, argp); |
1054 | case TIOCMIWAIT: | 1051 | case TIOCMIWAIT: |
1055 | return modem_input_wait(info,(int)arg); | 1052 | return modem_input_wait(info,(int)arg); |
1056 | case TIOCGICOUNT: | ||
1057 | spin_lock_irqsave(&info->lock,flags); | ||
1058 | cnow = info->icount; | ||
1059 | spin_unlock_irqrestore(&info->lock,flags); | ||
1060 | p_cuser = argp; | ||
1061 | if (put_user(cnow.cts, &p_cuser->cts) || | ||
1062 | put_user(cnow.dsr, &p_cuser->dsr) || | ||
1063 | put_user(cnow.rng, &p_cuser->rng) || | ||
1064 | put_user(cnow.dcd, &p_cuser->dcd) || | ||
1065 | put_user(cnow.rx, &p_cuser->rx) || | ||
1066 | put_user(cnow.tx, &p_cuser->tx) || | ||
1067 | put_user(cnow.frame, &p_cuser->frame) || | ||
1068 | put_user(cnow.overrun, &p_cuser->overrun) || | ||
1069 | put_user(cnow.parity, &p_cuser->parity) || | ||
1070 | put_user(cnow.brk, &p_cuser->brk) || | ||
1071 | put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) | ||
1072 | return -EFAULT; | ||
1073 | return 0; | ||
1074 | case MGSL_IOCSGPIO: | 1053 | case MGSL_IOCSGPIO: |
1075 | return set_gpio(info, argp); | 1054 | return set_gpio(info, argp); |
1076 | case MGSL_IOCGGPIO: | 1055 | case MGSL_IOCGGPIO: |
@@ -1117,6 +1096,33 @@ static int ioctl(struct tty_struct *tty, struct file *file, | |||
1117 | return ret; | 1096 | return ret; |
1118 | } | 1097 | } |
1119 | 1098 | ||
1099 | static int get_icount(struct tty_struct *tty, | ||
1100 | struct serial_icounter_struct *icount) | ||
1101 | |||
1102 | { | ||
1103 | struct slgt_info *info = tty->driver_data; | ||
1104 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
1105 | unsigned long flags; | ||
1106 | |||
1107 | spin_lock_irqsave(&info->lock,flags); | ||
1108 | cnow = info->icount; | ||
1109 | spin_unlock_irqrestore(&info->lock,flags); | ||
1110 | |||
1111 | icount->cts = cnow.cts; | ||
1112 | icount->dsr = cnow.dsr; | ||
1113 | icount->rng = cnow.rng; | ||
1114 | icount->dcd = cnow.dcd; | ||
1115 | icount->rx = cnow.rx; | ||
1116 | icount->tx = cnow.tx; | ||
1117 | icount->frame = cnow.frame; | ||
1118 | icount->overrun = cnow.overrun; | ||
1119 | icount->parity = cnow.parity; | ||
1120 | icount->brk = cnow.brk; | ||
1121 | icount->buf_overrun = cnow.buf_overrun; | ||
1122 | |||
1123 | return 0; | ||
1124 | } | ||
1125 | |||
1120 | /* | 1126 | /* |
1121 | * support for 32 bit ioctl calls on 64 bit systems | 1127 | * support for 32 bit ioctl calls on 64 bit systems |
1122 | */ | 1128 | */ |
@@ -1206,10 +1212,6 @@ static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file, | |||
1206 | case MGSL_IOCSGPIO: | 1212 | case MGSL_IOCSGPIO: |
1207 | case MGSL_IOCGGPIO: | 1213 | case MGSL_IOCGGPIO: |
1208 | case MGSL_IOCWAITGPIO: | 1214 | case MGSL_IOCWAITGPIO: |
1209 | case TIOCGICOUNT: | ||
1210 | rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg))); | ||
1211 | break; | ||
1212 | |||
1213 | case MGSL_IOCSTXIDLE: | 1215 | case MGSL_IOCSTXIDLE: |
1214 | case MGSL_IOCTXENABLE: | 1216 | case MGSL_IOCTXENABLE: |
1215 | case MGSL_IOCRXENABLE: | 1217 | case MGSL_IOCRXENABLE: |
@@ -3642,6 +3644,7 @@ static const struct tty_operations ops = { | |||
3642 | .hangup = hangup, | 3644 | .hangup = hangup, |
3643 | .tiocmget = tiocmget, | 3645 | .tiocmget = tiocmget, |
3644 | .tiocmset = tiocmset, | 3646 | .tiocmset = tiocmset, |
3647 | .get_icount = get_icount, | ||
3645 | .proc_fops = &synclink_gt_proc_fops, | 3648 | .proc_fops = &synclink_gt_proc_fops, |
3646 | }; | 3649 | }; |
3647 | 3650 | ||
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index e56caf7d82aa..2f9eb4b0dec1 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, | |||
1258 | unsigned int cmd, unsigned long arg) | 1258 | unsigned int cmd, unsigned long arg) |
1259 | { | 1259 | { |
1260 | SLMP_INFO *info = tty->driver_data; | 1260 | SLMP_INFO *info = tty->driver_data; |
1261 | int error; | ||
1262 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
1263 | struct serial_icounter_struct __user *p_cuser; /* user space */ | ||
1264 | unsigned long flags; | ||
1265 | void __user *argp = (void __user *)arg; | 1261 | void __user *argp = (void __user *)arg; |
1266 | 1262 | ||
1267 | if (debug_level >= DEBUG_LEVEL_INFO) | 1263 | if (debug_level >= DEBUG_LEVEL_INFO) |
@@ -1272,7 +1268,7 @@ static int ioctl(struct tty_struct *tty, struct file *file, | |||
1272 | return -ENODEV; | 1268 | return -ENODEV; |
1273 | 1269 | ||
1274 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | 1270 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && |
1275 | (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { | 1271 | (cmd != TIOCMIWAIT)) { |
1276 | if (tty->flags & (1 << TTY_IO_ERROR)) | 1272 | if (tty->flags & (1 << TTY_IO_ERROR)) |
1277 | return -EIO; | 1273 | return -EIO; |
1278 | } | 1274 | } |
@@ -1310,40 +1306,38 @@ static int ioctl(struct tty_struct *tty, struct file *file, | |||
1310 | * NB: both 1->0 and 0->1 transitions are counted except for | 1306 | * NB: both 1->0 and 0->1 transitions are counted except for |
1311 | * RI where only 0->1 is counted. | 1307 | * RI where only 0->1 is counted. |
1312 | */ | 1308 | */ |
1313 | case TIOCGICOUNT: | ||
1314 | spin_lock_irqsave(&info->lock,flags); | ||
1315 | cnow = info->icount; | ||
1316 | spin_unlock_irqrestore(&info->lock,flags); | ||
1317 | p_cuser = argp; | ||
1318 | PUT_USER(error,cnow.cts, &p_cuser->cts); | ||
1319 | if (error) return error; | ||
1320 | PUT_USER(error,cnow.dsr, &p_cuser->dsr); | ||
1321 | if (error) return error; | ||
1322 | PUT_USER(error,cnow.rng, &p_cuser->rng); | ||
1323 | if (error) return error; | ||
1324 | PUT_USER(error,cnow.dcd, &p_cuser->dcd); | ||
1325 | if (error) return error; | ||
1326 | PUT_USER(error,cnow.rx, &p_cuser->rx); | ||
1327 | if (error) return error; | ||
1328 | PUT_USER(error,cnow.tx, &p_cuser->tx); | ||
1329 | if (error) return error; | ||
1330 | PUT_USER(error,cnow.frame, &p_cuser->frame); | ||
1331 | if (error) return error; | ||
1332 | PUT_USER(error,cnow.overrun, &p_cuser->overrun); | ||
1333 | if (error) return error; | ||
1334 | PUT_USER(error,cnow.parity, &p_cuser->parity); | ||
1335 | if (error) return error; | ||
1336 | PUT_USER(error,cnow.brk, &p_cuser->brk); | ||
1337 | if (error) return error; | ||
1338 | PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun); | ||
1339 | if (error) return error; | ||
1340 | return 0; | ||
1341 | default: | 1309 | default: |
1342 | return -ENOIOCTLCMD; | 1310 | return -ENOIOCTLCMD; |
1343 | } | 1311 | } |
1344 | return 0; | 1312 | return 0; |
1345 | } | 1313 | } |
1346 | 1314 | ||
1315 | static int get_icount(struct tty_struct *tty, | ||
1316 | struct serial_icounter_struct *icount) | ||
1317 | { | ||
1318 | SLMP_INFO *info = tty->driver_data; | ||
1319 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
1320 | unsigned long flags; | ||
1321 | |||
1322 | spin_lock_irqsave(&info->lock,flags); | ||
1323 | cnow = info->icount; | ||
1324 | spin_unlock_irqrestore(&info->lock,flags); | ||
1325 | |||
1326 | icount->cts = cnow.cts; | ||
1327 | icount->dsr = cnow.dsr; | ||
1328 | icount->rng = cnow.rng; | ||
1329 | icount->dcd = cnow.dcd; | ||
1330 | icount->rx = cnow.rx; | ||
1331 | icount->tx = cnow.tx; | ||
1332 | icount->frame = cnow.frame; | ||
1333 | icount->overrun = cnow.overrun; | ||
1334 | icount->parity = cnow.parity; | ||
1335 | icount->brk = cnow.brk; | ||
1336 | icount->buf_overrun = cnow.buf_overrun; | ||
1337 | |||
1338 | return 0; | ||
1339 | } | ||
1340 | |||
1347 | /* | 1341 | /* |
1348 | * /proc fs routines.... | 1342 | * /proc fs routines.... |
1349 | */ | 1343 | */ |
@@ -3909,6 +3903,7 @@ static const struct tty_operations ops = { | |||
3909 | .hangup = hangup, | 3903 | .hangup = hangup, |
3910 | .tiocmget = tiocmget, | 3904 | .tiocmget = tiocmget, |
3911 | .tiocmset = tiocmset, | 3905 | .tiocmset = tiocmset, |
3906 | .get_icount = get_icount, | ||
3912 | .proc_fops = &synclinkmp_proc_fops, | 3907 | .proc_fops = &synclinkmp_proc_fops, |
3913 | }; | 3908 | }; |
3914 | 3909 | ||
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 613c852ee0fe..c05c5af5aa04 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -96,6 +96,7 @@ | |||
96 | #include <linux/bitops.h> | 96 | #include <linux/bitops.h> |
97 | #include <linux/delay.h> | 97 | #include <linux/delay.h> |
98 | #include <linux/seq_file.h> | 98 | #include <linux/seq_file.h> |
99 | #include <linux/serial.h> | ||
99 | 100 | ||
100 | #include <linux/uaccess.h> | 101 | #include <linux/uaccess.h> |
101 | #include <asm/system.h> | 102 | #include <asm/system.h> |
@@ -183,6 +184,8 @@ struct tty_struct *alloc_tty_struct(void) | |||
183 | 184 | ||
184 | void free_tty_struct(struct tty_struct *tty) | 185 | void free_tty_struct(struct tty_struct *tty) |
185 | { | 186 | { |
187 | if (tty->dev) | ||
188 | put_device(tty->dev); | ||
186 | kfree(tty->write_buf); | 189 | kfree(tty->write_buf); |
187 | tty_buffer_free_all(tty); | 190 | tty_buffer_free_all(tty); |
188 | kfree(tty); | 191 | kfree(tty); |
@@ -194,12 +197,13 @@ static inline struct tty_struct *file_tty(struct file *file) | |||
194 | } | 197 | } |
195 | 198 | ||
196 | /* Associate a new file with the tty structure */ | 199 | /* Associate a new file with the tty structure */ |
197 | void tty_add_file(struct tty_struct *tty, struct file *file) | 200 | int tty_add_file(struct tty_struct *tty, struct file *file) |
198 | { | 201 | { |
199 | struct tty_file_private *priv; | 202 | struct tty_file_private *priv; |
200 | 203 | ||
201 | /* XXX: must implement proper error handling in callers */ | 204 | priv = kmalloc(sizeof(*priv), GFP_KERNEL); |
202 | priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL); | 205 | if (!priv) |
206 | return -ENOMEM; | ||
203 | 207 | ||
204 | priv->tty = tty; | 208 | priv->tty = tty; |
205 | priv->file = file; | 209 | priv->file = file; |
@@ -208,6 +212,8 @@ void tty_add_file(struct tty_struct *tty, struct file *file) | |||
208 | spin_lock(&tty_files_lock); | 212 | spin_lock(&tty_files_lock); |
209 | list_add(&priv->list, &tty->tty_files); | 213 | list_add(&priv->list, &tty->tty_files); |
210 | spin_unlock(&tty_files_lock); | 214 | spin_unlock(&tty_files_lock); |
215 | |||
216 | return 0; | ||
211 | } | 217 | } |
212 | 218 | ||
213 | /* Delete file from its tty */ | 219 | /* Delete file from its tty */ |
@@ -1875,7 +1881,11 @@ got_driver: | |||
1875 | return PTR_ERR(tty); | 1881 | return PTR_ERR(tty); |
1876 | } | 1882 | } |
1877 | 1883 | ||
1878 | tty_add_file(tty, filp); | 1884 | retval = tty_add_file(tty, filp); |
1885 | if (retval) { | ||
1886 | tty_unlock(); | ||
1887 | return retval; | ||
1888 | } | ||
1879 | 1889 | ||
1880 | check_tty_count(tty, "tty_open"); | 1890 | check_tty_count(tty, "tty_open"); |
1881 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 1891 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
@@ -2502,6 +2512,20 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int | |||
2502 | return tty->ops->tiocmset(tty, file, set, clear); | 2512 | return tty->ops->tiocmset(tty, file, set, clear); |
2503 | } | 2513 | } |
2504 | 2514 | ||
2515 | static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) | ||
2516 | { | ||
2517 | int retval = -EINVAL; | ||
2518 | struct serial_icounter_struct icount; | ||
2519 | memset(&icount, 0, sizeof(icount)); | ||
2520 | if (tty->ops->get_icount) | ||
2521 | retval = tty->ops->get_icount(tty, &icount); | ||
2522 | if (retval != 0) | ||
2523 | return retval; | ||
2524 | if (copy_to_user(arg, &icount, sizeof(icount))) | ||
2525 | return -EFAULT; | ||
2526 | return 0; | ||
2527 | } | ||
2528 | |||
2505 | struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) | 2529 | struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) |
2506 | { | 2530 | { |
2507 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 2531 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
@@ -2622,6 +2646,12 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
2622 | case TIOCMBIC: | 2646 | case TIOCMBIC: |
2623 | case TIOCMBIS: | 2647 | case TIOCMBIS: |
2624 | return tty_tiocmset(tty, file, cmd, p); | 2648 | return tty_tiocmset(tty, file, cmd, p); |
2649 | case TIOCGICOUNT: | ||
2650 | retval = tty_tiocgicount(tty, p); | ||
2651 | /* For the moment allow fall through to the old method */ | ||
2652 | if (retval != -EINVAL) | ||
2653 | return retval; | ||
2654 | break; | ||
2625 | case TCFLSH: | 2655 | case TCFLSH: |
2626 | switch (arg) { | 2656 | switch (arg) { |
2627 | case TCIFLUSH: | 2657 | case TCIFLUSH: |
@@ -2783,6 +2813,20 @@ void do_SAK(struct tty_struct *tty) | |||
2783 | 2813 | ||
2784 | EXPORT_SYMBOL(do_SAK); | 2814 | EXPORT_SYMBOL(do_SAK); |
2785 | 2815 | ||
2816 | static int dev_match_devt(struct device *dev, void *data) | ||
2817 | { | ||
2818 | dev_t *devt = data; | ||
2819 | return dev->devt == *devt; | ||
2820 | } | ||
2821 | |||
2822 | /* Must put_device() after it's unused! */ | ||
2823 | static struct device *tty_get_device(struct tty_struct *tty) | ||
2824 | { | ||
2825 | dev_t devt = tty_devnum(tty); | ||
2826 | return class_find_device(tty_class, NULL, &devt, dev_match_devt); | ||
2827 | } | ||
2828 | |||
2829 | |||
2786 | /** | 2830 | /** |
2787 | * initialize_tty_struct | 2831 | * initialize_tty_struct |
2788 | * @tty: tty to initialize | 2832 | * @tty: tty to initialize |
@@ -2823,6 +2867,7 @@ void initialize_tty_struct(struct tty_struct *tty, | |||
2823 | tty->ops = driver->ops; | 2867 | tty->ops = driver->ops; |
2824 | tty->index = idx; | 2868 | tty->index = idx; |
2825 | tty_line_name(driver, idx, tty->name); | 2869 | tty_line_name(driver, idx, tty->name); |
2870 | tty->dev = tty_get_device(tty); | ||
2826 | } | 2871 | } |
2827 | 2872 | ||
2828 | /** | 2873 | /** |
@@ -2980,6 +3025,7 @@ int tty_register_driver(struct tty_driver *driver) | |||
2980 | int i; | 3025 | int i; |
2981 | dev_t dev; | 3026 | dev_t dev; |
2982 | void **p = NULL; | 3027 | void **p = NULL; |
3028 | struct device *d; | ||
2983 | 3029 | ||
2984 | if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { | 3030 | if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { |
2985 | p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL); | 3031 | p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL); |
@@ -3027,12 +3073,31 @@ int tty_register_driver(struct tty_driver *driver) | |||
3027 | mutex_unlock(&tty_mutex); | 3073 | mutex_unlock(&tty_mutex); |
3028 | 3074 | ||
3029 | if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) { | 3075 | if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) { |
3030 | for (i = 0; i < driver->num; i++) | 3076 | for (i = 0; i < driver->num; i++) { |
3031 | tty_register_device(driver, i, NULL); | 3077 | d = tty_register_device(driver, i, NULL); |
3078 | if (IS_ERR(d)) { | ||
3079 | error = PTR_ERR(d); | ||
3080 | goto err; | ||
3081 | } | ||
3082 | } | ||
3032 | } | 3083 | } |
3033 | proc_tty_register_driver(driver); | 3084 | proc_tty_register_driver(driver); |
3034 | driver->flags |= TTY_DRIVER_INSTALLED; | 3085 | driver->flags |= TTY_DRIVER_INSTALLED; |
3035 | return 0; | 3086 | return 0; |
3087 | |||
3088 | err: | ||
3089 | for (i--; i >= 0; i--) | ||
3090 | tty_unregister_device(driver, i); | ||
3091 | |||
3092 | mutex_lock(&tty_mutex); | ||
3093 | list_del(&driver->tty_drivers); | ||
3094 | mutex_unlock(&tty_mutex); | ||
3095 | |||
3096 | unregister_chrdev_region(dev, driver->num); | ||
3097 | driver->ttys = NULL; | ||
3098 | driver->termios = NULL; | ||
3099 | kfree(p); | ||
3100 | return error; | ||
3036 | } | 3101 | } |
3037 | 3102 | ||
3038 | EXPORT_SYMBOL(tty_register_driver); | 3103 | EXPORT_SYMBOL(tty_register_driver); |
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c new file mode 100644 index 000000000000..c40c1612c8a7 --- /dev/null +++ b/drivers/char/ttyprintk.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * linux/drivers/char/ttyprintk.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Samo Pogacnik | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the smems of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * This pseudo device allows user to make printk messages. It is possible | ||
13 | * to store "console" messages inline with kernel messages for better analyses | ||
14 | * of the boot process, for example. | ||
15 | */ | ||
16 | |||
17 | #include <linux/device.h> | ||
18 | #include <linux/serial.h> | ||
19 | #include <linux/tty.h> | ||
20 | |||
21 | struct ttyprintk_port { | ||
22 | struct tty_port port; | ||
23 | struct mutex port_write_mutex; | ||
24 | }; | ||
25 | |||
26 | static struct ttyprintk_port tpk_port; | ||
27 | |||
28 | /* | ||
29 | * Our simple preformatting supports transparent output of (time-stamped) | ||
30 | * printk messages (also suitable for logging service): | ||
31 | * - any cr is replaced by nl | ||
32 | * - adds a ttyprintk source tag in front of each line | ||
33 | * - too long message is fragmeted, with '\'nl between fragments | ||
34 | * - TPK_STR_SIZE isn't really the write_room limiting factor, bcause | ||
35 | * it is emptied on the fly during preformatting. | ||
36 | */ | ||
37 | #define TPK_STR_SIZE 508 /* should be bigger then max expected line length */ | ||
38 | #define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */ | ||
39 | static const char *tpk_tag = "[U] "; /* U for User */ | ||
40 | static int tpk_curr; | ||
41 | |||
42 | static int tpk_printk(const unsigned char *buf, int count) | ||
43 | { | ||
44 | static char tmp[TPK_STR_SIZE + 4]; | ||
45 | int i = tpk_curr; | ||
46 | |||
47 | if (buf == NULL) { | ||
48 | /* flush tmp[] */ | ||
49 | if (tpk_curr > 0) { | ||
50 | /* non nl or cr terminated message - add nl */ | ||
51 | tmp[tpk_curr + 0] = '\n'; | ||
52 | tmp[tpk_curr + 1] = '\0'; | ||
53 | printk(KERN_INFO "%s%s", tpk_tag, tmp); | ||
54 | tpk_curr = 0; | ||
55 | } | ||
56 | return i; | ||
57 | } | ||
58 | |||
59 | for (i = 0; i < count; i++) { | ||
60 | tmp[tpk_curr] = buf[i]; | ||
61 | if (tpk_curr < TPK_STR_SIZE) { | ||
62 | switch (buf[i]) { | ||
63 | case '\r': | ||
64 | /* replace cr with nl */ | ||
65 | tmp[tpk_curr + 0] = '\n'; | ||
66 | tmp[tpk_curr + 1] = '\0'; | ||
67 | printk(KERN_INFO "%s%s", tpk_tag, tmp); | ||
68 | tpk_curr = 0; | ||
69 | if (buf[i + 1] == '\n') | ||
70 | i++; | ||
71 | break; | ||
72 | case '\n': | ||
73 | tmp[tpk_curr + 1] = '\0'; | ||
74 | printk(KERN_INFO "%s%s", tpk_tag, tmp); | ||
75 | tpk_curr = 0; | ||
76 | break; | ||
77 | default: | ||
78 | tpk_curr++; | ||
79 | } | ||
80 | } else { | ||
81 | /* end of tmp buffer reached: cut the message in two */ | ||
82 | tmp[tpk_curr + 1] = '\\'; | ||
83 | tmp[tpk_curr + 2] = '\n'; | ||
84 | tmp[tpk_curr + 3] = '\0'; | ||
85 | printk(KERN_INFO "%s%s", tpk_tag, tmp); | ||
86 | tpk_curr = 0; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | return count; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * TTY operations open function. | ||
95 | */ | ||
96 | static int tpk_open(struct tty_struct *tty, struct file *filp) | ||
97 | { | ||
98 | tty->driver_data = &tpk_port; | ||
99 | |||
100 | return tty_port_open(&tpk_port.port, tty, filp); | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * TTY operations close function. | ||
105 | */ | ||
106 | static void tpk_close(struct tty_struct *tty, struct file *filp) | ||
107 | { | ||
108 | struct ttyprintk_port *tpkp = tty->driver_data; | ||
109 | |||
110 | mutex_lock(&tpkp->port_write_mutex); | ||
111 | /* flush tpk_printk buffer */ | ||
112 | tpk_printk(NULL, 0); | ||
113 | mutex_unlock(&tpkp->port_write_mutex); | ||
114 | |||
115 | tty_port_close(&tpkp->port, tty, filp); | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * TTY operations write function. | ||
120 | */ | ||
121 | static int tpk_write(struct tty_struct *tty, | ||
122 | const unsigned char *buf, int count) | ||
123 | { | ||
124 | struct ttyprintk_port *tpkp = tty->driver_data; | ||
125 | int ret; | ||
126 | |||
127 | |||
128 | /* exclusive use of tpk_printk within this tty */ | ||
129 | mutex_lock(&tpkp->port_write_mutex); | ||
130 | ret = tpk_printk(buf, count); | ||
131 | mutex_unlock(&tpkp->port_write_mutex); | ||
132 | |||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * TTY operations write_room function. | ||
138 | */ | ||
139 | static int tpk_write_room(struct tty_struct *tty) | ||
140 | { | ||
141 | return TPK_MAX_ROOM; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * TTY operations ioctl function. | ||
146 | */ | ||
147 | static int tpk_ioctl(struct tty_struct *tty, struct file *file, | ||
148 | unsigned int cmd, unsigned long arg) | ||
149 | { | ||
150 | struct ttyprintk_port *tpkp = tty->driver_data; | ||
151 | |||
152 | if (!tpkp) | ||
153 | return -EINVAL; | ||
154 | |||
155 | switch (cmd) { | ||
156 | /* Stop TIOCCONS */ | ||
157 | case TIOCCONS: | ||
158 | return -EOPNOTSUPP; | ||
159 | default: | ||
160 | return -ENOIOCTLCMD; | ||
161 | } | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static const struct tty_operations ttyprintk_ops = { | ||
166 | .open = tpk_open, | ||
167 | .close = tpk_close, | ||
168 | .write = tpk_write, | ||
169 | .write_room = tpk_write_room, | ||
170 | .ioctl = tpk_ioctl, | ||
171 | }; | ||
172 | |||
173 | struct tty_port_operations null_ops = { }; | ||
174 | |||
175 | static struct tty_driver *ttyprintk_driver; | ||
176 | |||
177 | static int __init ttyprintk_init(void) | ||
178 | { | ||
179 | int ret = -ENOMEM; | ||
180 | void *rp; | ||
181 | |||
182 | ttyprintk_driver = alloc_tty_driver(1); | ||
183 | if (!ttyprintk_driver) | ||
184 | return ret; | ||
185 | |||
186 | ttyprintk_driver->owner = THIS_MODULE; | ||
187 | ttyprintk_driver->driver_name = "ttyprintk"; | ||
188 | ttyprintk_driver->name = "ttyprintk"; | ||
189 | ttyprintk_driver->major = TTYAUX_MAJOR; | ||
190 | ttyprintk_driver->minor_start = 3; | ||
191 | ttyprintk_driver->num = 1; | ||
192 | ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE; | ||
193 | ttyprintk_driver->init_termios = tty_std_termios; | ||
194 | ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; | ||
195 | ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS | | ||
196 | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | ||
197 | tty_set_operations(ttyprintk_driver, &ttyprintk_ops); | ||
198 | |||
199 | ret = tty_register_driver(ttyprintk_driver); | ||
200 | if (ret < 0) { | ||
201 | printk(KERN_ERR "Couldn't register ttyprintk driver\n"); | ||
202 | goto error; | ||
203 | } | ||
204 | |||
205 | /* create our unnumbered device */ | ||
206 | rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL, | ||
207 | ttyprintk_driver->name); | ||
208 | if (IS_ERR(rp)) { | ||
209 | printk(KERN_ERR "Couldn't create ttyprintk device\n"); | ||
210 | ret = PTR_ERR(rp); | ||
211 | goto error; | ||
212 | } | ||
213 | |||
214 | tty_port_init(&tpk_port.port); | ||
215 | tpk_port.port.ops = &null_ops; | ||
216 | mutex_init(&tpk_port.port_write_mutex); | ||
217 | |||
218 | return 0; | ||
219 | |||
220 | error: | ||
221 | put_tty_driver(ttyprintk_driver); | ||
222 | ttyprintk_driver = NULL; | ||
223 | return ret; | ||
224 | } | ||
225 | module_init(ttyprintk_init); | ||
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index bcce46c96b88..273ab44cc91d 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c | |||
@@ -35,6 +35,12 @@ | |||
35 | #include <linux/console.h> | 35 | #include <linux/console.h> |
36 | #include <linux/device.h> | 36 | #include <linux/device.h> |
37 | #include <linux/smp_lock.h> | 37 | #include <linux/smp_lock.h> |
38 | #include <linux/sched.h> | ||
39 | #include <linux/fs.h> | ||
40 | #include <linux/poll.h> | ||
41 | #include <linux/signal.h> | ||
42 | #include <linux/slab.h> | ||
43 | #include <linux/notifier.h> | ||
38 | 44 | ||
39 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
40 | #include <asm/byteorder.h> | 46 | #include <asm/byteorder.h> |
@@ -45,6 +51,86 @@ | |||
45 | #undef addr | 51 | #undef addr |
46 | #define HEADER_SIZE 4 | 52 | #define HEADER_SIZE 4 |
47 | 53 | ||
54 | struct vcs_poll_data { | ||
55 | struct notifier_block notifier; | ||
56 | unsigned int cons_num; | ||
57 | bool seen_last_update; | ||
58 | wait_queue_head_t waitq; | ||
59 | struct fasync_struct *fasync; | ||
60 | }; | ||
61 | |||
62 | static int | ||
63 | vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param) | ||
64 | { | ||
65 | struct vt_notifier_param *param = _param; | ||
66 | struct vc_data *vc = param->vc; | ||
67 | struct vcs_poll_data *poll = | ||
68 | container_of(nb, struct vcs_poll_data, notifier); | ||
69 | int currcons = poll->cons_num; | ||
70 | |||
71 | if (code != VT_UPDATE) | ||
72 | return NOTIFY_DONE; | ||
73 | |||
74 | if (currcons == 0) | ||
75 | currcons = fg_console; | ||
76 | else | ||
77 | currcons--; | ||
78 | if (currcons != vc->vc_num) | ||
79 | return NOTIFY_DONE; | ||
80 | |||
81 | poll->seen_last_update = false; | ||
82 | wake_up_interruptible(&poll->waitq); | ||
83 | kill_fasync(&poll->fasync, SIGIO, POLL_IN); | ||
84 | return NOTIFY_OK; | ||
85 | } | ||
86 | |||
87 | static void | ||
88 | vcs_poll_data_free(struct vcs_poll_data *poll) | ||
89 | { | ||
90 | unregister_vt_notifier(&poll->notifier); | ||
91 | kfree(poll); | ||
92 | } | ||
93 | |||
94 | static struct vcs_poll_data * | ||
95 | vcs_poll_data_get(struct file *file) | ||
96 | { | ||
97 | struct vcs_poll_data *poll = file->private_data; | ||
98 | |||
99 | if (poll) | ||
100 | return poll; | ||
101 | |||
102 | poll = kzalloc(sizeof(*poll), GFP_KERNEL); | ||
103 | if (!poll) | ||
104 | return NULL; | ||
105 | poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127; | ||
106 | init_waitqueue_head(&poll->waitq); | ||
107 | poll->notifier.notifier_call = vcs_notifier; | ||
108 | if (register_vt_notifier(&poll->notifier) != 0) { | ||
109 | kfree(poll); | ||
110 | return NULL; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * This code may be called either through ->poll() or ->fasync(). | ||
115 | * If we have two threads using the same file descriptor, they could | ||
116 | * both enter this function, both notice that the structure hasn't | ||
117 | * been allocated yet and go ahead allocating it in parallel, but | ||
118 | * only one of them must survive and be shared otherwise we'd leak | ||
119 | * memory with a dangling notifier callback. | ||
120 | */ | ||
121 | spin_lock(&file->f_lock); | ||
122 | if (!file->private_data) { | ||
123 | file->private_data = poll; | ||
124 | } else { | ||
125 | /* someone else raced ahead of us */ | ||
126 | vcs_poll_data_free(poll); | ||
127 | poll = file->private_data; | ||
128 | } | ||
129 | spin_unlock(&file->f_lock); | ||
130 | |||
131 | return poll; | ||
132 | } | ||
133 | |||
48 | static int | 134 | static int |
49 | vcs_size(struct inode *inode) | 135 | vcs_size(struct inode *inode) |
50 | { | 136 | { |
@@ -102,6 +188,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
102 | struct inode *inode = file->f_path.dentry->d_inode; | 188 | struct inode *inode = file->f_path.dentry->d_inode; |
103 | unsigned int currcons = iminor(inode); | 189 | unsigned int currcons = iminor(inode); |
104 | struct vc_data *vc; | 190 | struct vc_data *vc; |
191 | struct vcs_poll_data *poll; | ||
105 | long pos; | 192 | long pos; |
106 | long viewed, attr, read; | 193 | long viewed, attr, read; |
107 | int col, maxcol; | 194 | int col, maxcol; |
@@ -134,6 +221,9 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
134 | ret = -EINVAL; | 221 | ret = -EINVAL; |
135 | if (pos < 0) | 222 | if (pos < 0) |
136 | goto unlock_out; | 223 | goto unlock_out; |
224 | poll = file->private_data; | ||
225 | if (count && poll) | ||
226 | poll->seen_last_update = true; | ||
137 | read = 0; | 227 | read = 0; |
138 | ret = 0; | 228 | ret = 0; |
139 | while (count) { | 229 | while (count) { |
@@ -448,6 +538,8 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
448 | } | 538 | } |
449 | *ppos += written; | 539 | *ppos += written; |
450 | ret = written; | 540 | ret = written; |
541 | if (written) | ||
542 | vcs_scr_updated(vc); | ||
451 | 543 | ||
452 | unlock_out: | 544 | unlock_out: |
453 | release_console_sem(); | 545 | release_console_sem(); |
@@ -457,6 +549,37 @@ unlock_out: | |||
457 | return ret; | 549 | return ret; |
458 | } | 550 | } |
459 | 551 | ||
552 | static unsigned int | ||
553 | vcs_poll(struct file *file, poll_table *wait) | ||
554 | { | ||
555 | struct vcs_poll_data *poll = vcs_poll_data_get(file); | ||
556 | int ret = 0; | ||
557 | |||
558 | if (poll) { | ||
559 | poll_wait(file, &poll->waitq, wait); | ||
560 | if (!poll->seen_last_update) | ||
561 | ret = POLLIN | POLLRDNORM; | ||
562 | } | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | static int | ||
567 | vcs_fasync(int fd, struct file *file, int on) | ||
568 | { | ||
569 | struct vcs_poll_data *poll = file->private_data; | ||
570 | |||
571 | if (!poll) { | ||
572 | /* don't allocate anything if all we want is disable fasync */ | ||
573 | if (!on) | ||
574 | return 0; | ||
575 | poll = vcs_poll_data_get(file); | ||
576 | if (!poll) | ||
577 | return -ENOMEM; | ||
578 | } | ||
579 | |||
580 | return fasync_helper(fd, file, on, &poll->fasync); | ||
581 | } | ||
582 | |||
460 | static int | 583 | static int |
461 | vcs_open(struct inode *inode, struct file *filp) | 584 | vcs_open(struct inode *inode, struct file *filp) |
462 | { | 585 | { |
@@ -470,11 +593,23 @@ vcs_open(struct inode *inode, struct file *filp) | |||
470 | return ret; | 593 | return ret; |
471 | } | 594 | } |
472 | 595 | ||
596 | static int vcs_release(struct inode *inode, struct file *file) | ||
597 | { | ||
598 | struct vcs_poll_data *poll = file->private_data; | ||
599 | |||
600 | if (poll) | ||
601 | vcs_poll_data_free(poll); | ||
602 | return 0; | ||
603 | } | ||
604 | |||
473 | static const struct file_operations vcs_fops = { | 605 | static const struct file_operations vcs_fops = { |
474 | .llseek = vcs_lseek, | 606 | .llseek = vcs_lseek, |
475 | .read = vcs_read, | 607 | .read = vcs_read, |
476 | .write = vcs_write, | 608 | .write = vcs_write, |
609 | .poll = vcs_poll, | ||
610 | .fasync = vcs_fasync, | ||
477 | .open = vcs_open, | 611 | .open = vcs_open, |
612 | .release = vcs_release, | ||
478 | }; | 613 | }; |
479 | 614 | ||
480 | static struct class *vc_class; | 615 | static struct class *vc_class; |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 281aada7b4a1..a8ec48ed14d9 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -4182,6 +4182,11 @@ void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org) | |||
4182 | } | 4182 | } |
4183 | } | 4183 | } |
4184 | 4184 | ||
4185 | void vcs_scr_updated(struct vc_data *vc) | ||
4186 | { | ||
4187 | notify_update(vc); | ||
4188 | } | ||
4189 | |||
4185 | /* | 4190 | /* |
4186 | * Visible symbols for modules | 4191 | * Visible symbols for modules |
4187 | */ | 4192 | */ |