diff --git a/[refs] b/[refs] index 9bb8bde464c3..e31290fb9df0 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 11a96d1820113fde0d55c3487b7da7a9031326b8 +refs/heads/master: 9f8305fe164077bcef42034c56275c8208042e88 diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index cc8093c15cf5..3d2d0c29f027 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -287,6 +287,14 @@ Who: Glauber Costa --------------------------- +What: old style serial driver for ColdFire (CONFIG_SERIAL_COLDFIRE) +When: 2.6.28 +Why: This driver still uses the old interface and has been replaced + by CONFIG_SERIAL_MCF. +Who: Sebastian Siewior + +--------------------------- + What: /sys/o2cb symlink When: January 2010 Why: /sys/fs/o2cb is the proper location for this information - /sys/o2cb diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 74b808205312..6ba3ee822838 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2797,6 +2797,15 @@ L: linux-mtd@lists.infradead.org T: git git://git.infradead.org/mtd-2.6.git S: Maintained +MEI MN10300/AM33 PORT +P: David Howells +M: dhowells@redhat.com +P: Koichi Yasutake +M: yasutake.koichi@jp.panasonic.com +L: linux-am33-list@redhat.com (moderated for non-subscribers) +W: ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/ +S: Maintained + MICROTEK X6 SCANNER P: Oliver Neukum M: oliver@neukum.name @@ -3161,15 +3170,6 @@ M: olof@lixom.net L: i2c@lm-sensors.org S: Maintained -PANASONIC MN10300/AM33 PORT -P: David Howells -M: dhowells@redhat.com -P: Koichi Yasutake -M: yasutake.koichi@jp.panasonic.com -L: linux-am33-list@redhat.com (moderated for non-subscribers) -W: ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/ -S: Maintained - PARALLEL PORT SUPPORT L: linux-parport@lists.infradead.org (subscribers-only) S: Orphan diff --git a/trunk/arch/blackfin/kernel/bfin_dma_5xx.c b/trunk/arch/blackfin/kernel/bfin_dma_5xx.c index 339293d677cc..93229b3d6e3e 100644 --- a/trunk/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/trunk/arch/blackfin/kernel/bfin_dma_5xx.c @@ -117,14 +117,15 @@ int request_dma(unsigned int channel, char *device_id) #ifdef CONFIG_BF54x if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) { - unsigned int per_map; - per_map = dma_ch[channel].regs->peripheral_map & 0xFFF; - if (strncmp(device_id, "BFIN_UART", 9) == 0) - dma_ch[channel].regs->peripheral_map = per_map | + if (strncmp(device_id, "BFIN_UART", 9) == 0) { + dma_ch[channel].regs->peripheral_map &= 0x0FFF; + dma_ch[channel].regs->peripheral_map |= ((channel - CH_UART2_RX + 0xC)<<12); - else - dma_ch[channel].regs->peripheral_map = per_map | + } else { + dma_ch[channel].regs->peripheral_map &= 0x0FFF; + dma_ch[channel].regs->peripheral_map |= ((channel - CH_UART2_RX + 0x6)<<12); + } } #endif diff --git a/trunk/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h index 75722d6008b0..2526b6ed6faa 100644 --- a/trunk/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h @@ -78,9 +78,6 @@ # define CONFIG_UART1_RTS_PIN -1 # endif #endif - -#define BFIN_UART_TX_FIFO_SIZE 2 - /* * The pin configuration is different from schematic */ @@ -122,6 +119,7 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) bfin_write16(uart->port.membase + OFFSET_LSR, -1); } +struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; struct bfin_serial_res { unsigned long uart_base_addr; int uart_irq; @@ -166,6 +164,8 @@ struct bfin_serial_res bfin_serial_resource[] = { #endif }; +int nr_ports = ARRAY_SIZE(bfin_serial_resource); + #define DRIVER_NAME "bfin-uart" static void bfin_serial_hw_init(struct bfin_serial_port *uart) diff --git a/trunk/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h index 815bfe5dd1a9..ebf592b59aab 100644 --- a/trunk/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h @@ -69,8 +69,6 @@ # endif #endif -#define BFIN_UART_TX_FIFO_SIZE 2 - struct bfin_serial_port { struct uart_port port; unsigned int old_status; @@ -113,6 +111,7 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) bfin_write16(uart->port.membase + OFFSET_LSR, -1); } +struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; struct bfin_serial_res { unsigned long uart_base_addr; int uart_irq; @@ -143,6 +142,7 @@ struct bfin_serial_res bfin_serial_resource[] = { #define DRIVER_NAME "bfin-uart" +int nr_ports = BFIN_UART_NR_PORTS; static void bfin_serial_hw_init(struct bfin_serial_port *uart) { diff --git a/trunk/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h index b3f87e1d16a2..1bf56ffa22f9 100644 --- a/trunk/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h @@ -78,9 +78,6 @@ # define CONFIG_UART1_RTS_PIN -1 # endif #endif - -#define BFIN_UART_TX_FIFO_SIZE 2 - /* * The pin configuration is different from schematic */ @@ -122,6 +119,7 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) bfin_write16(uart->port.membase + OFFSET_LSR, -1); } +struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; struct bfin_serial_res { unsigned long uart_base_addr; int uart_irq; @@ -166,6 +164,8 @@ struct bfin_serial_res bfin_serial_resource[] = { #endif }; +int nr_ports = ARRAY_SIZE(bfin_serial_resource); + #define DRIVER_NAME "bfin-uart" static void bfin_serial_hw_init(struct bfin_serial_port *uart) diff --git a/trunk/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h index e4cf35e7ab9f..5e29446a8e03 100644 --- a/trunk/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h @@ -82,9 +82,6 @@ # define CONFIG_UART1_RTS_PIN -1 # endif #endif - -#define BFIN_UART_TX_FIFO_SIZE 2 - /* * The pin configuration is different from schematic */ @@ -108,6 +105,7 @@ struct bfin_serial_port { #endif }; +struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; struct bfin_serial_res { unsigned long uart_base_addr; int uart_irq; @@ -172,6 +170,8 @@ struct bfin_serial_res bfin_serial_resource[] = { #endif }; +int nr_ports = ARRAY_SIZE(bfin_serial_resource); + #define DRIVER_NAME "bfin-uart" static void bfin_serial_hw_init(struct bfin_serial_port *uart) diff --git a/trunk/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h b/trunk/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h index e0ce0c1843d4..8aa02780e642 100644 --- a/trunk/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h +++ b/trunk/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h @@ -69,8 +69,6 @@ # endif #endif -#define BFIN_UART_TX_FIFO_SIZE 2 - struct bfin_serial_port { struct uart_port port; unsigned int old_status; @@ -113,6 +111,7 @@ static inline void UART_CLEAR_LSR(struct bfin_serial_port *uart) bfin_write16(uart->port.membase + OFFSET_LSR, -1); } +struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; struct bfin_serial_res { unsigned long uart_base_addr; int uart_irq; @@ -143,6 +142,7 @@ struct bfin_serial_res bfin_serial_resource[] = { #define DRIVER_NAME "bfin-uart" +int nr_ports = BFIN_UART_NR_PORTS; static void bfin_serial_hw_init(struct bfin_serial_port *uart) { diff --git a/trunk/arch/sparc/include/asm/serial.h b/trunk/arch/sparc/include/asm/serial.h deleted file mode 100644 index f90d61c28059..000000000000 --- a/trunk/arch/sparc/include/asm/serial.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __SPARC_SERIAL_H -#define __SPARC_SERIAL_H - -#define BASE_BAUD ( 1843200 / 16 ) - -#endif /* __SPARC_SERIAL_H */ diff --git a/trunk/arch/um/drivers/line.c b/trunk/arch/um/drivers/line.c index 14a102e877d6..d741f35d7b3a 100644 --- a/trunk/arch/um/drivers/line.c +++ b/trunk/arch/um/drivers/line.c @@ -275,8 +275,6 @@ int line_ioctl(struct tty_struct *tty, struct file * file, case TIOCGLTC: case TIOCSLTC: #endif - /* Note: these are out of date as we now have TCGETS2 etc but this - whole lot should probably go away */ case TCGETS: case TCSETSF: case TCSETSW: diff --git a/trunk/drivers/bluetooth/hci_ldisc.c b/trunk/drivers/bluetooth/hci_ldisc.c index 4426bb552bd9..8dfcf77cb717 100644 --- a/trunk/drivers/bluetooth/hci_ldisc.c +++ b/trunk/drivers/bluetooth/hci_ldisc.c @@ -484,7 +484,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, return -EUNATCH; default: - err = n_tty_ioctl_helper(tty, file, cmd, arg); + err = n_tty_ioctl(tty, file, cmd, arg); break; }; diff --git a/trunk/drivers/char/Kconfig b/trunk/drivers/char/Kconfig index 700ff9679457..caff85149b9d 100644 --- a/trunk/drivers/char/Kconfig +++ b/trunk/drivers/char/Kconfig @@ -350,7 +350,7 @@ config STALDRV config STALLION tristate "Stallion EasyIO or EC8/32 support" - depends on STALDRV && (ISA || EISA || PCI) + depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) help If you have an EasyIO or EasyConnection 8/32 multiport Stallion card, then this is for you; say Y. Make sure to read @@ -361,7 +361,7 @@ config STALLION config ISTALLION tristate "Stallion EC8/64, ONboard, Brumby support" - depends on STALDRV && (ISA || EISA || PCI) + depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) help If you have an EasyConnection 8/64, ONboard, Brumby or Stallion serial multiport card, say Y here. Make sure to read diff --git a/trunk/drivers/char/Makefile b/trunk/drivers/char/Makefile index 1a4247dccac4..6850f6da7576 100644 --- a/trunk/drivers/char/Makefile +++ b/trunk/drivers/char/Makefile @@ -7,7 +7,7 @@ # FONTMAPFILE = cp437.uni -obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o +obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o obj-$(CONFIG_LEGACY_PTYS) += pty.o obj-$(CONFIG_UNIX98_PTYS) += pty.o diff --git a/trunk/drivers/char/amiserial.c b/trunk/drivers/char/amiserial.c index 98821f97583c..6e763e3f5a81 100644 --- a/trunk/drivers/char/amiserial.c +++ b/trunk/drivers/char/amiserial.c @@ -837,6 +837,9 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) struct async_struct *info; unsigned long flags; + if (!tty) + return 0; + info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_put_char")) @@ -889,6 +892,9 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count struct async_struct *info; unsigned long flags; + if (!tty) + return 0; + info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_write")) diff --git a/trunk/drivers/char/applicom.c b/trunk/drivers/char/applicom.c index b899d9182c7d..31d08b641f5b 100644 --- a/trunk/drivers/char/applicom.c +++ b/trunk/drivers/char/applicom.c @@ -712,7 +712,8 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un IndexCard = adgl->num_card-1; - if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { + if(cmd != 0 && cmd != 6 && + ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { static int warncount = 10; if (warncount) { printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1); @@ -831,7 +832,8 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un } break; default: - ret = -ENOTTY; + printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ; + ret = -EINVAL; break; } Dummy = readb(apbs[IndexCard].RamIO + VERS); diff --git a/trunk/drivers/char/cyclades.c b/trunk/drivers/char/cyclades.c index 5e5b1dc1a0a7..fe6d774fe2e4 100644 --- a/trunk/drivers/char/cyclades.c +++ b/trunk/drivers/char/cyclades.c @@ -4993,14 +4993,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { card_name = "Cyclom-Y"; - addr0 = ioremap_nocache(pci_resource_start(pdev, 0), - CyPCI_Yctl); + addr0 = pci_iomap(pdev, 0, CyPCI_Yctl); if (addr0 == NULL) { dev_err(&pdev->dev, "can't remap ctl region\n"); goto err_reg; } - addr2 = ioremap_nocache(pci_resource_start(pdev, 2), - CyPCI_Ywin); + addr2 = pci_iomap(pdev, 2, CyPCI_Ywin); if (addr2 == NULL) { dev_err(&pdev->dev, "can't remap base region\n"); goto err_unmap; @@ -5015,8 +5013,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { struct RUNTIME_9060 __iomem *ctl_addr; - ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0), - CyPCI_Zctl); + ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl); if (addr0 == NULL) { dev_err(&pdev->dev, "can't remap ctl region\n"); goto err_reg; @@ -5029,8 +5026,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, mailbox = (u32)readl(&ctl_addr->mail_box_0); - addr2 = ioremap_nocache(pci_resource_start(pdev, 2), - mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin); + addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ? + CyPCI_Ze_win : CyPCI_Zwin); if (addr2 == NULL) { dev_err(&pdev->dev, "can't remap base region\n"); goto err_unmap; @@ -5162,9 +5159,9 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, cy_card[card_no].base_addr = NULL; free_irq(irq, &cy_card[card_no]); err_unmap: - iounmap(addr0); + pci_iounmap(pdev, addr0); if (addr2) - iounmap(addr2); + pci_iounmap(pdev, addr2); err_reg: pci_release_regions(pdev); err_dis: @@ -5189,9 +5186,9 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev) cy_writew(cinfo->ctl_addr + 0x68, readw(cinfo->ctl_addr + 0x68) & ~0x0900); - iounmap(cinfo->base_addr); + pci_iounmap(pdev, cinfo->base_addr); if (cinfo->ctl_addr) - iounmap(cinfo->ctl_addr); + pci_iounmap(pdev, cinfo->ctl_addr); if (cinfo->irq #ifndef CONFIG_CYZ_INTR && !IS_CYC_Z(*cinfo) diff --git a/trunk/drivers/char/epca.c b/trunk/drivers/char/epca.c index 4998b2761e8f..456e4ede049f 100644 --- a/trunk/drivers/char/epca.c +++ b/trunk/drivers/char/epca.c @@ -1376,7 +1376,6 @@ static void post_fep_init(unsigned int crd) unsigned long flags; u16 tseg, rseg; - tty_port_init(&ch->port); ch->brdchan = bc; ch->mailbox = gd; INIT_WORK(&ch->tqueue, do_softint); @@ -1511,6 +1510,10 @@ static void post_fep_init(unsigned int crd) ch->fepstopca = 0; ch->close_delay = 50; + ch->port.count = 0; + ch->port.blocked_open = 0; + init_waitqueue_head(&ch->port.open_wait); + init_waitqueue_head(&ch->port.close_wait); spin_unlock_irqrestore(&epca_lock, flags); } diff --git a/trunk/drivers/char/generic_serial.c b/trunk/drivers/char/generic_serial.c index c6090f84a2e4..19d3afb0e50c 100644 --- a/trunk/drivers/char/generic_serial.c +++ b/trunk/drivers/char/generic_serial.c @@ -54,6 +54,8 @@ int gs_put_char(struct tty_struct * tty, unsigned char ch) func_enter (); + if (!tty) return 0; + port = tty->driver_data; if (!port) return 0; @@ -95,6 +97,8 @@ int gs_write(struct tty_struct * tty, func_enter (); + if (!tty) return 0; + port = tty->driver_data; if (!port) return 0; @@ -181,6 +185,7 @@ static int gs_real_chars_in_buffer(struct tty_struct *tty) struct gs_port *port; func_enter (); + if (!tty) return 0; port = tty->driver_data; if (!port->rd) return 0; @@ -269,6 +274,8 @@ void gs_flush_buffer(struct tty_struct *tty) func_enter (); + if (!tty) return; + port = tty->driver_data; if (!port) return; @@ -289,6 +296,8 @@ void gs_flush_chars(struct tty_struct * tty) func_enter (); + if (!tty) return; + port = tty->driver_data; if (!port) return; @@ -312,6 +321,8 @@ void gs_stop(struct tty_struct * tty) func_enter (); + if (!tty) return; + port = tty->driver_data; if (!port) return; @@ -330,6 +341,8 @@ void gs_start(struct tty_struct * tty) { struct gs_port *port; + if (!tty) return; + port = tty->driver_data; if (!port) return; @@ -380,6 +393,8 @@ void gs_hangup(struct tty_struct *tty) func_enter (); + if (!tty) return; + port = tty->driver_data; tty = port->port.tty; if (!tty) @@ -411,6 +426,8 @@ int gs_block_til_ready(void *port_, struct file * filp) tty = port->port.tty; + if (!tty) return 0; + gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); /* * If the device is in the middle of being closed, then block @@ -506,6 +523,8 @@ void gs_close(struct tty_struct * tty, struct file * filp) func_enter (); + if (!tty) return; + port = (struct gs_port *) tty->driver_data; if (!port) return; @@ -602,6 +621,8 @@ void gs_set_termios (struct tty_struct * tty, func_enter(); + if (!tty) return; + port = tty->driver_data; if (!port) return; diff --git a/trunk/drivers/char/hvc_console.c b/trunk/drivers/char/hvc_console.c index ec7aded0a2df..fd64137b1ab9 100644 --- a/trunk/drivers/char/hvc_console.c +++ b/trunk/drivers/char/hvc_console.c @@ -819,11 +819,11 @@ static int hvc_init(void) hvc_driver = drv; return 0; +put_tty: + put_tty_driver(hvc_driver); stop_thread: kthread_stop(hvc_task); hvc_task = NULL; -put_tty: - put_tty_driver(drv); out: return err; } diff --git a/trunk/drivers/char/ip2/Makefile b/trunk/drivers/char/ip2/Makefile index bc397d92b499..939618f62fe1 100644 --- a/trunk/drivers/char/ip2/Makefile +++ b/trunk/drivers/char/ip2/Makefile @@ -4,5 +4,5 @@ obj-$(CONFIG_COMPUTONE) += ip2.o -ip2-objs := ip2main.o +ip2-objs := ip2base.o ip2main.o diff --git a/trunk/drivers/char/ip2/i2ellis.c b/trunk/drivers/char/ip2/i2ellis.c index 29db44de399f..3601017f58cf 100644 --- a/trunk/drivers/char/ip2/i2ellis.c +++ b/trunk/drivers/char/ip2/i2ellis.c @@ -68,6 +68,38 @@ static DEFINE_RWLOCK(Dl_spinlock); // iiInitialize //======================================================= +//****************************************************************************** +// Function: iiEllisInit() +// Parameters: None +// +// Returns: Nothing +// +// Description: +// +// This routine performs any required initialization of the iiEllis subsystem. +// +//****************************************************************************** +static void +iiEllisInit(void) +{ +} + +//****************************************************************************** +// Function: iiEllisCleanup() +// Parameters: None +// +// Returns: Nothing +// +// Description: +// +// This routine performs any required cleanup of the iiEllis subsystem. +// +//****************************************************************************** +static void +iiEllisCleanup(void) +{ +} + //****************************************************************************** // Function: iiSetAddress(pB, address, delay) // Parameters: pB - pointer to the board structure diff --git a/trunk/drivers/char/ip2/i2ellis.h b/trunk/drivers/char/ip2/i2ellis.h index fb6df2456018..c88a64e527aa 100644 --- a/trunk/drivers/char/ip2/i2ellis.h +++ b/trunk/drivers/char/ip2/i2ellis.h @@ -511,6 +511,7 @@ typedef void (*delayFunc_t)(unsigned int); // // Initialization of a board & structure is in four (five!) parts: // +// 0) iiEllisInit() - Initialize iiEllis subsystem. // 1) iiSetAddress() - Define the board address & delay function for a board. // 2) iiReset() - Reset the board (provided it exists) // -- Note you may do this to several boards -- @@ -522,6 +523,7 @@ typedef void (*delayFunc_t)(unsigned int); // loadware. To change loadware, you must begin again with step 2, resetting // the board again (step 1 not needed). +static void iiEllisInit(void); static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t ); static int iiReset(i2eBordStrPtr); static int iiResetDelay(i2eBordStrPtr); diff --git a/trunk/drivers/char/ip2/ip2base.c b/trunk/drivers/char/ip2/ip2base.c new file mode 100644 index 000000000000..8155e247c04b --- /dev/null +++ b/trunk/drivers/char/ip2/ip2base.c @@ -0,0 +1,108 @@ +// ip2.c +// This is a dummy module to make the firmware available when needed +// and allows it to be unloaded when not. Rumor is the __initdata +// macro doesn't always works on all platforms so we use this kludge. +// If not compiled as a module it just makes fip_firm avaliable then +// __initdata should work as advertized +// + +#include +#include +#include + +#ifndef __init +#define __init +#endif +#ifndef __initfunc +#define __initfunc(a) a +#endif +#ifndef __initdata +#define __initdata +#endif + +#include "ip2types.h" + +int +ip2_loadmain(int *, int *); // ref into ip2main.c + +/* Note: Add compiled in defaults to these arrays, not to the structure + in ip2.h any longer. That structure WILL get overridden + by these values, or command line values, or insmod values!!! =mhw= +*/ +static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 }; +static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; + +static int poll_only = 0; + +MODULE_AUTHOR("Doug McNash"); +MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); +module_param_array(irq, int, NULL, 0); +MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards"); +module_param_array(io, int, NULL, 0); +MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards"); +module_param(poll_only, bool, 0); +MODULE_PARM_DESC(poll_only,"Do not use card interrupts"); + + +static int __init ip2_init(void) +{ + if( poll_only ) { + /* Hard lock the interrupts to zero */ + irq[0] = irq[1] = irq[2] = irq[3] = 0; + } + + return ip2_loadmain(io, irq); +} +module_init(ip2_init); + +MODULE_LICENSE("GPL"); + +#ifndef MODULE +/****************************************************************************** + * ip2_setup: + * str: kernel command line string + * + * Can't autoprobe the boards so user must specify configuration on + * kernel command line. Sane people build it modular but the others + * come here. + * + * Alternating pairs of io,irq for up to 4 boards. + * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3 + * + * io=0 => No board + * io=1 => PCI + * io=2 => EISA + * else => ISA I/O address + * + * irq=0 or invalid for ISA will revert to polling mode + * + * Any value = -1, do not overwrite compiled in value. + * + ******************************************************************************/ +static int __init ip2_setup(char *str) +{ + int ints[10]; /* 4 boards, 2 parameters + 2 */ + int i, j; + + str = get_options (str, ARRAY_SIZE(ints), ints); + + for( i = 0, j = 1; i < 4; i++ ) { + if( j > ints[0] ) { + break; + } + if( ints[j] >= 0 ) { + io[i] = ints[j]; + } + j++; + if( j > ints[0] ) { + break; + } + if( ints[j] >= 0 ) { + irq[i] = ints[j]; + } + j++; + } + return 1; +} +__setup("ip2=", ip2_setup); +#endif /* !MODULE */ diff --git a/trunk/drivers/char/ip2/ip2main.c b/trunk/drivers/char/ip2/ip2main.c index 6774572d3759..689f9dcd3b86 100644 --- a/trunk/drivers/char/ip2/ip2main.c +++ b/trunk/drivers/char/ip2/ip2main.c @@ -150,12 +150,15 @@ static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /*************/ /* String constants to identify ourselves */ -static const char pcName[] = "Computone IntelliPort Plus multiport driver"; -static const char pcVersion[] = "1.2.14"; +static char *pcName = "Computone IntelliPort Plus multiport driver"; +static char *pcVersion = "1.2.14"; /* String constants for port names */ -static const char pcDriver_name[] = "ip2"; -static const char pcIpl[] = "ip2ipl"; +static char *pcDriver_name = "ip2"; +static char *pcIpl = "ip2ipl"; + +// cheezy kludge or genius - you decide? +int ip2_loadmain(int *, int *); /***********************/ /* Function Prototypes */ @@ -237,8 +240,8 @@ static const struct file_operations ip2_ipl = { .open = ip2_ipl_open, }; -static unsigned long irq_counter; -static unsigned long bh_counter; +static unsigned long irq_counter = 0; +static unsigned long bh_counter = 0; // Use immediate queue to service interrupts #define USE_IQI @@ -249,6 +252,7 @@ static unsigned long bh_counter; */ #define POLL_TIMEOUT (jiffies + 1) static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0); +static char TimerOn; #ifdef IP2DEBUG_TRACE /* Trace (debug) buffer data */ @@ -264,8 +268,8 @@ static int tracewrap; /**********/ #if defined(MODULE) && defined(IP2DEBUG_OPEN) -#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \ - tty->name,(pCh->flags), \ +#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \ + tty->name,(pCh->flags),ip2_tty_driver->refcount, \ tty->count,/*GET_USE_COUNT(module)*/0,s) #else #define DBG_CNT(s) @@ -283,9 +287,8 @@ static int tracewrap; MODULE_AUTHOR("Doug McNash"); MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); -MODULE_LICENSE("GPL"); -static int poll_only; +static int poll_only = 0; static int Eisa_irq; static int Eisa_slot; @@ -294,46 +297,34 @@ static int iindx; static char rirqs[IP2_MAX_BOARDS]; static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; -/* Note: Add compiled in defaults to these arrays, not to the structure - in ip2.h any longer. That structure WILL get overridden - by these values, or command line values, or insmod values!!! =mhw= -*/ -static int io[IP2_MAX_BOARDS]; -static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; - -MODULE_AUTHOR("Doug McNash"); -MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); -module_param_array(irq, int, NULL, 0); -MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards"); -module_param_array(io, int, NULL, 0); -MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards"); -module_param(poll_only, bool, 0); -MODULE_PARM_DESC(poll_only, "Do not use card interrupts"); - /* for sysfs class support */ static struct class *ip2_class; -/* Some functions to keep track of what irqs we have */ +// Some functions to keep track of what irq's we have -static int __init is_valid_irq(int irq) +static int +is_valid_irq(int irq) { int *i = Valid_Irqs; - while (*i != 0 && *i != irq) + while ((*i != 0) && (*i != irq)) { i++; - - return *i; + } + return (*i); } -static void __init mark_requested_irq(char irq) +static void +mark_requested_irq( char irq ) { rirqs[iindx++] = irq; } -static int __exit clear_requested_irq(char irq) +#ifdef MODULE +static int +clear_requested_irq( char irq ) { int i; - for (i = 0; i < IP2_MAX_BOARDS; ++i) { + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { if (rirqs[i] == irq) { rirqs[i] = 0; return 1; @@ -341,15 +332,17 @@ static int __exit clear_requested_irq(char irq) } return 0; } +#endif -static int have_requested_irq(char irq) +static int +have_requested_irq( char irq ) { - /* array init to zeros so 0 irq will not be requested as a side - * effect */ + // array init to zeros so 0 irq will not be requested as a side effect int i; - for (i = 0; i < IP2_MAX_BOARDS; ++i) + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { if (rirqs[i] == irq) return 1; + } return 0; } @@ -368,45 +361,53 @@ static int have_requested_irq(char irq) /* handle subsequent installations of the driver. All memory allocated by the */ /* driver should be returned since it may be unloaded from memory. */ /******************************************************************************/ -static void __exit ip2_cleanup_module(void) +#ifdef MODULE +void __exit +ip2_cleanup_module(void) { int err; int i; - del_timer_sync(&PollTimer); +#ifdef IP2DEBUG_INIT + printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion ); +#endif + /* Stop poll timer if we had one. */ + if ( TimerOn ) { + del_timer ( &PollTimer ); + TimerOn = 0; + } /* Reset the boards we have. */ - for (i = 0; i < IP2_MAX_BOARDS; i++) - if (i2BoardPtrTable[i]) - iiReset(i2BoardPtrTable[i]); + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( i2BoardPtrTable[i] ) { + iiReset( i2BoardPtrTable[i] ); + } + } /* The following is done at most once, if any boards were installed. */ - for (i = 0; i < IP2_MAX_BOARDS; i++) { - if (i2BoardPtrTable[i]) { - iiResetDelay(i2BoardPtrTable[i]); + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( i2BoardPtrTable[i] ) { + iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ - release_region(ip2config.addr[i], 8); + release_region( ip2config.addr[i], 8 ); device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); - device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, - 4 * i + 1)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); } /* Disable and remove interrupt handler. */ - if (ip2config.irq[i] > 0 && - have_requested_irq(ip2config.irq[i])) { - free_irq(ip2config.irq[i], (void *)&pcName); - clear_requested_irq(ip2config.irq[i]); + if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { + free_irq ( ip2config.irq[i], (void *)&pcName); + clear_requested_irq( ip2config.irq[i]); } } class_destroy(ip2_class); - err = tty_unregister_driver(ip2_tty_driver); - if (err) - printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", - err); + if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { + printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); + } put_tty_driver(ip2_tty_driver); unregister_chrdev(IP2_IPL_MAJOR, pcIpl); remove_proc_entry("ip2mem", NULL); - /* free memory */ + // free memory for (i = 0; i < IP2_MAX_BOARDS; i++) { void *pB; #ifdef CONFIG_PCI @@ -416,18 +417,24 @@ static void __exit ip2_cleanup_module(void) ip2config.pci_dev[i] = NULL; } #endif - pB = i2BoardPtrTable[i]; - if (pB != NULL) { - kfree(pB); + if ((pB = i2BoardPtrTable[i]) != 0 ) { + kfree ( pB ); i2BoardPtrTable[i] = NULL; } - if (DevTableMem[i] != NULL) { - kfree(DevTableMem[i]); + if ((DevTableMem[i]) != NULL ) { + kfree ( DevTableMem[i] ); DevTableMem[i] = NULL; } } + + /* Cleanup the iiEllis subsystem. */ + iiEllisCleanup(); +#ifdef IP2DEBUG_INIT + printk (KERN_DEBUG "IP2 Unloaded\n" ); +#endif } module_exit(ip2_cleanup_module); +#endif /* MODULE */ static const struct tty_operations ip2_ops = { .open = ip2_open, @@ -487,168 +494,139 @@ static const struct firmware *ip2_request_firmware(void) return fw; } -#ifndef MODULE -/****************************************************************************** - * ip2_setup: - * str: kernel command line string - * - * Can't autoprobe the boards so user must specify configuration on - * kernel command line. Sane people build it modular but the others - * come here. - * - * Alternating pairs of io,irq for up to 4 boards. - * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3 - * - * io=0 => No board - * io=1 => PCI - * io=2 => EISA - * else => ISA I/O address - * - * irq=0 or invalid for ISA will revert to polling mode - * - * Any value = -1, do not overwrite compiled in value. - * - ******************************************************************************/ -static int __init ip2_setup(char *str) -{ - int j, ints[10]; /* 4 boards, 2 parameters + 2 */ - unsigned int i; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - for (i = 0, j = 1; i < 4; i++) { - if (j > ints[0]) - break; - if (ints[j] >= 0) - io[i] = ints[j]; - j++; - if (j > ints[0]) - break; - if (ints[j] >= 0) - irq[i] = ints[j]; - j++; - } - return 1; -} -__setup("ip2=", ip2_setup); -#endif /* !MODULE */ - -static int __init ip2_loadmain(void) +int +ip2_loadmain(int *iop, int *irqp) { int i, j, box; int err = 0; + static int loaded; i2eBordStrPtr pB = NULL; int rc = -1; - struct pci_dev *pdev = NULL; + static struct pci_dev *pci_dev_i = NULL; const struct firmware *fw = NULL; - if (poll_only) { - /* Hard lock the interrupts to zero */ - irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0; - } - - ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0); + ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 ); /* process command line arguments to modprobe or insmod i.e. iop & irqp */ /* irqp and iop should ALWAYS be specified now... But we check them individually just to be sure, anyways... */ - for (i = 0; i < IP2_MAX_BOARDS; ++i) { - ip2config.addr[i] = io[i]; - if (irq[i] >= 0) - ip2config.irq[i] = irq[i]; - else - ip2config.irq[i] = 0; - /* This is a little bit of a hack. If poll_only=1 on command - line back in ip2.c OR all IRQs on all specified boards are - explicitly set to 0, then drop to poll only mode and override - PCI or EISA interrupts. This superceeds the old hack of - triggering if all interrupts were zero (like da default). - Still a hack but less prone to random acts of terrorism. - - What we really should do, now that the IRQ default is set - to -1, is to use 0 as a hard coded, do not probe. - - /\/\|=mhw=|\/\/ - */ - poll_only |= irq[i]; + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if (iop) { + ip2config.addr[i] = iop[i]; + if (irqp) { + if( irqp[i] >= 0 ) { + ip2config.irq[i] = irqp[i]; + } else { + ip2config.irq[i] = 0; + } + // This is a little bit of a hack. If poll_only=1 on command + // line back in ip2.c OR all IRQs on all specified boards are + // explicitly set to 0, then drop to poll only mode and override + // PCI or EISA interrupts. This superceeds the old hack of + // triggering if all interrupts were zero (like da default). + // Still a hack but less prone to random acts of terrorism. + // + // What we really should do, now that the IRQ default is set + // to -1, is to use 0 as a hard coded, do not probe. + // + // /\/\|=mhw=|\/\/ + poll_only |= irqp[i]; + } + } } poll_only = !poll_only; /* Announce our presence */ - printk(KERN_INFO "%s version %s\n", pcName, pcVersion); + printk( KERN_INFO "%s version %s\n", pcName, pcVersion ); + + // ip2 can be unloaded and reloaded for no good reason + // we can't let that happen here or bad things happen + // second load hoses board but not system - fixme later + if (loaded) { + printk( KERN_INFO "Still loaded\n" ); + return 0; + } + loaded++; ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS); if (!ip2_tty_driver) return -ENOMEM; + /* Initialise the iiEllis subsystem. */ + iiEllisInit(); + + /* Initialize arrays. */ + memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable ); + memset( DevTable, 0, sizeof DevTable ); + /* Initialise all the boards we can find (up to the maximum). */ - for (i = 0; i < IP2_MAX_BOARDS; ++i) { - switch (ip2config.addr[i]) { + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + switch ( ip2config.addr[i] ) { case 0: /* skip this slot even if card is present */ break; default: /* ISA */ /* ISA address must be specified */ - if (ip2config.addr[i] < 0x100 || - ip2config.addr[i] > 0x3f8) { - printk(KERN_ERR "IP2: Bad ISA board %d " - "address %x\n", i, - ip2config.addr[i]); + if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) { + printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n", + i, ip2config.addr[i] ); ip2config.addr[i] = 0; - break; - } - ip2config.type[i] = ISA; - - /* Check for valid irq argument, set for polling if - * invalid */ - if (ip2config.irq[i] && - !is_valid_irq(ip2config.irq[i])) { - printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n", - ip2config.irq[i]); - /* 0 is polling and is valid in that sense */ - ip2config.irq[i] = 0; + } else { + ip2config.type[i] = ISA; + + /* Check for valid irq argument, set for polling if invalid */ + if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) { + printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]); + ip2config.irq[i] = 0;// 0 is polling and is valid in that sense + } } break; case PCI: #ifdef CONFIG_PCI - { - u32 addr; - int status; + { + int status; - pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE, - PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev); - if (pdev == NULL) { - ip2config.addr[i] = 0; - printk(KERN_ERR "IP2: PCI board %d not " - "found\n", i); - break; - } + pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE, + PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); + if (pci_dev_i != NULL) { + unsigned int addr; - if (pci_enable_device(pdev)) { - dev_err(&pdev->dev, "can't enable device\n"); - break; + if (pci_enable_device(pci_dev_i)) { + printk( KERN_ERR "IP2: can't enable PCI device at %s\n", + pci_name(pci_dev_i)); + break; + } + ip2config.type[i] = PCI; + ip2config.pci_dev[i] = pci_dev_get(pci_dev_i); + status = + pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr); + if ( addr & 1 ) { + ip2config.addr[i]=(USHORT)(addr&0xfffe); + } else { + printk( KERN_ERR "IP2: PCI I/O address error\n"); + } + +// If the PCI BIOS assigned it, lets try and use it. If we +// can't acquire it or it screws up, deal with it then. + +// if (!is_valid_irq(pci_irq)) { +// printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq); +// pci_irq = 0; +// } + ip2config.irq[i] = pci_dev_i->irq; + } else { // ann error + ip2config.addr[i] = 0; + printk(KERN_ERR "IP2: PCI board %d not found\n", i); + } } - ip2config.type[i] = PCI; - ip2config.pci_dev[i] = pci_dev_get(pdev); - status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, - &addr); - if (addr & 1) - ip2config.addr[i] = (USHORT)(addr & 0xfffe); - else - dev_err(&pdev->dev, "I/O address error\n"); - - ip2config.irq[i] = pdev->irq; - } #else - printk(KERN_ERR "IP2: PCI card specified but PCI " - "support not enabled.\n"); - printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI " - "defined!\n"); + printk( KERN_ERR "IP2: PCI card specified but PCI support not\n"); + printk( KERN_ERR "IP2: configured in this kernel.\n"); + printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n"); #endif /* CONFIG_PCI */ break; case EISA: - ip2config.addr[i] = find_eisa_board(Eisa_slot + 1); - if (ip2config.addr[i] != 0) { + if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) { /* Eisa_irq set as side effect, boo */ ip2config.type[i] = EISA; } @@ -656,32 +634,31 @@ static int __init ip2_loadmain(void) break; } /* switch */ } /* for */ - pci_dev_put(pdev); + if (pci_dev_i) + pci_dev_put(pci_dev_i); - for (i = 0; i < IP2_MAX_BOARDS; ++i) { - if (ip2config.addr[i]) { + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( ip2config.addr[i] ) { pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL); if (pB) { i2BoardPtrTable[i] = pB; - iiSetAddress(pB, ip2config.addr[i], - ii2DelayTimer); - iiReset(pB); - } else - printk(KERN_ERR "IP2: board memory allocation " - "error\n"); + iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer ); + iiReset( pB ); + } else { + printk(KERN_ERR "IP2: board memory allocation error\n"); + } } } - for (i = 0; i < IP2_MAX_BOARDS; ++i) { - pB = i2BoardPtrTable[i]; - if (pB != NULL) { - iiResetDelay(pB); + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( ( pB = i2BoardPtrTable[i] ) != NULL ) { + iiResetDelay( pB ); break; } } - for (i = 0; i < IP2_MAX_BOARDS; ++i) { + for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { /* We don't want to request the firmware unless we have at least one board */ - if (i2BoardPtrTable[i] != NULL) { + if ( i2BoardPtrTable[i] != NULL ) { if (!fw) fw = ip2_request_firmware(); if (!fw) @@ -692,7 +669,7 @@ static int __init ip2_loadmain(void) if (fw) release_firmware(fw); - ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0); + ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 ); ip2_tty_driver->owner = THIS_MODULE; ip2_tty_driver->name = "ttyF"; @@ -703,23 +680,20 @@ static int __init ip2_loadmain(void) ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL; ip2_tty_driver->init_termios = tty_std_termios; ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; - ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV; + ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(ip2_tty_driver, &ip2_ops); - ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0); + ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 ); - err = tty_register_driver(ip2_tty_driver); - if (err) { - printk(KERN_ERR "IP2: failed to register tty driver\n"); + /* Register the tty devices. */ + if ( ( err = tty_register_driver ( ip2_tty_driver ) ) ) { + printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err); put_tty_driver(ip2_tty_driver); - return err; /* leaking resources */ - } - - err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl); - if (err) { - printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", - err); + return -EINVAL; + } else + /* Register the IPL driver. */ + if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) { + printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err ); } else { /* create the sysfs class */ ip2_class = class_create(THIS_MODULE, "ip2"); @@ -731,86 +705,84 @@ static int __init ip2_loadmain(void) /* Register the read_procmem thing */ if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) { printk(KERN_ERR "IP2: failed to register read_procmem\n"); - return -EIO; /* leaking resources */ - } - - ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0); - /* Register the interrupt handler or poll handler, depending upon the - * specified interrupt. - */ + } else { - for (i = 0; i < IP2_MAX_BOARDS; ++i) { - if (ip2config.addr[i] == 0) - continue; + ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 ); + /* Register the interrupt handler or poll handler, depending upon the + * specified interrupt. + */ - pB = i2BoardPtrTable[i]; - if (pB != NULL) { - device_create_drvdata(ip2_class, NULL, - MKDEV(IP2_IPL_MAJOR, 4 * i), - NULL, "ipl%d", i); - device_create_drvdata(ip2_class, NULL, - MKDEV(IP2_IPL_MAJOR, 4 * i + 1), - NULL, "stat%d", i); - - for (box = 0; box < ABS_MAX_BOXES; box++) - for (j = 0; j < ABS_BIGGEST_BOX; j++) - if (pB->i2eChannelMap[box] & (1 << j)) - tty_register_device( - ip2_tty_driver, - j + ABS_BIGGEST_BOX * - (box+i*ABS_MAX_BOXES), - NULL); - } + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( 0 == ip2config.addr[i] ) { + continue; + } - if (poll_only) { - /* Poll only forces driver to only use polling and - to ignore the probed PCI or EISA interrupts. */ - ip2config.irq[i] = CIR_POLL; - } - if (ip2config.irq[i] == CIR_POLL) { -retry: - if (!timer_pending(&PollTimer)) { - mod_timer(&PollTimer, POLL_TIMEOUT); - printk(KERN_INFO "IP2: polling\n"); + if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { + device_create_drvdata(ip2_class, NULL, + MKDEV(IP2_IPL_MAJOR, 4 * i), + NULL, "ipl%d", i); + device_create_drvdata(ip2_class, NULL, + MKDEV(IP2_IPL_MAJOR, 4 * i + 1), + NULL, "stat%d", i); + + for ( box = 0; box < ABS_MAX_BOXES; ++box ) + { + for ( j = 0; j < ABS_BIGGEST_BOX; ++j ) + { + if ( pB->i2eChannelMap[box] & (1 << j) ) + { + tty_register_device(ip2_tty_driver, + j + ABS_BIGGEST_BOX * + (box+i*ABS_MAX_BOXES), NULL); + } + } + } } - } else { - if (have_requested_irq(ip2config.irq[i])) - continue; - rc = request_irq(ip2config.irq[i], ip2_interrupt, - IP2_SA_FLAGS | - (ip2config.type[i] == PCI ? IRQF_SHARED : 0), - pcName, i2BoardPtrTable[i]); - if (rc) { - printk(KERN_ERR "IP2: request_irq failed: " - "error %d\n", rc); + + if (poll_only) { +// Poll only forces driver to only use polling and +// to ignore the probed PCI or EISA interrupts. ip2config.irq[i] = CIR_POLL; - printk(KERN_INFO "IP2: Polling %ld/sec.\n", - (POLL_TIMEOUT - jiffies)); - goto retry; } - mark_requested_irq(ip2config.irq[i]); - /* Initialise the interrupt handler bottom half - * (aka slih). */ + if ( ip2config.irq[i] == CIR_POLL ) { +retry: + if (!TimerOn) { + PollTimer.expires = POLL_TIMEOUT; + add_timer ( &PollTimer ); + TimerOn = 1; + printk( KERN_INFO "IP2: polling\n"); + } + } else { + if (have_requested_irq(ip2config.irq[i])) + continue; + rc = request_irq( ip2config.irq[i], ip2_interrupt, + IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0), + pcName, i2BoardPtrTable[i]); + if (rc) { + printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc); + ip2config.irq[i] = CIR_POLL; + printk( KERN_INFO "IP2: Polling %ld/sec.\n", + (POLL_TIMEOUT - jiffies)); + goto retry; + } + mark_requested_irq(ip2config.irq[i]); + /* Initialise the interrupt handler bottom half (aka slih). */ + } } - } - - for (i = 0; i < IP2_MAX_BOARDS; ++i) { - if (i2BoardPtrTable[i]) { - /* set and enable board interrupt */ - set_irq(i, ip2config.irq[i]); + for( i = 0; i < IP2_MAX_BOARDS; ++i ) { + if ( i2BoardPtrTable[i] ) { + set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */ + } } } - - ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0); - - return 0; + ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 ); + goto out; out_chrdev: unregister_chrdev(IP2_IPL_MAJOR, "ip2"); - /* unregister and put tty here */ +out: return err; } -module_init(ip2_loadmain); /******************************************************************************/ /* Function: ip2_init_board() */ @@ -1227,8 +1199,9 @@ ip2_polled_interrupt(void) { int i; i2eBordStrPtr pB; + const int irq = 0; - ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0); + ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq ); /* Service just the boards on the list using this irq */ for( i = 0; i < i2nBoards; ++i ) { @@ -1237,8 +1210,9 @@ ip2_polled_interrupt(void) // Only process those boards which match our IRQ. // IRQ = 0 for polled boards, we won't poll "IRQ" boards - if (pB && pB->i2eUsingIrq == 0) + if ( pB && (pB->i2eUsingIrq == irq) ) { ip2_irq_work(pB); + } } ++irq_counter; @@ -1276,12 +1250,16 @@ ip2_poll(unsigned long arg) { ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 ); + TimerOn = 0; // it's the truth but not checked in service + // Just polled boards, IRQ = 0 will hit all non-interrupt boards. // It will NOT poll boards handled by hard interrupts. // The issue of queued BH interrupts is handled in ip2_interrupt(). ip2_polled_interrupt(); - mod_timer(&PollTimer, POLL_TIMEOUT); + PollTimer.expires = POLL_TIMEOUT; + add_timer( &PollTimer ); + TimerOn = 1; ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); } @@ -2893,7 +2871,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) case 13: switch ( cmd ) { case 64: /* Driver - ip2stat */ - rc = put_user(-1, pIndex++ ); + rc = put_user(ip2_tty_driver->refcount, pIndex++ ); rc = put_user(irq_counter, pIndex++ ); rc = put_user(bh_counter, pIndex++ ); break; diff --git a/trunk/drivers/char/isicom.c b/trunk/drivers/char/isicom.c index 7d30ee1d3fca..8f7cc190b62d 100644 --- a/trunk/drivers/char/isicom.c +++ b/trunk/drivers/char/isicom.c @@ -421,16 +421,17 @@ static void isicom_tx(unsigned long _data) if (retries >= 100) goto unlock; - tty = tty_port_tty_get(&port->port); - if (tty == NULL) - goto put_unlock; - for (; count > 0; count--, port++) { /* port not active or tx disabled to force flow control */ if (!(port->port.flags & ASYNC_INITIALIZED) || !(port->status & ISI_TXOK)) continue; + tty = port->port.tty; + + if (tty == NULL) + continue; + txcount = min_t(short, TX_SIZE, port->xmit_cnt); if (txcount <= 0 || tty->stopped || tty->hw_stopped) continue; @@ -488,8 +489,6 @@ static void isicom_tx(unsigned long _data) tty_wakeup(tty); } -put_unlock: - tty_kref_put(tty); unlock: spin_unlock_irqrestore(&isi_card[card].card_lock, flags); /* schedule another tx for hopefully in about 10ms */ @@ -548,7 +547,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty == NULL) { word_count = byte_count >> 1; while (byte_count > 1) { @@ -589,7 +588,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) } if (port->port.flags & ASYNC_CTS_FLOW) { - if (tty->hw_stopped) { + if (port->port.tty->hw_stopped) { if (header & ISI_CTS) { port->port.tty->hw_stopped = 0; /* start tx ing */ @@ -598,7 +597,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) tty_wakeup(tty); } } else if (!(header & ISI_CTS)) { - tty->hw_stopped = 1; + port->port.tty->hw_stopped = 1; /* stop tx ing */ port->status &= ~(ISI_TXOK | ISI_CTS); } @@ -661,21 +660,24 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) } outw(0x0000, base+0x04); /* enable interrupts */ spin_unlock(&card->card_lock); - tty_kref_put(tty); return IRQ_HANDLED; } -static void isicom_config_port(struct tty_struct *tty) +static void isicom_config_port(struct isi_port *port) { - struct isi_port *port = tty->driver_data; struct isi_board *card = port->card; + struct tty_struct *tty; unsigned long baud; unsigned long base = card->base; u16 channel_setup, channel = port->channel, shift_count = card->shift_count; unsigned char flow_ctrl; + tty = port->port.tty; + + if (tty == NULL) + return; /* FIXME: Switch to new tty baud API */ baud = C_BAUD(tty); if (baud & CBAUDEX) { @@ -688,7 +690,7 @@ static void isicom_config_port(struct tty_struct *tty) /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ if (baud < 1 || baud > 4) - tty->termios->c_cflag &= ~CBAUDEX; + port->port.tty->termios->c_cflag &= ~CBAUDEX; else baud += 15; } @@ -795,9 +797,8 @@ static inline void isicom_setup_board(struct isi_board *bp) spin_unlock_irqrestore(&bp->card_lock, flags); } -static int isicom_setup_port(struct tty_struct *tty) +static int isicom_setup_port(struct isi_port *port) { - struct isi_port *port = tty->driver_data; struct isi_board *card = port->card; unsigned long flags; @@ -807,7 +808,8 @@ static int isicom_setup_port(struct tty_struct *tty) return -ENOMEM; spin_lock_irqsave(&card->card_lock, flags); - clear_bit(TTY_IO_ERROR, &tty->flags); + if (port->port.tty) + clear_bit(TTY_IO_ERROR, &port->port.tty->flags); if (port->port.count == 1) card->count++; @@ -821,7 +823,7 @@ static int isicom_setup_port(struct tty_struct *tty) InterruptTheCard(card->base); } - isicom_config_port(tty); + isicom_config_port(port); port->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); @@ -932,8 +934,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) port->port.count++; tty->driver_data = port; - tty_port_tty_set(&port->port, tty); - error = isicom_setup_port(tty); + port->port.tty = tty; + error = isicom_setup_port(port); if (error == 0) error = block_til_ready(tty, filp, port); return error; @@ -953,17 +955,15 @@ static void isicom_shutdown_port(struct isi_port *port) struct isi_board *card = port->card; struct tty_struct *tty; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; - if (!(port->port.flags & ASYNC_INITIALIZED)) { - tty_kref_put(tty); + if (!(port->port.flags & ASYNC_INITIALIZED)) return; - } tty_port_free_xmit_buf(&port->port); port->port.flags &= ~ASYNC_INITIALIZED; /* 3rd October 2000 : Vinayak P Risbud */ - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; /*Fix done by Anil .S on 30-04-2001 remote login through isi port has dtr toggle problem @@ -1243,10 +1243,9 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static int isicom_set_serial_info(struct tty_struct *tty, - struct serial_struct __user *info) +static int isicom_set_serial_info(struct isi_port *port, + struct serial_struct __user *info) { - struct isi_port *port = tty->driver_data; struct serial_struct newinfo; int reconfig_port; @@ -1277,7 +1276,7 @@ static int isicom_set_serial_info(struct tty_struct *tty, if (reconfig_port) { unsigned long flags; spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(tty); + isicom_config_port(port); spin_unlock_irqrestore(&port->card->card_lock, flags); } unlock_kernel(); @@ -1319,7 +1318,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp, return isicom_get_serial_info(port, argp); case TIOCSSERIAL: - return isicom_set_serial_info(tty, argp); + return isicom_set_serial_info(port, argp); default: return -ENOIOCTLCMD; @@ -1342,7 +1341,7 @@ static void isicom_set_termios(struct tty_struct *tty, return; spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(tty); + isicom_config_port(port); spin_unlock_irqrestore(&port->card->card_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && @@ -1420,7 +1419,7 @@ static void isicom_hangup(struct tty_struct *tty) port->port.count = 0; port->port.flags &= ~ASYNC_NORMAL_ACTIVE; - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; wake_up_interruptible(&port->port.open_wait); } diff --git a/trunk/drivers/char/istallion.c b/trunk/drivers/char/istallion.c index 505d7a1f6b8c..843a2afaf204 100644 --- a/trunk/drivers/char/istallion.c +++ b/trunk/drivers/char/istallion.c @@ -623,25 +623,24 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp); static void stli_poll(unsigned long arg); static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp); -static int stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp); +static int stli_initopen(struct stlibrd *brdp, struct stliport *portp); static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); -static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, - struct stliport *portp, struct file *filp); -static int stli_setport(struct tty_struct *tty); +static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp); +static int stli_setport(struct stliport *portp); static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp); -static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp, asyport_t *pp, struct ktermios *tiosp); +static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp); static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts); static long stli_mktiocm(unsigned long sigvalue); static void stli_read(struct stlibrd *brdp, struct stliport *portp); static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp); -static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp); +static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp); static int stli_getbrdstats(combrd_t __user *bp); -static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, comstats_t __user *cp); -static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp); +static int stli_getportstats(struct stliport *portp, comstats_t __user *cp); +static int stli_portcmdstats(struct stliport *portp); static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp); static int stli_getportstruct(struct stliport __user *arg); static int stli_getbrdstruct(struct stlibrd __user *arg); @@ -732,16 +731,12 @@ static void stli_cleanup_ports(struct stlibrd *brdp) { struct stliport *portp; unsigned int j; - struct tty_struct *tty; for (j = 0; j < STL_MAXPORTS; j++) { portp = brdp->ports[j]; if (portp != NULL) { - tty = tty_port_tty_get(&portp->port); - if (tty != NULL) { - tty_hangup(tty); - tty_kref_put(tty); - } + if (portp->port.tty != NULL) + tty_hangup(portp->port.tty); kfree(portp); } } @@ -829,7 +824,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) * requires several commands to the board we will need to wait for any * other open that is already initializing the port. */ - tty_port_tty_set(&portp->port, tty); + portp->port.tty = tty; tty->driver_data = portp; portp->port.count++; @@ -840,7 +835,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) if ((portp->port.flags & ASYNC_INITIALIZED) == 0) { set_bit(ST_INITIALIZING, &portp->state); - if ((rc = stli_initopen(tty, brdp, portp)) >= 0) { + if ((rc = stli_initopen(brdp, portp)) >= 0) { portp->port.flags |= ASYNC_INITIALIZED; clear_bit(TTY_IO_ERROR, &tty->flags); } @@ -869,7 +864,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) * then also we might have to wait for carrier. */ if (!(filp->f_flags & O_NONBLOCK)) { - if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0) + if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0) return rc; } portp->port.flags |= ASYNC_NORMAL_ACTIVE; @@ -935,7 +930,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp) stli_flushbuffer(tty); tty->closing = 0; - tty_port_tty_set(&portp->port, NULL); + portp->port.tty = NULL; if (portp->openwaitcnt) { if (portp->close_delay) @@ -957,9 +952,9 @@ static void stli_close(struct tty_struct *tty, struct file *filp) * this still all happens pretty quickly. */ -static int stli_initopen(struct tty_struct *tty, - struct stlibrd *brdp, struct stliport *portp) +static int stli_initopen(struct stlibrd *brdp, struct stliport *portp) { + struct tty_struct *tty; asynotify_t nt; asyport_t aport; int rc; @@ -974,7 +969,10 @@ static int stli_initopen(struct tty_struct *tty, sizeof(asynotify_t), 0)) < 0) return rc; - stli_mkasyport(tty, portp, &aport, tty->termios); + tty = portp->port.tty; + if (tty == NULL) + return -ENODEV; + stli_mkasyport(portp, &aport, tty->termios); if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)) < 0) return rc; @@ -1163,21 +1161,22 @@ static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned l * waiting for the command to complete - so must have user context. */ -static int stli_setport(struct tty_struct *tty) +static int stli_setport(struct stliport *portp) { - struct stliport *portp = tty->driver_data; struct stlibrd *brdp; asyport_t aport; if (portp == NULL) return -ENODEV; + if (portp->port.tty == NULL) + return -ENODEV; if (portp->brdnr >= stli_nrbrds) return -ENODEV; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) return -ENODEV; - stli_mkasyport(tty, portp, &aport, tty->termios); + stli_mkasyport(portp, &aport, portp->port.tty->termios); return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)); } @@ -1188,8 +1187,7 @@ static int stli_setport(struct tty_struct *tty) * maybe because if we are clocal then we don't need to wait... */ -static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, - struct stliport *portp, struct file *filp) +static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp) { unsigned long flags; int rc, doclocal; @@ -1197,7 +1195,7 @@ static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, rc = 0; doclocal = 0; - if (tty->termios->c_cflag & CLOCAL) + if (portp->port.tty->termios->c_cflag & CLOCAL) doclocal++; spin_lock_irqsave(&stli_lock, flags); @@ -1375,6 +1373,8 @@ static void stli_flushchars(struct tty_struct *tty) stli_txcookrealsize = 0; stli_txcooktty = NULL; + if (tty == NULL) + return; if (cooktty == NULL) return; if (tty != cooktty) @@ -1572,11 +1572,10 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s * just quietly ignore any requests to change irq, etc. */ -static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp) +static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp) { struct serial_struct sio; int rc; - struct stliport *portp = tty->driver_data; if (copy_from_user(&sio, sp, sizeof(struct serial_struct))) return -EFAULT; @@ -1595,7 +1594,7 @@ static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *s portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; - if ((rc = stli_setport(tty)) < 0) + if ((rc = stli_setport(portp)) < 0) return rc; return 0; } @@ -1686,17 +1685,17 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm rc = stli_getserial(portp, argp); break; case TIOCSSERIAL: - rc = stli_setserial(tty, argp); + rc = stli_setserial(portp, argp); break; case STL_GETPFLAG: rc = put_user(portp->pflag, (unsigned __user *)argp); break; case STL_SETPFLAG: if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0) - stli_setport(tty); + stli_setport(portp); break; case COM_GETPORTSTATS: - rc = stli_getportstats(tty, portp, argp); + rc = stli_getportstats(portp, argp); break; case COM_CLRPORTSTATS: rc = stli_clrportstats(portp, argp); @@ -1730,6 +1729,8 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) struct ktermios *tiosp; asyport_t aport; + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1741,7 +1742,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) tiosp = tty->termios; - stli_mkasyport(tty, portp, &aport, tiosp); + stli_mkasyport(portp, &aport, tiosp); stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0); stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1); stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, @@ -1853,7 +1854,7 @@ static void stli_hangup(struct tty_struct *tty) clear_bit(ST_TXBUSY, &portp->state); clear_bit(ST_RXSTOP, &portp->state); set_bit(TTY_IO_ERROR, &tty->flags); - tty_port_tty_set(&portp->port, NULL); + portp->port.tty = NULL; portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; portp->port.count = 0; spin_unlock_irqrestore(&stli_lock, flags); @@ -1934,6 +1935,8 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout) struct stliport *portp; unsigned long tend; + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1995,7 +1998,7 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn char *sp, *uart; int rc, cnt; - rc = stli_portcmdstats(NULL, portp); + rc = stli_portcmdstats(portp); uart = "UNKNOWN"; if (brdp->state & BST_STARTED) { @@ -2185,7 +2188,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp) if (test_bit(ST_RXSTOP, &portp->state)) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -2227,7 +2230,6 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp) set_bit(ST_RXING, &portp->state); tty_schedule_flip(tty); - tty_kref_put(tty); } /*****************************************************************************/ @@ -2360,7 +2362,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) if (ap->notify) { nt = ap->changed; ap->notify = 0; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (nt.signal & SG_DCD) { oldsigs = portp->sigs; @@ -2397,7 +2399,6 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) tty_schedule_flip(tty); } } - tty_kref_put(tty); if (nt.data & DT_RXBUSY) { donerx++; @@ -2534,15 +2535,14 @@ static void stli_poll(unsigned long arg) * the slave. */ -static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp, - asyport_t *pp, struct ktermios *tiosp) +static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp) { memset(pp, 0, sizeof(asyport_t)); /* * Start of by setting the baud, char size, parity and stop bit info. */ - pp->baudout = tty_get_baud_rate(tty); + pp->baudout = tty_get_baud_rate(portp->port.tty); if ((tiosp->c_cflag & CBAUD) == B38400) { if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) pp->baudout = 57600; @@ -2695,7 +2695,7 @@ static int stli_initports(struct stlibrd *brdp) printk("STALLION: failed to allocate port structure\n"); continue; } - tty_port_init(&portp->port); + portp->magic = STLI_PORTMAGIC; portp->portnr = i; portp->brdnr = brdp->brdnr; @@ -4220,7 +4220,7 @@ static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, * what port to get stats for (used through board control device). */ -static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp) +static int stli_portcmdstats(struct stliport *portp) { unsigned long flags; struct stlibrd *brdp; @@ -4249,15 +4249,15 @@ static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp) stli_comstats.flags = portp->port.flags; spin_lock_irqsave(&brd_lock, flags); - if (tty != NULL) { - if (portp->port.tty == tty) { - stli_comstats.ttystate = tty->flags; + if (portp->port.tty != NULL) { + if (portp->port.tty->driver_data == portp) { + stli_comstats.ttystate = portp->port.tty->flags; stli_comstats.rxbuffered = -1; - if (tty->termios != NULL) { - stli_comstats.cflags = tty->termios->c_cflag; - stli_comstats.iflags = tty->termios->c_iflag; - stli_comstats.oflags = tty->termios->c_oflag; - stli_comstats.lflags = tty->termios->c_lflag; + if (portp->port.tty->termios != NULL) { + stli_comstats.cflags = portp->port.tty->termios->c_cflag; + stli_comstats.iflags = portp->port.tty->termios->c_iflag; + stli_comstats.oflags = portp->port.tty->termios->c_oflag; + stli_comstats.lflags = portp->port.tty->termios->c_lflag; } } } @@ -4294,8 +4294,7 @@ static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp) * what port to get stats for (used through board control device). */ -static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, - comstats_t __user *cp) +static int stli_getportstats(struct stliport *portp, comstats_t __user *cp) { struct stlibrd *brdp; int rc; @@ -4313,7 +4312,7 @@ static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, if (!brdp) return -ENODEV; - if ((rc = stli_portcmdstats(tty, portp)) < 0) + if ((rc = stli_portcmdstats(portp)) < 0) return rc; return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ? @@ -4428,7 +4427,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un switch (cmd) { case COM_GETPORTSTATS: - rc = stli_getportstats(NULL, NULL, argp); + rc = stli_getportstats(NULL, argp); done++; break; case COM_CLRPORTSTATS: diff --git a/trunk/drivers/char/moxa.c b/trunk/drivers/char/moxa.c index 5df4003ad873..d3d7864e0c1e 100644 --- a/trunk/drivers/char/moxa.c +++ b/trunk/drivers/char/moxa.c @@ -205,7 +205,7 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file, static void moxa_poll(unsigned long); static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); static void moxa_setup_empty_event(struct tty_struct *); -static void moxa_shut_down(struct tty_struct *); +static void moxa_shut_down(struct moxa_port *); /* * moxa board interface functions: */ @@ -217,7 +217,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, int, int); static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int); static int MoxaPortLineStatus(struct moxa_port *); static void MoxaPortFlushData(struct moxa_port *, int); -static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int); +static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int); static int MoxaPortReadData(struct moxa_port *); static int MoxaPortTxQueue(struct moxa_port *); static int MoxaPortRxQueue(struct moxa_port *); @@ -332,7 +332,6 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, for (i = 0; i < MAX_BOARDS; i++) { p = moxa_boards[i].ports; for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { - struct tty_struct *ttyp; memset(&tmp, 0, sizeof(tmp)); if (!moxa_boards[i].ready) goto copy; @@ -345,12 +344,10 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, if (status & 4) tmp.dcd = 1; - ttyp = tty_port_tty_get(&p->port); - if (!ttyp || !ttyp->termios) + if (!p->port.tty || !p->port.tty->termios) tmp.cflag = p->cflag; else - tmp.cflag = ttyp->termios->c_cflag; - tty_kref_put(tty); + tmp.cflag = p->port.tty->termios->c_cflag; copy: if (copy_to_user(argm, &tmp, sizeof(tmp))) { mutex_unlock(&moxa_openlock); @@ -883,14 +880,8 @@ static void moxa_board_deinit(struct moxa_board_conf *brd) /* pci hot-un-plug support */ for (a = 0; a < brd->numPorts; a++) - if (brd->ports[a].port.flags & ASYNC_INITIALIZED) { - struct tty_struct *tty = tty_port_tty_get( - &brd->ports[a].port); - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } - } + if (brd->ports[a].port.flags & ASYNC_INITIALIZED) + tty_hangup(brd->ports[a].port.tty); while (1) { opened = 0; for (a = 0; a < brd->numPorts; a++) @@ -1105,14 +1096,13 @@ static void __exit moxa_exit(void) module_init(moxa_init); module_exit(moxa_exit); -static void moxa_close_port(struct tty_struct *tty) +static void moxa_close_port(struct moxa_port *ch) { - struct moxa_port *ch = tty->driver_data; - moxa_shut_down(tty); + moxa_shut_down(ch); MoxaPortFlushData(ch, 2); ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; - tty->driver_data = NULL; - tty_port_tty_set(&ch->port, NULL); + ch->port.tty->driver_data = NULL; + ch->port.tty = NULL; } static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, @@ -1171,7 +1161,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; ch->port.count++; tty->driver_data = ch; - tty_port_tty_set(&ch->port, tty); + ch->port.tty = tty; if (!(ch->port.flags & ASYNC_INITIALIZED)) { ch->statusflags = 0; moxa_set_tty_param(tty, tty->termios); @@ -1189,7 +1179,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) if (retval) { if (ch->port.count) /* 0 means already hung up... */ if (--ch->port.count == 0) - moxa_close_port(tty); + moxa_close_port(ch); } else ch->port.flags |= ASYNC_NORMAL_ACTIVE; mutex_unlock(&moxa_openlock); @@ -1229,7 +1219,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ } - moxa_close_port(tty); + moxa_close_port(ch); unlock: mutex_unlock(&moxa_openlock); } @@ -1244,7 +1234,7 @@ static int moxa_write(struct tty_struct *tty, return 0; spin_lock_bh(&moxa_lock); - len = MoxaPortWriteData(tty, buf, count); + len = MoxaPortWriteData(ch, buf, count); spin_unlock_bh(&moxa_lock); ch->statusflags |= LOWWAIT; @@ -1419,7 +1409,7 @@ static void moxa_hangup(struct tty_struct *tty) return; } ch->port.count = 0; - moxa_close_port(tty); + moxa_close_port(ch); mutex_unlock(&moxa_openlock); wake_up_interruptible(&ch->port.open_wait); @@ -1427,14 +1417,11 @@ static void moxa_hangup(struct tty_struct *tty) static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) { - struct tty_struct *tty; dcd = !!dcd; - if (dcd != p->DCDState) { - tty = tty_port_tty_get(&p->port); - if (tty && C_CLOCAL(tty) && !dcd) - tty_hangup(tty); - tty_kref_put(tty); + if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) { + if (!dcd) + tty_hangup(p->port.tty); } p->DCDState = dcd; } @@ -1442,7 +1429,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) static int moxa_poll_port(struct moxa_port *p, unsigned int handle, u16 __iomem *ip) { - struct tty_struct *tty = tty_port_tty_get(&p->port); + struct tty_struct *tty = p->port.tty; void __iomem *ofsAddr; unsigned int inited = p->port.flags & ASYNC_INITIALIZED; u16 intr; @@ -1489,7 +1476,6 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, tty_insert_flip_char(tty, 0, TTY_BREAK); tty_schedule_flip(tty); } - tty_kref_put(tty); if (intr & IntrLine) moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state); @@ -1574,9 +1560,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty) spin_unlock_bh(&moxa_lock); } -static void moxa_shut_down(struct tty_struct *tty) +static void moxa_shut_down(struct moxa_port *ch) { - struct moxa_port *ch = tty->driver_data; + struct tty_struct *tp = ch->port.tty; if (!(ch->port.flags & ASYNC_INITIALIZED)) return; @@ -1586,7 +1572,7 @@ static void moxa_shut_down(struct tty_struct *tty) /* * If we're a modem control device and HUPCL is on, drop RTS & DTR. */ - if (C_HUPCL(tty)) + if (C_HUPCL(tp)) MoxaPortLineCtrl(ch, 0, 0); spin_lock_bh(&moxa_lock); @@ -1967,10 +1953,9 @@ static int MoxaPortLineStatus(struct moxa_port *port) return val; } -static int MoxaPortWriteData(struct tty_struct *tty, +static int MoxaPortWriteData(struct moxa_port *port, const unsigned char *buffer, int len) { - struct moxa_port *port = tty->driver_data; void __iomem *baseAddr, *ofsAddr, *ofs; unsigned int c, total; u16 head, tail, tx_mask, spage, epage; diff --git a/trunk/drivers/char/mxser.c b/trunk/drivers/char/mxser.c index 8beef50f95a0..b638403e8e9c 100644 --- a/trunk/drivers/char/mxser.c +++ b/trunk/drivers/char/mxser.c @@ -610,13 +610,15 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, return 0; } -static int mxser_set_baud(struct tty_struct *tty, long newspd) +static int mxser_set_baud(struct mxser_port *info, long newspd) { - struct mxser_port *info = tty->driver_data; int quot = 0, baud; unsigned char cval; - if (!info->ioaddr) + if (!info->port.tty || !info->port.tty->termios) + return -1; + + if (!(info->ioaddr)) return -1; if (newspd > info->max_baud) @@ -624,13 +626,13 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) if (newspd == 134) { quot = 2 * info->baud_base / 269; - tty_encode_baud_rate(tty, 134, 134); + tty_encode_baud_rate(info->port.tty, 134, 134); } else if (newspd) { quot = info->baud_base / newspd; if (quot == 0) quot = 1; baud = info->baud_base/quot; - tty_encode_baud_rate(tty, baud, baud); + tty_encode_baud_rate(info->port.tty, baud, baud); } else { quot = 0; } @@ -656,7 +658,7 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ #ifdef BOTHER - if (C_BAUD(tty) == BOTHER) { + if (C_BAUD(info->port.tty) == BOTHER) { quot = info->baud_base % newspd; quot *= 8; if (quot % newspd > newspd / 2) { @@ -677,20 +679,21 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static int mxser_change_speed(struct tty_struct *tty, - struct ktermios *old_termios) +static int mxser_change_speed(struct mxser_port *info, + struct ktermios *old_termios) { - struct mxser_port *info = tty->driver_data; unsigned cflag, cval, fcr; int ret = 0; unsigned char status; - cflag = tty->termios->c_cflag; - if (!info->ioaddr) + if (!info->port.tty || !info->port.tty->termios) + return ret; + cflag = info->port.tty->termios->c_cflag; + if (!(info->ioaddr)) return ret; - if (mxser_set_baud_method[tty->index] == 0) - mxser_set_baud(tty, tty_get_baud_rate(tty)); + if (mxser_set_baud_method[info->port.tty->index] == 0) + mxser_set_baud(info, tty_get_baud_rate(info->port.tty)); /* byte size and parity */ switch (cflag & CSIZE) { @@ -759,9 +762,9 @@ static int mxser_change_speed(struct tty_struct *tty, info->MCR |= UART_MCR_AFE; } else { status = inb(info->ioaddr + UART_MSR); - if (tty->hw_stopped) { + if (info->port.tty->hw_stopped) { if (status & UART_MSR_CTS) { - tty->hw_stopped = 0; + info->port.tty->hw_stopped = 0; if (info->type != PORT_16550A && !info->board->chip_flag) { outb(info->IER & ~UART_IER_THRI, @@ -771,11 +774,11 @@ static int mxser_change_speed(struct tty_struct *tty, outb(info->IER, info->ioaddr + UART_IER); } - tty_wakeup(tty); + tty_wakeup(info->port.tty); } } else { if (!(status & UART_MSR_CTS)) { - tty->hw_stopped = 1; + info->port.tty->hw_stopped = 1; if ((info->type != PORT_16550A) && (!info->board->chip_flag)) { info->IER &= ~UART_IER_THRI; @@ -801,21 +804,21 @@ static int mxser_change_speed(struct tty_struct *tty, * Set up parity check flag */ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (I_INPCK(tty)) + if (I_INPCK(info->port.tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (I_BRKINT(tty) || I_PARMRK(tty)) + if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) info->read_status_mask |= UART_LSR_BI; info->ignore_status_mask = 0; - if (I_IGNBRK(tty)) { + if (I_IGNBRK(info->port.tty)) { info->ignore_status_mask |= UART_LSR_BI; info->read_status_mask |= UART_LSR_BI; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ - if (I_IGNPAR(tty)) { + if (I_IGNPAR(info->port.tty)) { info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | @@ -827,16 +830,16 @@ static int mxser_change_speed(struct tty_struct *tty, } } if (info->board->chip_flag) { - mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty)); - mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty)); - if (I_IXON(tty)) { + mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty)); + mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty)); + if (I_IXON(info->port.tty)) { mxser_enable_must_rx_software_flow_control( info->ioaddr); } else { mxser_disable_must_rx_software_flow_control( info->ioaddr); } - if (I_IXOFF(tty)) { + if (I_IXOFF(info->port.tty)) { mxser_enable_must_tx_software_flow_control( info->ioaddr); } else { @@ -852,8 +855,7 @@ static int mxser_change_speed(struct tty_struct *tty, return ret; } -static void mxser_check_modem_status(struct tty_struct *tty, - struct mxser_port *port, int status) +static void mxser_check_modem_status(struct mxser_port *port, int status) { /* update input line counters */ if (status & UART_MSR_TERI) @@ -872,11 +874,10 @@ static void mxser_check_modem_status(struct tty_struct *tty, wake_up_interruptible(&port->port.open_wait); } - tty = tty_port_tty_get(&port->port); if (port->port.flags & ASYNC_CTS_FLOW) { - if (tty->hw_stopped) { + if (port->port.tty->hw_stopped) { if (status & UART_MSR_CTS) { - tty->hw_stopped = 0; + port->port.tty->hw_stopped = 0; if ((port->type != PORT_16550A) && (!port->board->chip_flag)) { @@ -886,11 +887,11 @@ static void mxser_check_modem_status(struct tty_struct *tty, outb(port->IER, port->ioaddr + UART_IER); } - tty_wakeup(tty); + tty_wakeup(port->port.tty); } } else { if (!(status & UART_MSR_CTS)) { - tty->hw_stopped = 1; + port->port.tty->hw_stopped = 1; if (port->type != PORT_16550A && !port->board->chip_flag) { port->IER &= ~UART_IER_THRI; @@ -902,9 +903,8 @@ static void mxser_check_modem_status(struct tty_struct *tty, } } -static int mxser_startup(struct tty_struct *tty) +static int mxser_startup(struct mxser_port *info) { - struct mxser_port *info = tty->driver_data; unsigned long page; unsigned long flags; @@ -921,7 +921,8 @@ static int mxser_startup(struct tty_struct *tty) } if (!info->ioaddr || !info->type) { - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); free_page(page); spin_unlock_irqrestore(&info->slock, flags); return 0; @@ -951,8 +952,8 @@ static int mxser_startup(struct tty_struct *tty) if (inb(info->ioaddr + UART_LSR) == 0xff) { spin_unlock_irqrestore(&info->slock, flags); if (capable(CAP_SYS_ADMIN)) { - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); return 0; } else return -ENODEV; @@ -990,13 +991,14 @@ static int mxser_startup(struct tty_struct *tty) (void) inb(info->ioaddr + UART_IIR); (void) inb(info->ioaddr + UART_MSR); - clear_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* * and set the speed of the serial port */ - mxser_change_speed(tty, NULL); + mxser_change_speed(info, NULL); info->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&info->slock, flags); @@ -1007,9 +1009,8 @@ static int mxser_startup(struct tty_struct *tty) * This routine will shutdown a serial port; interrupts maybe disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void mxser_shutdown(struct tty_struct *tty) +static void mxser_shutdown(struct mxser_port *info) { - struct mxser_port *info = tty->driver_data; unsigned long flags; if (!(info->port.flags & ASYNC_INITIALIZED)) @@ -1034,7 +1035,7 @@ static void mxser_shutdown(struct tty_struct *tty) info->IER = 0; outb(0x00, info->ioaddr + UART_IER); - if (tty->termios->c_cflag & HUPCL) + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); outb(info->MCR, info->ioaddr + UART_MCR); @@ -1050,7 +1051,8 @@ static void mxser_shutdown(struct tty_struct *tty) /* read data port to reset things */ (void) inb(info->ioaddr + UART_RX); - set_bit(TTY_IO_ERROR, &tty->flags); + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); info->port.flags &= ~ASYNC_INITIALIZED; @@ -1082,14 +1084,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) return -ENODEV; tty->driver_data = info; - tty_port_tty_set(&info->port, tty); + info->port.tty = tty; /* * Start up serial port */ spin_lock_irqsave(&info->slock, flags); info->port.count++; spin_unlock_irqrestore(&info->slock, flags); - retval = mxser_startup(tty); + retval = mxser_startup(info); if (retval) return retval; @@ -1207,13 +1209,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) break; } } - mxser_shutdown(tty); + mxser_shutdown(info); mxser_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; - tty_port_tty_set(&info->port, NULL); + info->port.tty = NULL; if (info->port.blocked_open) { if (info->port.close_delay) schedule_timeout_interruptible(info->port.close_delay); @@ -1335,13 +1337,12 @@ static int mxser_chars_in_buffer(struct tty_struct *tty) * friends of mxser_ioctl() * ------------------------------------------------------------ */ -static int mxser_get_serial_info(struct tty_struct *tty, +static int mxser_get_serial_info(struct mxser_port *info, struct serial_struct __user *retinfo) { - struct mxser_port *info = tty->driver_data; struct serial_struct tmp = { .type = info->type, - .line = tty->index, + .line = info->port.tty->index, .port = info->ioaddr, .irq = info->board->irq, .flags = info->port.flags, @@ -1356,10 +1357,9 @@ static int mxser_get_serial_info(struct tty_struct *tty, return 0; } -static int mxser_set_serial_info(struct tty_struct *tty, +static int mxser_set_serial_info(struct mxser_port *info, struct serial_struct __user *new_info) { - struct mxser_port *info = tty->driver_data; struct serial_struct new_serial; speed_t baud; unsigned long sl_flags; @@ -1393,14 +1393,14 @@ static int mxser_set_serial_info(struct tty_struct *tty, (new_serial.flags & ASYNC_FLAGS)); info->port.close_delay = new_serial.close_delay * HZ / 100; info->port.closing_wait = new_serial.closing_wait * HZ / 100; - tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) - ? 1 : 0; + info->port.tty->low_latency = + (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && (new_serial.baud_base != info->baud_base || new_serial.custom_divisor != info->custom_divisor)) { baud = new_serial.baud_base / new_serial.custom_divisor; - tty_encode_baud_rate(tty, baud, baud); + tty_encode_baud_rate(info->port.tty, baud, baud); } } @@ -1411,11 +1411,11 @@ static int mxser_set_serial_info(struct tty_struct *tty, if (info->port.flags & ASYNC_INITIALIZED) { if (flags != (info->port.flags & ASYNC_SPD_MASK)) { spin_lock_irqsave(&info->slock, sl_flags); - mxser_change_speed(tty, NULL); + mxser_change_speed(info, NULL); spin_unlock_irqrestore(&info->slock, sl_flags); } } else - retval = mxser_startup(tty); + retval = mxser_startup(info); return retval; } @@ -1461,7 +1461,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file) spin_lock_irqsave(&info->slock, flags); status = inb(info->ioaddr + UART_MSR); if (status & UART_MSR_ANY_DELTA) - mxser_check_modem_status(tty, info, status); + mxser_check_modem_status(info, status); spin_unlock_irqrestore(&info->slock, flags); return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | @@ -1606,7 +1606,6 @@ static int __init mxser_read_register(int port, unsigned short *regs) static int mxser_ioctl_special(unsigned int cmd, void __user *argp) { struct mxser_port *port; - struct tty_struct *tty; int result, status; unsigned int i, j; int ret = 0; @@ -1644,14 +1643,12 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) if (!port->ioaddr) goto copy; - - tty = tty_port_tty_get(&port->port); - if (!tty || !tty->termios) + if (!port->port.tty || !port->port.tty->termios) ms.cflag = port->normal_termios.c_cflag; else - ms.cflag = tty->termios->c_cflag; - tty_kref_put(tty); + ms.cflag = port->port.tty->termios->c_cflag; + status = inb(port->ioaddr + UART_MSR); if (status & UART_MSR_DCD) ms.dcd = 1; @@ -1707,18 +1704,15 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) me->up_txcnt[p] = port->mon_data.up_txcnt; me->modem_status[p] = port->mon_data.modem_status; - tty = tty_port_tty_get(&port->port); + me->baudrate[p] = tty_get_baud_rate(port->port.tty); - if (!tty || !tty->termios) { + if (!port->port.tty || !port->port.tty->termios) { cflag = port->normal_termios.c_cflag; iflag = port->normal_termios.c_iflag; - me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios); } else { - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; - me->baudrate[p] = tty_get_baud_rate(tty); + cflag = port->port.tty->termios->c_cflag; + iflag = port->port.tty->termios->c_iflag; } - tty_kref_put(tty); me->databits[p] = cflag & CSIZE; me->stopbits[p] = cflag & CSTOPB; @@ -1828,12 +1822,12 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, switch (cmd) { case TIOCGSERIAL: lock_kernel(); - retval = mxser_get_serial_info(tty, argp); + retval = mxser_get_serial_info(info, argp); unlock_kernel(); return retval; case TIOCSSERIAL: lock_kernel(); - retval = mxser_set_serial_info(tty, argp); + retval = mxser_set_serial_info(info, argp); unlock_kernel(); return retval; case TIOCSERGETLSR: /* Get line status register */ @@ -1902,7 +1896,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, lock_kernel(); status = mxser_get_msr(info->ioaddr, 1, tty->index); - mxser_check_modem_status(tty, info, status); + mxser_check_modem_status(info, status); mcr = inb(info->ioaddr + UART_MCR); if (mcr & MOXA_MUST_MCR_XON_FLAG) @@ -1915,7 +1909,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, else info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; - if (tty->hw_stopped) + if (info->port.tty->hw_stopped) info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; else info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; @@ -1964,7 +1958,7 @@ static void mxser_stoprx(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) { + if (info->port.tty->termios->c_cflag & CRTSCTS) { info->MCR &= ~UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -2001,7 +1995,7 @@ static void mxser_unthrottle(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) { + if (info->port.tty->termios->c_cflag & CRTSCTS) { info->MCR |= UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -2046,7 +2040,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi unsigned long flags; spin_lock_irqsave(&info->slock, flags); - mxser_change_speed(tty, old_termios); + mxser_change_speed(info, old_termios); spin_unlock_irqrestore(&info->slock, flags); if ((old_termios->c_cflag & CRTSCTS) && @@ -2144,10 +2138,10 @@ static void mxser_hangup(struct tty_struct *tty) struct mxser_port *info = tty->driver_data; mxser_flush_buffer(tty); - mxser_shutdown(tty); + mxser_shutdown(info); info->port.count = 0; info->port.flags &= ~ASYNC_NORMAL_ACTIVE; - tty_port_tty_set(&info->port, NULL); + info->port.tty = NULL; wake_up_interruptible(&info->port.open_wait); } @@ -2170,9 +2164,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state) return 0; } -static void mxser_receive_chars(struct tty_struct *tty, - struct mxser_port *port, int *status) +static void mxser_receive_chars(struct mxser_port *port, int *status) { + struct tty_struct *tty = port->port.tty; unsigned char ch, gdl; int ignored = 0; int cnt = 0; @@ -2180,8 +2174,9 @@ static void mxser_receive_chars(struct tty_struct *tty, int max = 256; recv_room = tty->receive_room; - if (recv_room == 0 && !port->ldisc_stop_rx) + if ((recv_room == 0) && (!port->ldisc_stop_rx)) mxser_stoprx(tty); + if (port->board->chip_flag != MOXA_OTHER_UART) { if (*status & UART_LSR_SPECIAL) @@ -2258,7 +2253,7 @@ static void mxser_receive_chars(struct tty_struct *tty, } while (*status & UART_LSR_DR); end_intr: - mxvar_log.rxcnt[tty->index] += cnt; + mxvar_log.rxcnt[port->port.tty->index] += cnt; port->mon_data.rxcnt += cnt; port->mon_data.up_rxcnt += cnt; @@ -2272,14 +2267,14 @@ static void mxser_receive_chars(struct tty_struct *tty, spin_lock(&port->slock); } -static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port) +static void mxser_transmit_chars(struct mxser_port *port) { int count, cnt; if (port->x_char) { outb(port->x_char, port->ioaddr + UART_TX); port->x_char = 0; - mxvar_log.txcnt[tty->index]++; + mxvar_log.txcnt[port->port.tty->index]++; port->mon_data.txcnt++; port->mon_data.up_txcnt++; port->icount.tx++; @@ -2289,8 +2284,8 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port if (port->port.xmit_buf == NULL) return; - if (port->xmit_cnt <= 0 || tty->stopped || - (tty->hw_stopped && + if ((port->xmit_cnt <= 0) || port->port.tty->stopped || + (port->port.tty->hw_stopped && (port->type != PORT_16550A) && (!port->board->chip_flag))) { port->IER &= ~UART_IER_THRI; @@ -2307,14 +2302,14 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port if (--port->xmit_cnt <= 0) break; } while (--count > 0); - mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt); + mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt); port->mon_data.txcnt += (cnt - port->xmit_cnt); port->mon_data.up_txcnt += (cnt - port->xmit_cnt); port->icount.tx += (cnt - port->xmit_cnt); - if (port->xmit_cnt < WAKEUP_CHARS && tty) - tty_wakeup(tty); + if (port->xmit_cnt < WAKEUP_CHARS) + tty_wakeup(port->port.tty); if (port->xmit_cnt <= 0) { port->IER &= ~UART_IER_THRI; @@ -2333,7 +2328,6 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) int max, irqbits, bits, msr; unsigned int int_cnt, pass_counter = 0; int handled = IRQ_NONE; - struct tty_struct *tty; for (i = 0; i < MXSER_BOARDS; i++) if (dev_id == &mxser_boards[i]) { @@ -2366,15 +2360,13 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) if (iir & UART_IIR_NO_INT) break; iir &= MOXA_MUST_IIR_MASK; - tty = tty_port_tty_get(&port->port); - if (!tty || + if (!port->port.tty || (port->port.flags & ASYNC_CLOSING) || !(port->port.flags & ASYNC_INITIALIZED)) { status = inb(port->ioaddr + UART_LSR); outb(0x27, port->ioaddr + UART_FCR); inb(port->ioaddr + UART_MSR); - tty_kref_put(tty); break; } @@ -2395,28 +2387,27 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) iir == MOXA_MUST_IIR_RDA || iir == MOXA_MUST_IIR_RTO || iir == MOXA_MUST_IIR_LSR) - mxser_receive_chars(tty, port, + mxser_receive_chars(port, &status); } else { status &= port->read_status_mask; if (status & UART_LSR_DR) - mxser_receive_chars(tty, port, + mxser_receive_chars(port, &status); } msr = inb(port->ioaddr + UART_MSR); if (msr & UART_MSR_ANY_DELTA) - mxser_check_modem_status(tty, port, msr); + mxser_check_modem_status(port, msr); if (port->board->chip_flag) { if (iir == 0x02 && (status & UART_LSR_THRE)) - mxser_transmit_chars(tty, port); + mxser_transmit_chars(port); } else { if (status & UART_LSR_THRE) - mxser_transmit_chars(tty, port); + mxser_transmit_chars(port); } - tty_kref_put(tty); } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); spin_unlock(&port->slock); } diff --git a/trunk/drivers/char/n_hdlc.c b/trunk/drivers/char/n_hdlc.c index bacb3e2872ae..69ec6399c714 100644 --- a/trunk/drivers/char/n_hdlc.c +++ b/trunk/drivers/char/n_hdlc.c @@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, break; default: - error = n_tty_ioctl_helper(tty, file, cmd, arg); + error = n_tty_ioctl (tty, file, cmd, arg); break; } return error; diff --git a/trunk/drivers/char/n_r3964.c b/trunk/drivers/char/n_r3964.c index 4a8215a89ad3..ae377aa473ba 100644 --- a/trunk/drivers/char/n_r3964.c +++ b/trunk/drivers/char/n_r3964.c @@ -372,8 +372,14 @@ static void remove_from_rx_queue(struct r3964_info *pInfo, static void put_char(struct r3964_info *pInfo, unsigned char ch) { struct tty_struct *tty = pInfo->tty; + + if (tty == NULL) + return; + /* FIXME: put_char should not be called from an IRQ */ - tty_put_char(tty, ch); + if (tty->ops->put_char) { + tty->ops->put_char(tty, ch); + } pInfo->bcc ^= ch; } diff --git a/trunk/drivers/char/n_tty.c b/trunk/drivers/char/n_tty.c index efbfe9612658..708c2b1dbe51 100644 --- a/trunk/drivers/char/n_tty.c +++ b/trunk/drivers/char/n_tty.c @@ -26,7 +26,7 @@ * * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to * waiting writing processes-Sapan Bhatia . - * Also fixed a bug in BLOCKING mode where n_tty_write returns + * Also fixed a bug in BLOCKING mode where write_chan returns * EAGAIN */ @@ -99,7 +99,6 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, static void n_tty_set_room(struct tty_struct *tty) { - /* tty->read_cnt is not read locked ? */ int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; /* @@ -122,16 +121,6 @@ static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) } } -/** - * put_tty_queue - add character to tty - * @c: character - * @tty: tty device - * - * Add a character to the tty read_buf queue. This is done under the - * read_lock to serialize character addition and also to protect us - * against parallel reads or flushes - */ - static void put_tty_queue(unsigned char c, struct tty_struct *tty) { unsigned long flags; @@ -148,11 +137,14 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty) * check_unthrottle - allow new receive data * @tty; tty device * - * Check whether to call the driver unthrottle functions - * + * Check whether to call the driver.unthrottle function. + * We test the TTY_THROTTLED bit first so that it always + * indicates the current state. The decision about whether + * it is worth allowing more input has been taken by the caller. * Can sleep, may be called under the atomic_read_lock mutex but * this is not guaranteed. */ + static void check_unthrottle(struct tty_struct *tty) { if (tty->count) @@ -166,8 +158,6 @@ static void check_unthrottle(struct tty_struct *tty) * Reset the read buffer counters, clear the flags, * and make sure the driver is unthrottled. Called * from n_tty_open() and n_tty_flush_buffer(). - * - * Locking: tty_read_lock for read fields. */ static void reset_buffer_flags(struct tty_struct *tty) { @@ -191,7 +181,7 @@ static void reset_buffer_flags(struct tty_struct *tty) * at hangup) or when the N_TTY line discipline internally has to * clean the pending queue (for example some signals). * - * Locking: ctrl_lock, read_lock. + * Locking: ctrl_lock */ static void n_tty_flush_buffer(struct tty_struct *tty) @@ -217,8 +207,6 @@ static void n_tty_flush_buffer(struct tty_struct *tty) * * Report the number of characters buffered to be delivered to user * at this instant in time. - * - * Locking: read_lock */ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) @@ -358,7 +346,7 @@ static int opost(unsigned char c, struct tty_struct *tty) * the simple cases normally found and helps to generate blocks of * symbols for the console driver and thus improve performance. * - * Called from n_tty_write under the tty layer write lock. Relies + * Called from write_chan under the tty layer write lock. Relies * on lock_kernel for the tty->column state. */ @@ -422,8 +410,6 @@ static ssize_t opost_block(struct tty_struct *tty, * * Echo user input back onto the screen. This must be called only when * L_ECHO(tty) is true. Called from the driver receive_buf path. - * - * Relies on BKL for tty column locking */ static void echo_char(unsigned char c, struct tty_struct *tty) @@ -436,12 +422,6 @@ static void echo_char(unsigned char c, struct tty_struct *tty) opost(c, tty); } -/** - * finsh_erasing - complete erase - * @tty: tty doing the erase - * - * Relies on BKL for tty column locking - */ static inline void finish_erasing(struct tty_struct *tty) { if (tty->erasing) { @@ -459,8 +439,6 @@ static inline void finish_erasing(struct tty_struct *tty) * Perform erase and necessary output when an erase character is * present in the stream from the driver layer. Handles the complexities * of UTF-8 multibyte symbols. - * - * Locking: read_lock for tty buffers, BKL for column/erasing state */ static void eraser(unsigned char c, struct tty_struct *tty) @@ -469,7 +447,6 @@ static void eraser(unsigned char c, struct tty_struct *tty) int head, seen_alnums, cnt; unsigned long flags; - /* FIXME: locking needed ? */ if (tty->read_head == tty->canon_head) { /* opost('\a', tty); */ /* what do you think? */ return; @@ -504,7 +481,6 @@ static void eraser(unsigned char c, struct tty_struct *tty) } seen_alnums = 0; - /* FIXME: Locking ?? */ while (tty->read_head != tty->canon_head) { head = tty->read_head; @@ -607,8 +583,6 @@ static void eraser(unsigned char c, struct tty_struct *tty) * may caus terminal flushing to take place according to the termios * settings and character used. Called from the driver receive_buf * path so serialized. - * - * Locking: ctrl_lock, read_lock (both via flush buffer) */ static inline void isig(int sig, struct tty_struct *tty, int flush) @@ -1033,26 +1007,12 @@ int is_ignored(int sig) * and is protected from re-entry by the tty layer. The user is * guaranteed that this function will not be re-entered or in progress * when the ldisc is closed. - * - * Locking: Caller holds tty->termios_mutex */ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { - int canon_change = 1; - BUG_ON(!tty); - - if (old) - canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON; - if (canon_change) { - memset(&tty->read_flags, 0, sizeof tty->read_flags); - tty->canon_head = tty->read_tail; - tty->canon_data = 0; - tty->erasing = 0; - } - - if (canon_change && !L_ICANON(tty) && tty->read_cnt) - wake_up_interruptible(&tty->read_wait); + if (!tty) + return; tty->icanon = (L_ICANON(tty) != 0); if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { @@ -1183,7 +1143,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt) * @b: user data * @nr: size of data * - * Helper function to speed up n_tty_read. It is only called when + * Helper function to speed up read_chan. It is only called when * ICANON is off; it copies characters straight from the tty queue to * user space directly. It can be profitably called twice; once to * drain the space from the tail pointer to the (physical) end of the @@ -1250,7 +1210,7 @@ static int job_control(struct tty_struct *tty, struct file *file) if (file->f_op->write != redirected_tty_write && current->signal->tty == tty) { if (!tty->pgrp) - printk(KERN_ERR "n_tty_read: no tty->pgrp!\n"); + printk(KERN_ERR "read_chan: no tty->pgrp!\n"); else if (task_pgrp(current) != tty->pgrp) { if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) @@ -1265,7 +1225,7 @@ static int job_control(struct tty_struct *tty, struct file *file) /** - * n_tty_read - read function for tty + * read_chan - read function for tty * @tty: tty device * @file: file object * @buf: userspace buffer pointer @@ -1279,7 +1239,7 @@ static int job_control(struct tty_struct *tty, struct file *file) * This code must be sure never to sleep through a hangup. */ -static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, +static ssize_t read_chan(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) { unsigned char __user *b = buf; @@ -1294,7 +1254,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, do_it_again: - BUG_ON(!tty->read_buf); + if (!tty->read_buf) { + printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n"); + return -EIO; + } c = job_control(tty, file); if (c < 0) @@ -1481,7 +1444,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, } /** - * n_tty_write - write function for tty + * write_chan - write function for tty * @tty: tty device * @file: file object * @buf: userspace buffer pointer @@ -1495,7 +1458,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, * This code must be sure never to sleep through a hangup. */ -static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, +static ssize_t write_chan(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr) { const unsigned char *b = buf; @@ -1569,7 +1532,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, } /** - * n_tty_poll - poll method for N_TTY + * normal_poll - poll method for N_TTY * @tty: terminal device * @file: file accessing it * @wait: poll table @@ -1582,7 +1545,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, * Called without the kernel lock held - fine */ -static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, +static unsigned int normal_poll(struct tty_struct *tty, struct file *file, poll_table *wait) { unsigned int mask = 0; @@ -1610,44 +1573,6 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, return mask; } -static unsigned long inq_canon(struct tty_struct *tty) -{ - int nr, head, tail; - - if (!tty->canon_data) - return 0; - head = tty->canon_head; - tail = tty->read_tail; - nr = (head - tail) & (N_TTY_BUF_SIZE-1); - /* Skip EOF-chars.. */ - while (head != tail) { - if (test_bit(tail, tty->read_flags) && - tty->read_buf[tail] == __DISABLED_CHAR) - nr--; - tail = (tail+1) & (N_TTY_BUF_SIZE-1); - } - return nr; -} - -static int n_tty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int retval; - - switch (cmd) { - case TIOCOUTQ: - return put_user(tty_chars_in_buffer(tty), (int __user *) arg); - case TIOCINQ: - /* FIXME: Locking */ - retval = tty->read_cnt; - if (L_ICANON(tty)) - retval = inq_canon(tty); - return put_user(retval, (unsigned int __user *) arg); - default: - return n_tty_ioctl_helper(tty, file, cmd, arg); - } -} - struct tty_ldisc_ops tty_ldisc_N_TTY = { .magic = TTY_LDISC_MAGIC, .name = "n_tty", @@ -1655,11 +1580,11 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = { .close = n_tty_close, .flush_buffer = n_tty_flush_buffer, .chars_in_buffer = n_tty_chars_in_buffer, - .read = n_tty_read, - .write = n_tty_write, + .read = read_chan, + .write = write_chan, .ioctl = n_tty_ioctl, .set_termios = n_tty_set_termios, - .poll = n_tty_poll, + .poll = normal_poll, .receive_buf = n_tty_receive_buf, .write_wakeup = n_tty_write_wakeup }; diff --git a/trunk/drivers/char/nozomi.c b/trunk/drivers/char/nozomi.c index 9a34a1935283..66a0f931c66c 100644 --- a/trunk/drivers/char/nozomi.c +++ b/trunk/drivers/char/nozomi.c @@ -1599,10 +1599,7 @@ static int ntty_open(struct tty_struct *tty, struct file *file) return 0; } -/* Called when the userspace process close the tty, /dev/noz*. Also - called immediately if ntty_open fails in which case tty->driver_data - will be NULL an we exit by the first return */ - +/* Called when the userspace process close the tty, /dev/noz*. */ static void ntty_close(struct tty_struct *tty, struct file *file) { struct nozomi *dc = get_dc_by_tty(tty); diff --git a/trunk/drivers/char/pcmcia/ipwireless/tty.c b/trunk/drivers/char/pcmcia/ipwireless/tty.c index 569f2f7743a7..3a23e7694d55 100644 --- a/trunk/drivers/char/pcmcia/ipwireless/tty.c +++ b/trunk/drivers/char/pcmcia/ipwireless/tty.c @@ -276,7 +276,6 @@ static int ipw_write_room(struct tty_struct *linux_tty) struct ipw_tty *tty = linux_tty->driver_data; int room; - /* FIXME: Exactly how is the tty object locked here .. */ if (!tty) return -ENODEV; @@ -398,7 +397,6 @@ static int set_control_lines(struct ipw_tty *tty, unsigned int set, static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file) { struct ipw_tty *tty = linux_tty->driver_data; - /* FIXME: Exactly how is the tty object locked here .. */ if (!tty) return -ENODEV; @@ -414,7 +412,6 @@ ipw_tiocmset(struct tty_struct *linux_tty, struct file *file, unsigned int set, unsigned int clear) { struct ipw_tty *tty = linux_tty->driver_data; - /* FIXME: Exactly how is the tty object locked here .. */ if (!tty) return -ENODEV; @@ -436,8 +433,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, if (!tty->open_count) return -EINVAL; - /* FIXME: Exactly how is the tty object locked here .. */ - switch (cmd) { case TIOCGSERIAL: return ipwireless_get_serial_info(tty, (void __user *) arg); @@ -472,6 +467,13 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, } return 0; + case TCGETS: + case TCGETA: + return n_tty_ioctl(linux_tty, file, cmd, arg); + + case TCFLSH: + return n_tty_ioctl(linux_tty, file, cmd, arg); + case FIONREAD: { int val = 0; @@ -480,11 +482,10 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, return -EFAULT; } return 0; - case TCFLSH: - return tty_perform_flush(linux_tty, arg); } } - return tty_mode_ioctl(linux_tty, file, cmd , arg); + + return -ENOIOCTLCMD; } static int add_tty(dev_node_t *nodesp, int j, @@ -587,8 +588,6 @@ void ipwireless_tty_free(struct ipw_tty *tty) tty_hangup(ttyj->linux_tty); /* Wait till the tty_hangup has completed */ flush_scheduled_work(); - /* FIXME: Exactly how is the tty object locked here - against a parallel ioctl etc */ mutex_lock(&ttyj->ipw_tty_mutex); } while (ttyj->open_count) diff --git a/trunk/drivers/char/pty.c b/trunk/drivers/char/pty.c index 6d4582712b1f..76b27932d229 100644 --- a/trunk/drivers/char/pty.c +++ b/trunk/drivers/char/pty.c @@ -8,12 +8,10 @@ * Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to * waiting writers -- Sapan Bhatia * - * When reading this code see also fs/devpts. In particular note that the - * driver_data field is used by the devpts side as a binding to the devpts - * inode. + * */ -#include +#include /* For EXPORT_SYMBOL */ #include #include @@ -25,12 +23,11 @@ #include #include #include -#include -#include -#include -#include +#include #include +#include +#include /* These are global because they are accessed in tty_io.c */ #ifdef CONFIG_UNIX98_PTYS @@ -38,12 +35,14 @@ struct tty_driver *ptm_driver; static struct tty_driver *pts_driver; #endif -static void pty_close(struct tty_struct *tty, struct file *filp) +static void pty_close(struct tty_struct * tty, struct file * filp) { - BUG_ON(!tty); - if (tty->driver->subtype == PTY_TYPE_MASTER) - WARN_ON(tty->count > 1); - else { + if (!tty) + return; + if (tty->driver->subtype == PTY_TYPE_MASTER) { + if (tty->count > 1) + printk("master pty_close: count = %d!!\n", tty->count); + } else { if (tty->count > 2) return; } @@ -60,7 +59,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) set_bit(TTY_OTHER_CLOSED, &tty->flags); #ifdef CONFIG_UNIX98_PTYS if (tty->driver == ptm_driver) - devpts_pty_kill(tty->link); + devpts_pty_kill(tty->index); #endif tty_vhangup(tty->link); } @@ -70,13 +69,13 @@ static void pty_close(struct tty_struct *tty, struct file *filp) * The unthrottle routine is called by the line discipline to signal * that it can receive more characters. For PTY's, the TTY_THROTTLED * flag is always set, to force the line discipline to always call the - * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE + * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE * characters in the queue. This is necessary since each time this * happens, we need to wake up any sleeping processes that could be * (1) trying to send data to the pty, or (2) waiting in wait_until_sent() * for the pty buffer to be drained. */ -static void pty_unthrottle(struct tty_struct *tty) +static void pty_unthrottle(struct tty_struct * tty) { struct tty_struct *o_tty = tty->link; @@ -88,7 +87,7 @@ static void pty_unthrottle(struct tty_struct *tty) } /* - * WSH 05/24/97: modified to + * WSH 05/24/97: modified to * (1) use space in tty->flip instead of a shared temp buffer * The flip buffers aren't being used for a pty, so there's lots * of space available. The buffer is protected by a per-pty @@ -101,8 +100,7 @@ static void pty_unthrottle(struct tty_struct *tty) * not our partners. We can't just take the other one blindly without * risking deadlocks. */ -static int pty_write(struct tty_struct *tty, const unsigned char *buf, - int count) +static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count) { struct tty_struct *to = tty->link; int c; @@ -114,7 +112,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, if (c > count) c = count; to->ldisc.ops->receive_buf(to, buf, NULL, c); - + return c; } @@ -130,17 +128,17 @@ static int pty_write_room(struct tty_struct *tty) /* * WSH 05/24/97: Modified for asymmetric MASTER/SLAVE behavior - * The chars_in_buffer() value is used by the ldisc select() function + * The chars_in_buffer() value is used by the ldisc select() function * to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256). * The pty driver chars_in_buffer() Master/Slave must behave differently: * * The Master side needs to allow typed-ahead commands to accumulate * while being canonicalized, so we report "our buffer" as empty until * some threshold is reached, and then report the count. (Any count > - * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock - * the count returned must be 0 if no canonical data is available to be + * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock + * the count returned must be 0 if no canonical data is available to be * read. (The N_TTY ldisc.chars_in_buffer now knows this.) - * + * * The Slave side passes all characters in raw mode to the Master side's * buffer where they can be read immediately, so in this case we can * return the true count in the buffer. @@ -157,22 +155,21 @@ static int pty_chars_in_buffer(struct tty_struct *tty) /* The ldisc must report 0 if no characters available to be read */ count = to->ldisc.ops->chars_in_buffer(to); - if (tty->driver->subtype == PTY_TYPE_SLAVE) - return count; + if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; - /* Master side driver ... if the other side's read buffer is less than + /* Master side driver ... if the other side's read buffer is less than * half full, return 0 to allow writers to proceed; otherwise return - * the count. This leaves a comfortable margin to avoid overflow, + * the count. This leaves a comfortable margin to avoid overflow, * and still allows half a buffer's worth of typed-ahead commands. */ - return (count < N_TTY_BUF_SIZE/2) ? 0 : count; + return ((count < N_TTY_BUF_SIZE/2) ? 0 : count); } /* Set the lock flag on a pty */ -static int pty_set_lock(struct tty_struct *tty, int __user *arg) +static int pty_set_lock(struct tty_struct *tty, int __user * arg) { int val; - if (get_user(val, arg)) + if (get_user(val,arg)) return -EFAULT; if (val) set_bit(TTY_PTY_LOCK, &tty->flags); @@ -185,13 +182,13 @@ static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; unsigned long flags; - + if (!to) return; - + if (to->ldisc.ops->flush_buffer) to->ldisc.ops->flush_buffer(to); - + if (to->packet) { spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status |= TIOCPKT_FLUSHWRITE; @@ -200,7 +197,7 @@ static void pty_flush_buffer(struct tty_struct *tty) } } -static int pty_open(struct tty_struct *tty, struct file *filp) +static int pty_open(struct tty_struct *tty, struct file * filp) { int retval = -ENODEV; @@ -223,65 +220,13 @@ static int pty_open(struct tty_struct *tty, struct file *filp) return retval; } -static void pty_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - tty->termios->c_cflag &= ~(CSIZE | PARENB); - tty->termios->c_cflag |= (CS8 | CREAD); -} - -static int pty_install(struct tty_driver *driver, struct tty_struct *tty) +static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct tty_struct *o_tty; - int idx = tty->index; - int retval; - - o_tty = alloc_tty_struct(); - if (!o_tty) - return -ENOMEM; - if (!try_module_get(driver->other->owner)) { - /* This cannot in fact currently happen */ - free_tty_struct(o_tty); - return -ENOMEM; - } - initialize_tty_struct(o_tty, driver->other, idx); - - /* We always use new tty termios data so we can do this - the easy way .. */ - retval = tty_init_termios(tty); - if (retval) - goto free_mem_out; - - retval = tty_init_termios(o_tty); - if (retval) { - tty_free_termios(tty); - goto free_mem_out; - } - - /* - * Everything allocated ... set up the o_tty structure. - */ - driver->other->ttys[idx] = o_tty; - tty_driver_kref_get(driver->other); - if (driver->subtype == PTY_TYPE_MASTER) - o_tty->count++; - /* Establish the links in both directions */ - tty->link = o_tty; - o_tty->link = tty; - - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[idx] = tty; - return 0; -free_mem_out: - module_put(o_tty->driver->owner); - free_tty_struct(o_tty); - return -ENOMEM; + tty->termios->c_cflag &= ~(CSIZE | PARENB); + tty->termios->c_cflag |= (CS8 | CREAD); } - static const struct tty_operations pty_ops = { - .install = pty_install, .open = pty_open, .close = pty_close, .write = pty_write, @@ -384,11 +329,8 @@ static inline void legacy_pty_init(void) { } * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. */ int pty_limit = NR_UNIX98_PTY_DEFAULT; -static int pty_limit_min; +static int pty_limit_min = 0; static int pty_limit_max = NR_UNIX98_PTY_MAX; -static int pty_count; - -static struct cdev ptmx_cdev; static struct ctl_table pty_table[] = { { @@ -406,7 +348,6 @@ static struct ctl_table pty_table[] = { .procname = "nr", .maxlen = sizeof(int), .mode = 0444, - .data = &pty_count, .proc_handler = &proc_dointvec, }, { .ctl_name = 0 @@ -447,127 +388,7 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } -/** - * ptm_unix98_lookup - find a pty master - * @driver: ptm driver - * @idx: tty index - * - * Look up a pty master device. Called under the tty_mutex for now. - * This provides our locking. - */ - -static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, - struct inode *ptm_inode, int idx) -{ - struct tty_struct *tty = devpts_get_tty(ptm_inode, idx); - if (tty) - tty = tty->link; - return tty; -} - -/** - * pts_unix98_lookup - find a pty slave - * @driver: pts driver - * @idx: tty index - * - * Look up a pty master device. Called under the tty_mutex for now. - * This provides our locking. - */ - -static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, - struct inode *pts_inode, int idx) -{ - struct tty_struct *tty = devpts_get_tty(pts_inode, idx); - /* Master must be open before slave */ - if (!tty) - return ERR_PTR(-EIO); - return tty; -} - -static void pty_unix98_shutdown(struct tty_struct *tty) -{ - /* We have our own method as we don't use the tty index */ - kfree(tty->termios); -} - -/* We have no need to install and remove our tty objects as devpts does all - the work for us */ - -static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) -{ - struct tty_struct *o_tty; - int idx = tty->index; - - o_tty = alloc_tty_struct(); - if (!o_tty) - return -ENOMEM; - if (!try_module_get(driver->other->owner)) { - /* This cannot in fact currently happen */ - free_tty_struct(o_tty); - return -ENOMEM; - } - initialize_tty_struct(o_tty, driver->other, idx); - - tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); - if (tty->termios == NULL) - goto free_mem_out; - *tty->termios = driver->init_termios; - tty->termios_locked = tty->termios + 1; - - o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); - if (o_tty->termios == NULL) - goto free_mem_out; - *o_tty->termios = driver->other->init_termios; - o_tty->termios_locked = o_tty->termios + 1; - - tty_driver_kref_get(driver->other); - if (driver->subtype == PTY_TYPE_MASTER) - o_tty->count++; - /* Establish the links in both directions */ - tty->link = o_tty; - o_tty->link = tty; - /* - * All structures have been allocated, so now we install them. - * Failures after this point use release_tty to clean up, so - * there's no need to null out the local pointers. - */ - tty_driver_kref_get(driver); - tty->count++; - pty_count++; - return 0; -free_mem_out: - kfree(o_tty->termios); - module_put(o_tty->driver->owner); - free_tty_struct(o_tty); - kfree(tty->termios); - return -ENOMEM; -} - -static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) -{ - pty_count--; -} - -static const struct tty_operations ptm_unix98_ops = { - .lookup = ptm_unix98_lookup, - .install = pty_unix98_install, - .remove = pty_unix98_remove, - .open = pty_open, - .close = pty_close, - .write = pty_write, - .write_room = pty_write_room, - .flush_buffer = pty_flush_buffer, - .chars_in_buffer = pty_chars_in_buffer, - .unthrottle = pty_unthrottle, - .set_termios = pty_set_termios, - .ioctl = pty_unix98_ioctl, - .shutdown = pty_unix98_shutdown -}; - static const struct tty_operations pty_unix98_ops = { - .lookup = pts_unix98_lookup, - .install = pty_unix98_install, - .remove = pty_unix98_remove, .open = pty_open, .close = pty_close, .write = pty_write, @@ -576,73 +397,9 @@ static const struct tty_operations pty_unix98_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, - .shutdown = pty_unix98_shutdown + .ioctl = pty_unix98_ioctl }; -/** - * ptmx_open - open a unix 98 pty master - * @inode: inode of device file - * @filp: file pointer to tty - * - * Allocate a unix98 pty master device from the ptmx driver. - * - * Locking: tty_mutex protects the init_dev work. tty->count should - * protect the rest. - * allocated_ptys_lock handles the list of free pty numbers - */ - -static int __ptmx_open(struct inode *inode, struct file *filp) -{ - struct tty_struct *tty; - int retval; - int index; - - nonseekable_open(inode, filp); - - /* find a device that is not in use. */ - index = devpts_new_index(inode); - if (index < 0) - return index; - - mutex_lock(&tty_mutex); - tty = tty_init_dev(ptm_driver, index, 1); - mutex_unlock(&tty_mutex); - - if (IS_ERR(tty)) { - retval = PTR_ERR(tty); - goto out; - } - - set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - filp->private_data = tty; - file_move(filp, &tty->tty_files); - - retval = devpts_pty_new(inode, tty->link); - if (retval) - goto out1; - - retval = ptm_driver->ops->open(tty, filp); - if (!retval) - return 0; -out1: - tty_release_dev(filp); - return retval; -out: - devpts_kill_index(inode, index); - return retval; -} - -static int ptmx_open(struct inode *inode, struct file *filp) -{ - int ret; - - lock_kernel(); - ret = __ptmx_open(inode, filp); - unlock_kernel(); - return ret; -} - -static struct file_operations ptmx_fops; static void __init unix98_pty_init(void) { @@ -670,7 +427,7 @@ static void __init unix98_pty_init(void) ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; ptm_driver->other = pts_driver; - tty_set_operations(ptm_driver, &ptm_unix98_ops); + tty_set_operations(ptm_driver, &pty_unix98_ops); pts_driver->owner = THIS_MODULE; pts_driver->driver_name = "pty_slave"; @@ -686,26 +443,16 @@ static void __init unix98_pty_init(void) pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; pts_driver->other = ptm_driver; - tty_set_operations(pts_driver, &pty_unix98_ops); - + tty_set_operations(pts_driver, &pty_ops); + if (tty_register_driver(ptm_driver)) panic("Couldn't register Unix98 ptm driver"); if (tty_register_driver(pts_driver)) panic("Couldn't register Unix98 pts driver"); + pty_table[1].data = &ptm_driver->refcount; register_sysctl_table(pty_root_table); - - /* Now create the /dev/ptmx special device */ - tty_default_fops(&ptmx_fops); - ptmx_fops.open = ptmx_open; - - cdev_init(&ptmx_cdev, &ptmx_fops); - if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || - register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) - panic("Couldn't register /dev/ptmx driver\n"); - device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); } - #else static inline void unix98_pty_init(void) { } #endif diff --git a/trunk/drivers/char/stallion.c b/trunk/drivers/char/stallion.c index 8b8f07a7f505..19db1eb87c26 100644 --- a/trunk/drivers/char/stallion.c +++ b/trunk/drivers/char/stallion.c @@ -405,9 +405,9 @@ static unsigned int stl_baudrates[] = { static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); static int stl_brdinit(struct stlbrd *brdp); -static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp); +static int stl_getportstats(struct stlport *portp, comstats_t __user *cp); static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp); -static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp); +static int stl_waitcarrier(struct stlport *portp, struct file *filp); /* * CD1400 uart specific handling functions. @@ -612,9 +612,8 @@ static struct class *stallion_class; static void stl_cd_change(struct stlport *portp) { unsigned int oldsigs = portp->sigs; - struct tty_struct *tty = tty_port_tty_get(&portp->port); - if (!tty) + if (!portp->port.tty) return; portp->sigs = stl_getsignals(portp); @@ -624,8 +623,7 @@ static void stl_cd_change(struct stlport *portp) if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) if (portp->port.flags & ASYNC_CHECK_CD) - tty_hangup(tty); - tty_kref_put(tty); + tty_hangup(portp->port.tty); } /* @@ -736,7 +734,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * On the first open of the device setup the port hardware, and * initialize the per port data structure. */ - tty_port_tty_set(&portp->port, tty); + portp->port.tty = tty; tty->driver_data = portp; portp->port.count++; @@ -776,7 +774,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * then also we might have to wait for carrier. */ if (!(filp->f_flags & O_NONBLOCK)) - if ((rc = stl_waitcarrier(tty, portp, filp)) != 0) + if ((rc = stl_waitcarrier(portp, filp)) != 0) return rc; portp->port.flags |= ASYNC_NORMAL_ACTIVE; @@ -791,8 +789,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * maybe because if we are clocal then we don't need to wait... */ -static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, - struct file *filp) +static int stl_waitcarrier(struct stlport *portp, struct file *filp) { unsigned long flags; int rc, doclocal; @@ -804,7 +801,7 @@ static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, spin_lock_irqsave(&stallion_lock, flags); - if (tty->termios->c_cflag & CLOCAL) + if (portp->port.tty->termios->c_cflag & CLOCAL) doclocal++; portp->openwaitcnt++; @@ -849,6 +846,8 @@ static void stl_flushbuffer(struct tty_struct *tty) pr_debug("stl_flushbuffer(tty=%p)\n", tty); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -866,6 +865,8 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -948,7 +949,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty->closing = 0; - tty_port_tty_set(&portp->port, NULL); + portp->port.tty = NULL; if (portp->openwaitcnt) { if (portp->close_delay) @@ -1032,6 +1033,8 @@ static int stl_putchar(struct tty_struct *tty, unsigned char ch) pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch); + if (tty == NULL) + return -EINVAL; portp = tty->driver_data; if (portp == NULL) return -EINVAL; @@ -1067,6 +1070,8 @@ static void stl_flushchars(struct tty_struct *tty) pr_debug("stl_flushchars(tty=%p)\n", tty); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1085,6 +1090,8 @@ static int stl_writeroom(struct tty_struct *tty) pr_debug("stl_writeroom(tty=%p)\n", tty); + if (tty == NULL) + return 0; portp = tty->driver_data; if (portp == NULL) return 0; @@ -1115,6 +1122,8 @@ static int stl_charsinbuffer(struct tty_struct *tty) pr_debug("stl_charsinbuffer(tty=%p)\n", tty); + if (tty == NULL) + return 0; portp = tty->driver_data; if (portp == NULL) return 0; @@ -1174,9 +1183,8 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) * just quietly ignore any requests to change irq, etc. */ -static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp) +static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) { - struct stlport * portp = tty->driver_data; struct serial_struct sio; pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp); @@ -1197,7 +1205,7 @@ static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp portp->close_delay = sio.close_delay; portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; - stl_setport(portp, tty->termios); + stl_setport(portp, portp->port.tty->termios); return 0; } @@ -1207,6 +1215,8 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file) { struct stlport *portp; + if (tty == NULL) + return -ENODEV; portp = tty->driver_data; if (portp == NULL) return -ENODEV; @@ -1222,6 +1232,8 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file, struct stlport *portp; int rts = -1, dtr = -1; + if (tty == NULL) + return -ENODEV; portp = tty->driver_data; if (portp == NULL) return -ENODEV; @@ -1250,6 +1262,8 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd, arg); + if (tty == NULL) + return -ENODEV; portp = tty->driver_data; if (portp == NULL) return -ENODEV; @@ -1268,10 +1282,10 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd rc = stl_getserial(portp, argp); break; case TIOCSSERIAL: - rc = stl_setserial(tty, argp); + rc = stl_setserial(portp, argp); break; case COM_GETPORTSTATS: - rc = stl_getportstats(tty, portp, argp); + rc = stl_getportstats(portp, argp); break; case COM_CLRPORTSTATS: rc = stl_clrportstats(portp, argp); @@ -1303,6 +1317,8 @@ static void stl_start(struct tty_struct *tty) pr_debug("stl_start(tty=%p)\n", tty); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1318,6 +1334,8 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old) pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1351,6 +1369,8 @@ static void stl_throttle(struct tty_struct *tty) pr_debug("stl_throttle(tty=%p)\n", tty); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1369,6 +1389,8 @@ static void stl_unthrottle(struct tty_struct *tty) pr_debug("stl_unthrottle(tty=%p)\n", tty); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1388,6 +1410,8 @@ static void stl_stop(struct tty_struct *tty) pr_debug("stl_stop(tty=%p)\n", tty); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1408,6 +1432,8 @@ static void stl_hangup(struct tty_struct *tty) pr_debug("stl_hangup(tty=%p)\n", tty); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1426,7 +1452,7 @@ static void stl_hangup(struct tty_struct *tty) portp->tx.head = NULL; portp->tx.tail = NULL; } - tty_port_tty_set(&portp->port, NULL); + portp->port.tty = NULL; portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; portp->port.count = 0; wake_up_interruptible(&portp->port.open_wait); @@ -1440,6 +1466,8 @@ static int stl_breakctl(struct tty_struct *tty, int state) pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state); + if (tty == NULL) + return -EINVAL; portp = tty->driver_data; if (portp == NULL) return -EINVAL; @@ -1456,6 +1484,8 @@ static void stl_sendxchar(struct tty_struct *tty, char ch) pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch); + if (tty == NULL) + return; portp = tty->driver_data; if (portp == NULL) return; @@ -1775,7 +1805,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) "(size=%Zd)\n", sizeof(struct stlport)); break; } - tty_port_init(&portp->port); + portp->magic = STL_PORTMAGIC; portp->portnr = i; portp->brdnr = panelp->brdnr; @@ -1802,7 +1832,6 @@ static void stl_cleanup_panels(struct stlbrd *brdp) struct stlpanel *panelp; struct stlport *portp; unsigned int j, k; - struct tty_struct *tty; for (j = 0; j < STL_MAXPANELS; j++) { panelp = brdp->panels[j]; @@ -1812,11 +1841,8 @@ static void stl_cleanup_panels(struct stlbrd *brdp) portp = panelp->ports[k]; if (portp == NULL) continue; - tty = tty_port_tty_get(&portp->port); - if (tty != NULL) { - stl_hangup(tty); - tty_kref_put(tty); - } + if (portp->port.tty != NULL) + stl_hangup(portp->port.tty); kfree(portp->tx.buf); kfree(portp); } @@ -2472,7 +2498,7 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr) * what port to get stats for (used through board control device). */ -static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp) +static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) { comstats_t stl_comstats; unsigned char *head, *tail; @@ -2499,17 +2525,18 @@ static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comst portp->stats.rxbuffered = 0; spin_lock_irqsave(&stallion_lock, flags); - if (tty != NULL && portp->port.tty == tty) { - portp->stats.ttystate = tty->flags; - /* No longer available as a statistic */ - portp->stats.rxbuffered = 1; /*tty->flip.count; */ - if (tty->termios != NULL) { - portp->stats.cflags = tty->termios->c_cflag; - portp->stats.iflags = tty->termios->c_iflag; - portp->stats.oflags = tty->termios->c_oflag; - portp->stats.lflags = tty->termios->c_lflag; + if (portp->port.tty != NULL) + if (portp->port.tty->driver_data == portp) { + portp->stats.ttystate = portp->port.tty->flags; + /* No longer available as a statistic */ + portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */ + if (portp->port.tty->termios != NULL) { + portp->stats.cflags = portp->port.tty->termios->c_cflag; + portp->stats.iflags = portp->port.tty->termios->c_iflag; + portp->stats.oflags = portp->port.tty->termios->c_oflag; + portp->stats.lflags = portp->port.tty->termios->c_lflag; + } } - } spin_unlock_irqrestore(&stallion_lock, flags); head = portp->tx.head; @@ -2613,7 +2640,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns switch (cmd) { case COM_GETPORTSTATS: - rc = stl_getportstats(NULL, NULL, argp); + rc = stl_getportstats(NULL, argp); break; case COM_CLRPORTSTATS: rc = stl_clrportstats(NULL, argp); @@ -3216,7 +3243,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -3261,7 +3288,6 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); - tty_kref_put(tty); } /*****************************************************************************/ @@ -3279,7 +3305,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -3299,7 +3325,6 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) } BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); - tty_kref_put(tty); } /*****************************************************************************/ @@ -3453,7 +3478,6 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) int len, stlen; char *head, *tail; unsigned char ioack, srer; - struct tty_struct *tty; pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr); @@ -3480,11 +3504,8 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - tty = tty_port_tty_get(&portp->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + if (portp->port.tty) + tty_wakeup(portp->port.tty); } if (len == 0) { @@ -3548,7 +3569,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) return; } portp = panelp->ports[(ioack >> 3)]; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { outb((RDCR + portp->uartaddr), ioaddr); @@ -3612,12 +3633,10 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) } } else { printk("STALLION: bad RX interrupt ack value=%x\n", ioack); - tty_kref_put(tty); return; } stl_rxalldone: - tty_kref_put(tty); outb((EOSRR + portp->uartaddr), ioaddr); outb(0, (ioaddr + EREG_DATA)); } @@ -4156,7 +4175,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -4207,7 +4226,6 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); - tty_kref_put(tty); } /*****************************************************************************/ @@ -4226,7 +4244,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; if (tty == NULL) return; @@ -4251,7 +4269,6 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) } BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); - tty_kref_put(tty); } /*****************************************************************************/ @@ -4391,7 +4408,6 @@ static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase) static void stl_sc26198txisr(struct stlport *portp) { - struct tty_struct *tty; unsigned int ioaddr; unsigned char mr0; int len, stlen; @@ -4406,11 +4422,8 @@ static void stl_sc26198txisr(struct stlport *portp) if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - tty = tty_port_tty_get(&portp->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + if (portp->port.tty) + tty_wakeup(portp->port.tty); } if (len == 0) { @@ -4463,7 +4476,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack); - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; ioaddr = portp->ioaddr; outb(GIBCR, (ioaddr + XP_ADDR)); len = inb(ioaddr + XP_DATA) + 1; @@ -4502,7 +4515,6 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) stl_sc26198txunflow(portp, tty); } } - tty_kref_put(tty); } /*****************************************************************************/ @@ -4516,7 +4528,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char struct tty_struct *tty; unsigned int ioaddr; - tty = tty_port_tty_get(&portp->port); + tty = portp->port.tty; ioaddr = portp->ioaddr; if (status & SR_RXPARITY) @@ -4554,7 +4566,6 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char if (status == 0) portp->stats.rxtotal++; } - tty_kref_put(tty); } /*****************************************************************************/ diff --git a/trunk/drivers/char/sx.c b/trunk/drivers/char/sx.c index 5b8d7a1aa3e6..c385206f9db5 100644 --- a/trunk/drivers/char/sx.c +++ b/trunk/drivers/char/sx.c @@ -2504,7 +2504,7 @@ static void __devexit sx_remove_card(struct sx_board *board, del_timer(&board->timer); if (pdev) { #ifdef CONFIG_PCI - pci_iounmap(pdev, board->base2); + pci_iounmap(pdev, board->base); pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2); #endif } else { @@ -2703,7 +2703,7 @@ static int __devinit sx_pci_probe(struct pci_dev *pdev, return 0; err_unmap: - pci_iounmap(pdev, board->base2); + pci_iounmap(pdev, board->base); err_reg: pci_release_region(pdev, reg); err_flag: diff --git a/trunk/drivers/char/tty_audit.c b/trunk/drivers/char/tty_audit.c index 5787249934c8..3582f43345a8 100644 --- a/trunk/drivers/char/tty_audit.c +++ b/trunk/drivers/char/tty_audit.c @@ -93,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, get_task_comm(name, tsk); audit_log_untrustedstring(ab, name); audit_log_format(ab, " data="); - audit_log_n_hex(ab, buf->data, buf->valid); + audit_log_n_untrustedstring(ab, buf->data, buf->valid); audit_log_end(ab); } buf->valid = 0; diff --git a/trunk/drivers/char/tty_buffer.c b/trunk/drivers/char/tty_buffer.c deleted file mode 100644 index 810ee25d66a4..000000000000 --- a/trunk/drivers/char/tty_buffer.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Tty buffer allocation management - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * tty_buffer_free_all - free buffers used by a tty - * @tty: tty to free from - * - * Remove all the buffers pending on a tty whether queued with data - * or in the free ring. Must be called when the tty is no longer in use - * - * Locking: none - */ - -void tty_buffer_free_all(struct tty_struct *tty) -{ - struct tty_buffer *thead; - while ((thead = tty->buf.head) != NULL) { - tty->buf.head = thead->next; - kfree(thead); - } - while ((thead = tty->buf.free) != NULL) { - tty->buf.free = thead->next; - kfree(thead); - } - tty->buf.tail = NULL; - tty->buf.memory_used = 0; -} - -/** - * tty_buffer_alloc - allocate a tty buffer - * @tty: tty device - * @size: desired size (characters) - * - * Allocate a new tty buffer to hold the desired number of characters. - * Return NULL if out of memory or the allocation would exceed the - * per device queue - * - * Locking: Caller must hold tty->buf.lock - */ - -static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) -{ - struct tty_buffer *p; - - if (tty->buf.memory_used + size > 65536) - return NULL; - p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); - if (p == NULL) - return NULL; - p->used = 0; - p->size = size; - p->next = NULL; - p->commit = 0; - p->read = 0; - p->char_buf_ptr = (char *)(p->data); - p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; - tty->buf.memory_used += size; - return p; -} - -/** - * tty_buffer_free - free a tty buffer - * @tty: tty owning the buffer - * @b: the buffer to free - * - * Free a tty buffer, or add it to the free list according to our - * internal strategy - * - * Locking: Caller must hold tty->buf.lock - */ - -static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) -{ - /* Dumb strategy for now - should keep some stats */ - tty->buf.memory_used -= b->size; - WARN_ON(tty->buf.memory_used < 0); - - if (b->size >= 512) - kfree(b); - else { - b->next = tty->buf.free; - tty->buf.free = b; - } -} - -/** - * __tty_buffer_flush - flush full tty buffers - * @tty: tty to flush - * - * flush all the buffers containing receive data. Caller must - * hold the buffer lock and must have ensured no parallel flush to - * ldisc is running. - * - * Locking: Caller must hold tty->buf.lock - */ - -static void __tty_buffer_flush(struct tty_struct *tty) -{ - struct tty_buffer *thead; - - while ((thead = tty->buf.head) != NULL) { - tty->buf.head = thead->next; - tty_buffer_free(tty, thead); - } - tty->buf.tail = NULL; -} - -/** - * tty_buffer_flush - flush full tty buffers - * @tty: tty to flush - * - * flush all the buffers containing receive data. If the buffer is - * being processed by flush_to_ldisc then we defer the processing - * to that function - * - * Locking: none - */ - -void tty_buffer_flush(struct tty_struct *tty) -{ - unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); - - /* If the data is being pushed to the tty layer then we can't - process it here. Instead set a flag and the flush_to_ldisc - path will process the flush request before it exits */ - if (test_bit(TTY_FLUSHING, &tty->flags)) { - set_bit(TTY_FLUSHPENDING, &tty->flags); - spin_unlock_irqrestore(&tty->buf.lock, flags); - wait_event(tty->read_wait, - test_bit(TTY_FLUSHPENDING, &tty->flags) == 0); - return; - } else - __tty_buffer_flush(tty); - spin_unlock_irqrestore(&tty->buf.lock, flags); -} - -/** - * tty_buffer_find - find a free tty buffer - * @tty: tty owning the buffer - * @size: characters wanted - * - * Locate an existing suitable tty buffer or if we are lacking one then - * allocate a new one. We round our buffers off in 256 character chunks - * to get better allocation behaviour. - * - * Locking: Caller must hold tty->buf.lock - */ - -static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) -{ - struct tty_buffer **tbh = &tty->buf.free; - while ((*tbh) != NULL) { - struct tty_buffer *t = *tbh; - if (t->size >= size) { - *tbh = t->next; - t->next = NULL; - t->used = 0; - t->commit = 0; - t->read = 0; - tty->buf.memory_used += t->size; - return t; - } - tbh = &((*tbh)->next); - } - /* Round the buffer size out */ - size = (size + 0xFF) & ~0xFF; - return tty_buffer_alloc(tty, size); - /* Should possibly check if this fails for the largest buffer we - have queued and recycle that ? */ -} - -/** - * tty_buffer_request_room - grow tty buffer if needed - * @tty: tty structure - * @size: size desired - * - * Make at least size bytes of linear space available for the tty - * buffer. If we fail return the size we managed to find. - * - * Locking: Takes tty->buf.lock - */ -int tty_buffer_request_room(struct tty_struct *tty, size_t size) -{ - struct tty_buffer *b, *n; - int left; - unsigned long flags; - - spin_lock_irqsave(&tty->buf.lock, flags); - - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to - remove this conditional if its worth it. This would be invisible - to the callers */ - if ((b = tty->buf.tail) != NULL) - left = b->size - b->used; - else - left = 0; - - if (left < size) { - /* This is the slow path - looking for new buffers to use */ - if ((n = tty_buffer_find(tty, size)) != NULL) { - if (b != NULL) { - b->next = n; - b->commit = b->used; - } else - tty->buf.head = n; - tty->buf.tail = n; - } else - size = left; - } - - spin_unlock_irqrestore(&tty->buf.lock, flags); - return size; -} -EXPORT_SYMBOL_GPL(tty_buffer_request_room); - -/** - * tty_insert_flip_string - Add characters to the tty buffer - * @tty: tty structure - * @chars: characters - * @size: size - * - * Queue a series of bytes to the tty buffering. All the characters - * passed are marked as without error. Returns the number added. - * - * Locking: Called functions may take tty->buf.lock - */ - -int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, - size_t size) -{ - int copied = 0; - do { - int space = tty_buffer_request_room(tty, size - copied); - struct tty_buffer *tb = tty->buf.tail; - /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) - break; - memcpy(tb->char_buf_ptr + tb->used, chars, space); - memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); - tb->used += space; - copied += space; - chars += space; - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - } while (unlikely(size > copied)); - return copied; -} -EXPORT_SYMBOL(tty_insert_flip_string); - -/** - * tty_insert_flip_string_flags - Add characters to the tty buffer - * @tty: tty structure - * @chars: characters - * @flags: flag bytes - * @size: size - * - * Queue a series of bytes to the tty buffering. For each character - * the flags array indicates the status of the character. Returns the - * number added. - * - * Locking: Called functions may take tty->buf.lock - */ - -int tty_insert_flip_string_flags(struct tty_struct *tty, - const unsigned char *chars, const char *flags, size_t size) -{ - int copied = 0; - do { - int space = tty_buffer_request_room(tty, size - copied); - struct tty_buffer *tb = tty->buf.tail; - /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) - break; - memcpy(tb->char_buf_ptr + tb->used, chars, space); - memcpy(tb->flag_buf_ptr + tb->used, flags, space); - tb->used += space; - copied += space; - chars += space; - flags += space; - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - } while (unlikely(size > copied)); - return copied; -} -EXPORT_SYMBOL(tty_insert_flip_string_flags); - -/** - * tty_schedule_flip - push characters to ldisc - * @tty: tty to push from - * - * Takes any pending buffers and transfers their ownership to the - * ldisc side of the queue. It then schedules those characters for - * processing by the line discipline. - * - * Locking: Takes tty->buf.lock - */ - -void tty_schedule_flip(struct tty_struct *tty) -{ - unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); - if (tty->buf.tail != NULL) - tty->buf.tail->commit = tty->buf.tail->used; - spin_unlock_irqrestore(&tty->buf.lock, flags); - schedule_delayed_work(&tty->buf.work, 1); -} -EXPORT_SYMBOL(tty_schedule_flip); - -/** - * tty_prepare_flip_string - make room for characters - * @tty: tty - * @chars: return pointer for character write area - * @size: desired size - * - * Prepare a block of space in the buffer for data. Returns the length - * available and buffer pointer to the space which is now allocated and - * accounted for as ready for normal characters. This is used for drivers - * that need their own block copy routines into the buffer. There is no - * guarantee the buffer is a DMA target! - * - * Locking: May call functions taking tty->buf.lock - */ - -int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, - size_t size) -{ - int space = tty_buffer_request_room(tty, size); - if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; - *chars = tb->char_buf_ptr + tb->used; - memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); - tb->used += space; - } - return space; -} -EXPORT_SYMBOL_GPL(tty_prepare_flip_string); - -/** - * tty_prepare_flip_string_flags - make room for characters - * @tty: tty - * @chars: return pointer for character write area - * @flags: return pointer for status flag write area - * @size: desired size - * - * Prepare a block of space in the buffer for data. Returns the length - * available and buffer pointer to the space which is now allocated and - * accounted for as ready for characters. This is used for drivers - * that need their own block copy routines into the buffer. There is no - * guarantee the buffer is a DMA target! - * - * Locking: May call functions taking tty->buf.lock - */ - -int tty_prepare_flip_string_flags(struct tty_struct *tty, - unsigned char **chars, char **flags, size_t size) -{ - int space = tty_buffer_request_room(tty, size); - if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; - *chars = tb->char_buf_ptr + tb->used; - *flags = tb->flag_buf_ptr + tb->used; - tb->used += space; - } - return space; -} -EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); - - - -/** - * flush_to_ldisc - * @work: tty structure passed from work queue. - * - * This routine is called out of the software interrupt to flush data - * from the buffer chain to the line discipline. - * - * Locking: holds tty->buf.lock to guard buffer list. Drops the lock - * while invoking the line discipline receive_buf method. The - * receive_buf method is single threaded for each tty instance. - */ - -static void flush_to_ldisc(struct work_struct *work) -{ - struct tty_struct *tty = - container_of(work, struct tty_struct, buf.work.work); - unsigned long flags; - struct tty_ldisc *disc; - struct tty_buffer *tbuf, *head; - char *char_buf; - unsigned char *flag_buf; - - disc = tty_ldisc_ref(tty); - if (disc == NULL) /* !TTY_LDISC */ - return; - - spin_lock_irqsave(&tty->buf.lock, flags); - /* So we know a flush is running */ - set_bit(TTY_FLUSHING, &tty->flags); - head = tty->buf.head; - if (head != NULL) { - tty->buf.head = NULL; - for (;;) { - int count = head->commit - head->read; - if (!count) { - if (head->next == NULL) - break; - tbuf = head; - head = head->next; - tty_buffer_free(tty, tbuf); - continue; - } - /* Ldisc or user is trying to flush the buffers - we are feeding to the ldisc, stop feeding the - line discipline as we want to empty the queue */ - if (test_bit(TTY_FLUSHPENDING, &tty->flags)) - break; - if (!tty->receive_room) { - schedule_delayed_work(&tty->buf.work, 1); - break; - } - if (count > tty->receive_room) - count = tty->receive_room; - char_buf = head->char_buf_ptr + head->read; - flag_buf = head->flag_buf_ptr + head->read; - head->read += count; - spin_unlock_irqrestore(&tty->buf.lock, flags); - disc->ops->receive_buf(tty, char_buf, - flag_buf, count); - spin_lock_irqsave(&tty->buf.lock, flags); - } - /* Restore the queue head */ - tty->buf.head = head; - } - /* We may have a deferred request to flush the input buffer, - if so pull the chain under the lock and empty the queue */ - if (test_bit(TTY_FLUSHPENDING, &tty->flags)) { - __tty_buffer_flush(tty); - clear_bit(TTY_FLUSHPENDING, &tty->flags); - wake_up(&tty->read_wait); - } - clear_bit(TTY_FLUSHING, &tty->flags); - spin_unlock_irqrestore(&tty->buf.lock, flags); - - tty_ldisc_deref(disc); -} - -/** - * tty_flip_buffer_push - terminal - * @tty: tty to push - * - * Queue a push of the terminal flip buffers to the line discipline. This - * function must not be called from IRQ context if tty->low_latency is set. - * - * In the event of the queue being busy for flipping the work will be - * held off and retried later. - * - * Locking: tty buffer lock. Driver locks in low latency mode. - */ - -void tty_flip_buffer_push(struct tty_struct *tty) -{ - unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); - if (tty->buf.tail != NULL) - tty->buf.tail->commit = tty->buf.tail->used; - spin_unlock_irqrestore(&tty->buf.lock, flags); - - if (tty->low_latency) - flush_to_ldisc(&tty->buf.work.work); - else - schedule_delayed_work(&tty->buf.work, 1); -} -EXPORT_SYMBOL(tty_flip_buffer_push); - -/** - * tty_buffer_init - prepare a tty buffer structure - * @tty: tty to initialise - * - * Set up the initial state of the buffer management for a tty device. - * Must be called before the other tty buffer functions are used. - * - * Locking: none - */ - -void tty_buffer_init(struct tty_struct *tty) -{ - spin_lock_init(&tty->buf.lock); - tty->buf.head = NULL; - tty->buf.tail = NULL; - tty->buf.free = NULL; - tty->buf.memory_used = 0; - INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); -} - diff --git a/trunk/drivers/char/tty_io.c b/trunk/drivers/char/tty_io.c index 7053d6333692..e4dce8709541 100644 --- a/trunk/drivers/char/tty_io.c +++ b/trunk/drivers/char/tty_io.c @@ -49,7 +49,7 @@ * implement CONFIG_VT and generalize console device interface. * -- Marko Kohtala , March 97 * - * Rewrote tty_init_dev and tty_release_dev to eliminate races. + * Rewrote init_dev and release_dev to eliminate races. * -- Bill Hawes , June 97 * * Added devfs support. @@ -136,6 +136,13 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ DEFINE_MUTEX(tty_mutex); EXPORT_SYMBOL(tty_mutex); +#ifdef CONFIG_UNIX98_PTYS +extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ +static int ptmx_open(struct inode *, struct file *); +#endif + +static void initialize_tty_struct(struct tty_struct *tty); + static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); ssize_t redirected_tty_write(struct file *, const char __user *, @@ -164,11 +171,13 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); * Locking: none */ -struct tty_struct *alloc_tty_struct(void) +static struct tty_struct *alloc_tty_struct(void) { return kzalloc(sizeof(struct tty_struct), GFP_KERNEL); } +static void tty_buffer_free_all(struct tty_struct *); + /** * free_tty_struct - free a disused tty * @tty: tty struct to free @@ -178,7 +187,7 @@ struct tty_struct *alloc_tty_struct(void) * Locking: none. Must be called after tty is definitely unused */ -void free_tty_struct(struct tty_struct *tty) +static inline void free_tty_struct(struct tty_struct *tty) { kfree(tty->write_buf); tty_buffer_free_all(tty); @@ -254,6 +263,398 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) return 0; } +/* + * Tty buffer allocation management + */ + +/** + * tty_buffer_free_all - free buffers used by a tty + * @tty: tty to free from + * + * Remove all the buffers pending on a tty whether queued with data + * or in the free ring. Must be called when the tty is no longer in use + * + * Locking: none + */ + +static void tty_buffer_free_all(struct tty_struct *tty) +{ + struct tty_buffer *thead; + while ((thead = tty->buf.head) != NULL) { + tty->buf.head = thead->next; + kfree(thead); + } + while ((thead = tty->buf.free) != NULL) { + tty->buf.free = thead->next; + kfree(thead); + } + tty->buf.tail = NULL; + tty->buf.memory_used = 0; +} + +/** + * tty_buffer_init - prepare a tty buffer structure + * @tty: tty to initialise + * + * Set up the initial state of the buffer management for a tty device. + * Must be called before the other tty buffer functions are used. + * + * Locking: none + */ + +static void tty_buffer_init(struct tty_struct *tty) +{ + spin_lock_init(&tty->buf.lock); + tty->buf.head = NULL; + tty->buf.tail = NULL; + tty->buf.free = NULL; + tty->buf.memory_used = 0; +} + +/** + * tty_buffer_alloc - allocate a tty buffer + * @tty: tty device + * @size: desired size (characters) + * + * Allocate a new tty buffer to hold the desired number of characters. + * Return NULL if out of memory or the allocation would exceed the + * per device queue + * + * Locking: Caller must hold tty->buf.lock + */ + +static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) +{ + struct tty_buffer *p; + + if (tty->buf.memory_used + size > 65536) + return NULL; + p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); + if (p == NULL) + return NULL; + p->used = 0; + p->size = size; + p->next = NULL; + p->commit = 0; + p->read = 0; + p->char_buf_ptr = (char *)(p->data); + p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; + tty->buf.memory_used += size; + return p; +} + +/** + * tty_buffer_free - free a tty buffer + * @tty: tty owning the buffer + * @b: the buffer to free + * + * Free a tty buffer, or add it to the free list according to our + * internal strategy + * + * Locking: Caller must hold tty->buf.lock + */ + +static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) +{ + /* Dumb strategy for now - should keep some stats */ + tty->buf.memory_used -= b->size; + WARN_ON(tty->buf.memory_used < 0); + + if (b->size >= 512) + kfree(b); + else { + b->next = tty->buf.free; + tty->buf.free = b; + } +} + +/** + * __tty_buffer_flush - flush full tty buffers + * @tty: tty to flush + * + * flush all the buffers containing receive data. Caller must + * hold the buffer lock and must have ensured no parallel flush to + * ldisc is running. + * + * Locking: Caller must hold tty->buf.lock + */ + +static void __tty_buffer_flush(struct tty_struct *tty) +{ + struct tty_buffer *thead; + + while ((thead = tty->buf.head) != NULL) { + tty->buf.head = thead->next; + tty_buffer_free(tty, thead); + } + tty->buf.tail = NULL; +} + +/** + * tty_buffer_flush - flush full tty buffers + * @tty: tty to flush + * + * flush all the buffers containing receive data. If the buffer is + * being processed by flush_to_ldisc then we defer the processing + * to that function + * + * Locking: none + */ + +static void tty_buffer_flush(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + + /* If the data is being pushed to the tty layer then we can't + process it here. Instead set a flag and the flush_to_ldisc + path will process the flush request before it exits */ + if (test_bit(TTY_FLUSHING, &tty->flags)) { + set_bit(TTY_FLUSHPENDING, &tty->flags); + spin_unlock_irqrestore(&tty->buf.lock, flags); + wait_event(tty->read_wait, + test_bit(TTY_FLUSHPENDING, &tty->flags) == 0); + return; + } else + __tty_buffer_flush(tty); + spin_unlock_irqrestore(&tty->buf.lock, flags); +} + +/** + * tty_buffer_find - find a free tty buffer + * @tty: tty owning the buffer + * @size: characters wanted + * + * Locate an existing suitable tty buffer or if we are lacking one then + * allocate a new one. We round our buffers off in 256 character chunks + * to get better allocation behaviour. + * + * Locking: Caller must hold tty->buf.lock + */ + +static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) +{ + struct tty_buffer **tbh = &tty->buf.free; + while ((*tbh) != NULL) { + struct tty_buffer *t = *tbh; + if (t->size >= size) { + *tbh = t->next; + t->next = NULL; + t->used = 0; + t->commit = 0; + t->read = 0; + tty->buf.memory_used += t->size; + return t; + } + tbh = &((*tbh)->next); + } + /* Round the buffer size out */ + size = (size + 0xFF) & ~0xFF; + return tty_buffer_alloc(tty, size); + /* Should possibly check if this fails for the largest buffer we + have queued and recycle that ? */ +} + +/** + * tty_buffer_request_room - grow tty buffer if needed + * @tty: tty structure + * @size: size desired + * + * Make at least size bytes of linear space available for the tty + * buffer. If we fail return the size we managed to find. + * + * Locking: Takes tty->buf.lock + */ +int tty_buffer_request_room(struct tty_struct *tty, size_t size) +{ + struct tty_buffer *b, *n; + int left; + unsigned long flags; + + spin_lock_irqsave(&tty->buf.lock, flags); + + /* OPTIMISATION: We could keep a per tty "zero" sized buffer to + remove this conditional if its worth it. This would be invisible + to the callers */ + if ((b = tty->buf.tail) != NULL) + left = b->size - b->used; + else + left = 0; + + if (left < size) { + /* This is the slow path - looking for new buffers to use */ + if ((n = tty_buffer_find(tty, size)) != NULL) { + if (b != NULL) { + b->next = n; + b->commit = b->used; + } else + tty->buf.head = n; + tty->buf.tail = n; + } else + size = left; + } + + spin_unlock_irqrestore(&tty->buf.lock, flags); + return size; +} +EXPORT_SYMBOL_GPL(tty_buffer_request_room); + +/** + * tty_insert_flip_string - Add characters to the tty buffer + * @tty: tty structure + * @chars: characters + * @size: size + * + * Queue a series of bytes to the tty buffering. All the characters + * passed are marked as without error. Returns the number added. + * + * Locking: Called functions may take tty->buf.lock + */ + +int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, + size_t size) +{ + int copied = 0; + do { + int space = tty_buffer_request_room(tty, size - copied); + struct tty_buffer *tb = tty->buf.tail; + /* If there is no space then tb may be NULL */ + if (unlikely(space == 0)) + break; + memcpy(tb->char_buf_ptr + tb->used, chars, space); + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); + tb->used += space; + copied += space; + chars += space; + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + } while (unlikely(size > copied)); + return copied; +} +EXPORT_SYMBOL(tty_insert_flip_string); + +/** + * tty_insert_flip_string_flags - Add characters to the tty buffer + * @tty: tty structure + * @chars: characters + * @flags: flag bytes + * @size: size + * + * Queue a series of bytes to the tty buffering. For each character + * the flags array indicates the status of the character. Returns the + * number added. + * + * Locking: Called functions may take tty->buf.lock + */ + +int tty_insert_flip_string_flags(struct tty_struct *tty, + const unsigned char *chars, const char *flags, size_t size) +{ + int copied = 0; + do { + int space = tty_buffer_request_room(tty, size - copied); + struct tty_buffer *tb = tty->buf.tail; + /* If there is no space then tb may be NULL */ + if (unlikely(space == 0)) + break; + memcpy(tb->char_buf_ptr + tb->used, chars, space); + memcpy(tb->flag_buf_ptr + tb->used, flags, space); + tb->used += space; + copied += space; + chars += space; + flags += space; + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + } while (unlikely(size > copied)); + return copied; +} +EXPORT_SYMBOL(tty_insert_flip_string_flags); + +/** + * tty_schedule_flip - push characters to ldisc + * @tty: tty to push from + * + * Takes any pending buffers and transfers their ownership to the + * ldisc side of the queue. It then schedules those characters for + * processing by the line discipline. + * + * Locking: Takes tty->buf.lock + */ + +void tty_schedule_flip(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + if (tty->buf.tail != NULL) + tty->buf.tail->commit = tty->buf.tail->used; + spin_unlock_irqrestore(&tty->buf.lock, flags); + schedule_delayed_work(&tty->buf.work, 1); +} +EXPORT_SYMBOL(tty_schedule_flip); + +/** + * tty_prepare_flip_string - make room for characters + * @tty: tty + * @chars: return pointer for character write area + * @size: desired size + * + * Prepare a block of space in the buffer for data. Returns the length + * available and buffer pointer to the space which is now allocated and + * accounted for as ready for normal characters. This is used for drivers + * that need their own block copy routines into the buffer. There is no + * guarantee the buffer is a DMA target! + * + * Locking: May call functions taking tty->buf.lock + */ + +int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, + size_t size) +{ + int space = tty_buffer_request_room(tty, size); + if (likely(space)) { + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); + tb->used += space; + } + return space; +} + +EXPORT_SYMBOL_GPL(tty_prepare_flip_string); + +/** + * tty_prepare_flip_string_flags - make room for characters + * @tty: tty + * @chars: return pointer for character write area + * @flags: return pointer for status flag write area + * @size: desired size + * + * Prepare a block of space in the buffer for data. Returns the length + * available and buffer pointer to the space which is now allocated and + * accounted for as ready for characters. This is used for drivers + * that need their own block copy routines into the buffer. There is no + * guarantee the buffer is a DMA target! + * + * Locking: May call functions taking tty->buf.lock + */ + +int tty_prepare_flip_string_flags(struct tty_struct *tty, + unsigned char **chars, char **flags, size_t size) +{ + int space = tty_buffer_request_room(tty, size); + if (likely(space)) { + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + *flags = tb->flag_buf_ptr + tb->used; + tb->used += space; + } + return space; +} + +EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); + + + /** * get_tty_driver - find device of a tty * @dev_t: device identifier @@ -274,7 +675,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) if (device < base || device >= base + p->num) continue; *index = device - base; - return tty_driver_kref_get(p); + return p; } return NULL; } @@ -318,7 +719,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) if (tty_line >= 0 && tty_line <= p->num && p->ops && p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) { - res = tty_driver_kref_get(p); + res = p; *line = tty_line; break; } @@ -418,6 +819,20 @@ static const struct file_operations tty_fops = { .fasync = tty_fasync, }; +#ifdef CONFIG_UNIX98_PTYS +static const struct file_operations ptmx_fops = { + .llseek = no_llseek, + .read = tty_read, + .write = tty_write, + .poll = tty_poll, + .unlocked_ioctl = tty_ioctl, + .compat_ioctl = tty_compat_ioctl, + .open = ptmx_open, + .release = tty_release, + .fasync = tty_fasync, +}; +#endif + static const struct file_operations console_fops = { .llseek = no_llseek, .read = tty_read, @@ -538,7 +953,6 @@ static void do_tty_hangup(struct work_struct *work) struct tty_ldisc *ld; int closecount = 0, n; unsigned long flags; - int refs = 0; if (!tty) return; @@ -605,12 +1019,8 @@ static void do_tty_hangup(struct work_struct *work) if (tty->session) { do_each_pid_task(tty->session, PIDTYPE_SID, p) { spin_lock_irq(&p->sighand->siglock); - if (p->signal->tty == tty) { + if (p->signal->tty == tty) p->signal->tty = NULL; - /* We defer the dereferences outside fo - the tasklist lock */ - refs++; - } if (!p->signal->leader) { spin_unlock_irq(&p->sighand->siglock); continue; @@ -636,10 +1046,6 @@ static void do_tty_hangup(struct work_struct *work) tty->ctrl_status = 0; spin_unlock_irqrestore(&tty->ctrl_lock, flags); - /* Account for the p->signal references we killed */ - while (refs--) - tty_kref_put(tty); - /* * If one of the devices matches a console pointer, we * cannot just call hangup() because that will cause @@ -708,23 +1114,6 @@ void tty_vhangup(struct tty_struct *tty) EXPORT_SYMBOL(tty_vhangup); -/** - * tty_vhangup_self - process vhangup for own ctty - * - * Perform a vhangup on the current controlling tty - */ - -void tty_vhangup_self(void) -{ - struct tty_struct *tty; - - tty = get_current_tty(); - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } -} - /** * tty_hung_up_p - was tty hung up * @filp: file pointer of tty @@ -778,14 +1167,16 @@ void disassociate_ctty(int on_exit) struct pid *tty_pgrp = NULL; + mutex_lock(&tty_mutex); tty = get_current_tty(); if (tty) { tty_pgrp = get_pid(tty->pgrp); lock_kernel(); + mutex_unlock(&tty_mutex); + /* XXX: here we race, there is nothing protecting tty */ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); unlock_kernel(); - tty_kref_put(tty); } else if (on_exit) { struct pid *old_pgrp; spin_lock_irq(¤t->sighand->siglock); @@ -797,6 +1188,7 @@ void disassociate_ctty(int on_exit) kill_pgrp(old_pgrp, SIGCONT, on_exit); put_pid(old_pgrp); } + mutex_unlock(&tty_mutex); return; } if (tty_pgrp) { @@ -811,6 +1203,8 @@ void disassociate_ctty(int on_exit) current->signal->tty_old_pgrp = NULL; spin_unlock_irq(¤t->sighand->siglock); + mutex_lock(&tty_mutex); + /* It is possible that do_tty_hangup has free'd this tty */ tty = get_current_tty(); if (tty) { unsigned long flags; @@ -820,13 +1214,13 @@ void disassociate_ctty(int on_exit) tty->session = NULL; tty->pgrp = NULL; spin_unlock_irqrestore(&tty->ctrl_lock, flags); - tty_kref_put(tty); } else { #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "error attempted to write to tty [0x%p]" " = NULL", tty); #endif } + mutex_unlock(&tty_mutex); /* Now clear signal->tty under the lock */ read_lock(&tasklist_lock); @@ -1026,19 +1420,19 @@ static inline ssize_t do_tty_write( /* write_buf/write_cnt is protected by the atomic_write_lock mutex */ if (tty->write_cnt < chunk) { - unsigned char *buf_chunk; + unsigned char *buf; if (chunk < 1024) chunk = 1024; - buf_chunk = kmalloc(chunk, GFP_KERNEL); - if (!buf_chunk) { + buf = kmalloc(chunk, GFP_KERNEL); + if (!buf) { ret = -ENOMEM; goto out; } kfree(tty->write_buf); tty->write_cnt = chunk; - tty->write_buf = buf_chunk; + tty->write_buf = buf; } /* Do the write .. */ @@ -1072,31 +1466,6 @@ static inline ssize_t do_tty_write( return ret; } -/** - * tty_write_message - write a message to a certain tty, not just the console. - * @tty: the destination tty_struct - * @msg: the message to write - * - * This is used for messages that need to be redirected to a specific tty. - * We don't put it into the syslog queue right now maybe in the future if - * really needed. - * - * We must still hold the BKL and test the CLOSING flag for the moment. - */ - -void tty_write_message(struct tty_struct *tty, char *msg) -{ - lock_kernel(); - if (tty) { - mutex_lock(&tty->atomic_write_lock); - if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) - tty->ops->write(tty, msg, strlen(msg)); - tty_write_unlock(tty); - } - unlock_kernel(); - return; -} - /** * tty_write - write method for tty device file @@ -1164,6 +1533,42 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf, return tty_write(file, buf, count, ppos); } +void tty_port_init(struct tty_port *port) +{ + memset(port, 0, sizeof(*port)); + init_waitqueue_head(&port->open_wait); + init_waitqueue_head(&port->close_wait); + mutex_init(&port->mutex); + port->close_delay = (50 * HZ) / 100; + port->closing_wait = (3000 * HZ) / 100; +} +EXPORT_SYMBOL(tty_port_init); + +int tty_port_alloc_xmit_buf(struct tty_port *port) +{ + /* We may sleep in get_zeroed_page() */ + mutex_lock(&port->mutex); + if (port->xmit_buf == NULL) + port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); + mutex_unlock(&port->mutex); + if (port->xmit_buf == NULL) + return -ENOMEM; + return 0; +} +EXPORT_SYMBOL(tty_port_alloc_xmit_buf); + +void tty_port_free_xmit_buf(struct tty_port *port) +{ + mutex_lock(&port->mutex); + if (port->xmit_buf != NULL) { + free_page((unsigned long)port->xmit_buf); + port->xmit_buf = NULL; + } + mutex_unlock(&port->mutex); +} +EXPORT_SYMBOL(tty_port_free_xmit_buf); + + static char ptychar[] = "pqrstuvwxyzabcde"; /** @@ -1187,7 +1592,7 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) } /** - * tty_line_name - generate name for a tty + * pty_line_name - generate name for a tty * @driver: the tty driver in use * @index: the minor number * @p: output buffer of at least 7 bytes @@ -1199,152 +1604,14 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) */ static void tty_line_name(struct tty_driver *driver, int index, char *p) { - sprintf(p, "%s%d", driver->name, index + driver->name_base); -} - -/** - * tty_driver_lookup_tty() - find an existing tty, if any - * @driver: the driver for the tty - * @idx: the minor number - * - * Return the tty, if found or ERR_PTR() otherwise. - * - * Locking: tty_mutex must be held. If tty is found, the mutex must - * be held until the 'fast-open' is also done. Will change once we - * have refcounting in the driver and per driver locking - */ -struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, - struct inode *inode, int idx) -{ - struct tty_struct *tty; - - if (driver->ops->lookup) - return driver->ops->lookup(driver, inode, idx); - - tty = driver->ttys[idx]; - return tty; -} - -/** - * tty_init_termios - helper for termios setup - * @tty: the tty to set up - * - * Initialise the termios structures for this tty. Thus runs under - * the tty_mutex currently so we can be relaxed about ordering. - */ - -int tty_init_termios(struct tty_struct *tty) -{ - struct ktermios *tp; - int idx = tty->index; - - tp = tty->driver->termios[idx]; - if (tp == NULL) { - tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); - if (tp == NULL) - return -ENOMEM; - memcpy(tp, &tty->driver->init_termios, - sizeof(struct ktermios)); - tty->driver->termios[idx] = tp; - } - tty->termios = tp; - tty->termios_locked = tp + 1; - - /* Compatibility until drivers always set this */ - tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); - tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); - return 0; -} - -/** - * tty_driver_install_tty() - install a tty entry in the driver - * @driver: the driver for the tty - * @tty: the tty - * - * Install a tty object into the driver tables. The tty->index field - * will be set by the time this is called. This method is responsible - * for ensuring any need additional structures are allocated and - * configured. - * - * Locking: tty_mutex for now - */ -static int tty_driver_install_tty(struct tty_driver *driver, - struct tty_struct *tty) -{ - int idx = tty->index; - - if (driver->ops->install) - return driver->ops->install(driver, tty); - - if (tty_init_termios(tty) == 0) { - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[idx] = tty; - return 0; - } - return -ENOMEM; -} - -/** - * tty_driver_remove_tty() - remove a tty from the driver tables - * @driver: the driver for the tty - * @idx: the minor number - * - * Remvoe a tty object from the driver tables. The tty->index field - * will be set by the time this is called. - * - * Locking: tty_mutex for now - */ -static void tty_driver_remove_tty(struct tty_driver *driver, - struct tty_struct *tty) -{ - if (driver->ops->remove) - driver->ops->remove(driver, tty); - else - driver->ttys[tty->index] = NULL; -} - -/* - * tty_reopen() - fast re-open of an open tty - * @tty - the tty to open - * - * Return 0 on success, -errno on error. - * - * Locking: tty_mutex must be held from the time the tty was found - * till this open completes. - */ -static int tty_reopen(struct tty_struct *tty) -{ - struct tty_driver *driver = tty->driver; - - if (test_bit(TTY_CLOSING, &tty->flags)) - return -EIO; - - if (driver->type == TTY_DRIVER_TYPE_PTY && - driver->subtype == PTY_TYPE_MASTER) { - /* - * special case for PTY masters: only one open permitted, - * and the slave side open count is incremented as well. - */ - if (tty->count) - return -EIO; - - tty->link->count++; - } - tty->count++; - tty->driver = driver; /* N.B. why do this every time?? */ - - WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); - - return 0; + sprintf(p, "%s%d", driver->name, index + driver->name_base); } /** - * tty_init_dev - initialise a tty device + * init_dev - initialise a tty device * @driver: tty driver we are opening a device on * @idx: device index - * @ret_tty: returned tty structure - * @first_ok: ok to open a new device (used by ptmx) + * @tty: returned tty structure * * Prepare a tty device. This may not be a "new" clean device but * could also be an active device. The pty drivers require special @@ -1364,16 +1631,37 @@ static int tty_reopen(struct tty_struct *tty) * relaxed for the (most common) case of reopening a tty. */ -struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, - int first_ok) +static int init_dev(struct tty_driver *driver, int idx, + struct tty_struct **ret_tty) { - struct tty_struct *tty; - int retval; + struct tty_struct *tty, *o_tty; + struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc; + struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; + int retval = 0; - /* Check if pty master is being opened multiple times */ - if (driver->subtype == PTY_TYPE_MASTER && - (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) - return ERR_PTR(-EIO); + /* check whether we're reopening an existing tty */ + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + tty = devpts_get_tty(idx); + /* + * If we don't have a tty here on a slave open, it's because + * the master already started the close process and there's + * no relation between devpts file and tty anymore. + */ + if (!tty && driver->subtype == PTY_TYPE_SLAVE) { + retval = -EIO; + goto end_init; + } + /* + * It's safe from now on because init_dev() is called with + * tty_mutex held and release_dev() won't change tty->count + * or tty->flags without having to grab tty_mutex + */ + if (tty && driver->subtype == PTY_TYPE_MASTER) + tty = tty->link; + } else { + tty = driver->ttys[idx]; + } + if (tty) goto fast_track; /* * First time open is complex, especially for PTY devices. @@ -1383,69 +1671,189 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, * and locked termios may be retained.) */ - if (!try_module_get(driver->owner)) - return ERR_PTR(-ENODEV); + if (!try_module_get(driver->owner)) { + retval = -ENODEV; + goto end_init; + } + + o_tty = NULL; + tp = o_tp = NULL; + ltp = o_ltp = NULL; tty = alloc_tty_struct(); if (!tty) goto fail_no_mem; - initialize_tty_struct(tty, driver, idx); + initialize_tty_struct(tty); + tty->driver = driver; + tty->ops = driver->ops; + tty->index = idx; + tty_line_name(driver, idx, tty->name); + + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + tp_loc = &tty->termios; + ltp_loc = &tty->termios_locked; + } else { + tp_loc = &driver->termios[idx]; + ltp_loc = &driver->termios_locked[idx]; + } + + if (!*tp_loc) { + tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); + if (!tp) + goto free_mem_out; + *tp = driver->init_termios; + } + + if (!*ltp_loc) { + ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); + if (!ltp) + goto free_mem_out; + } + + if (driver->type == TTY_DRIVER_TYPE_PTY) { + o_tty = alloc_tty_struct(); + if (!o_tty) + goto free_mem_out; + initialize_tty_struct(o_tty); + o_tty->driver = driver->other; + o_tty->ops = driver->ops; + o_tty->index = idx; + tty_line_name(driver->other, idx, o_tty->name); + + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + o_tp_loc = &o_tty->termios; + o_ltp_loc = &o_tty->termios_locked; + } else { + o_tp_loc = &driver->other->termios[idx]; + o_ltp_loc = &driver->other->termios_locked[idx]; + } + + if (!*o_tp_loc) { + o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); + if (!o_tp) + goto free_mem_out; + *o_tp = driver->other->init_termios; + } + + if (!*o_ltp_loc) { + o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); + if (!o_ltp) + goto free_mem_out; + } - retval = tty_driver_install_tty(driver, tty); - if (retval < 0) { - free_tty_struct(tty); - module_put(driver->owner); - return ERR_PTR(retval); + /* + * Everything allocated ... set up the o_tty structure. + */ + if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) + driver->other->ttys[idx] = o_tty; + if (!*o_tp_loc) + *o_tp_loc = o_tp; + if (!*o_ltp_loc) + *o_ltp_loc = o_ltp; + o_tty->termios = *o_tp_loc; + o_tty->termios_locked = *o_ltp_loc; + driver->other->refcount++; + if (driver->subtype == PTY_TYPE_MASTER) + o_tty->count++; + + /* Establish the links in both directions */ + tty->link = o_tty; + o_tty->link = tty; } + /* + * All structures have been allocated, so now we install them. + * Failures after this point use release_tty to clean up, so + * there's no need to null out the local pointers. + */ + if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) + driver->ttys[idx] = tty; + + if (!*tp_loc) + *tp_loc = tp; + if (!*ltp_loc) + *ltp_loc = ltp; + tty->termios = *tp_loc; + tty->termios_locked = *ltp_loc; + /* Compatibility until drivers always set this */ + tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); + tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); + driver->refcount++; + tty->count++; + /* * Structures all installed ... call the ldisc open routines. * If we fail here just call release_tty to clean up. No need * to decrement the use counts, as release_tty doesn't care. */ - retval = tty_ldisc_setup(tty, tty->link); + retval = tty_ldisc_setup(tty, o_tty); + if (retval) goto release_mem_out; - return tty; + goto success; + + /* + * This fast open can be used if the tty is already open. + * No memory is allocated, and the only failures are from + * attempting to open a closing tty or attempting multiple + * opens on a pty master. + */ +fast_track: + if (test_bit(TTY_CLOSING, &tty->flags)) { + retval = -EIO; + goto end_init; + } + if (driver->type == TTY_DRIVER_TYPE_PTY && + driver->subtype == PTY_TYPE_MASTER) { + /* + * special case for PTY masters: only one open permitted, + * and the slave side open count is incremented as well. + */ + if (tty->count) { + retval = -EIO; + goto end_init; + } + tty->link->count++; + } + tty->count++; + tty->driver = driver; /* N.B. why do this every time?? */ + + /* FIXME */ + if (!test_bit(TTY_LDISC, &tty->flags)) + printk(KERN_ERR "init_dev but no ldisc\n"); +success: + *ret_tty = tty; + + /* All paths come through here to release the mutex */ +end_init: + return retval; + + /* Release locally allocated memory ... nothing placed in slots */ +free_mem_out: + kfree(o_tp); + if (o_tty) + free_tty_struct(o_tty); + kfree(ltp); + kfree(tp); + free_tty_struct(tty); fail_no_mem: module_put(driver->owner); - return ERR_PTR(-ENOMEM); + retval = -ENOMEM; + goto end_init; /* call the tty release_tty routine to clean out this slot */ release_mem_out: if (printk_ratelimit()) - printk(KERN_INFO "tty_init_dev: ldisc open failed, " + printk(KERN_INFO "init_dev: ldisc open failed, " "clearing slot %d\n", idx); release_tty(tty, idx); - return ERR_PTR(retval); -} - -void tty_free_termios(struct tty_struct *tty) -{ - struct ktermios *tp; - int idx = tty->index; - /* Kill this flag and push into drivers for locking etc */ - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - /* FIXME: Locking on ->termios array */ - tp = tty->termios; - tty->driver->termios[idx] = NULL; - kfree(tp); - } -} -EXPORT_SYMBOL(tty_free_termios); - -void tty_shutdown(struct tty_struct *tty) -{ - tty_driver_remove_tty(tty->driver, tty); - tty_free_termios(tty); + goto end_init; } -EXPORT_SYMBOL(tty_shutdown); /** * release_one_tty - release tty structure memory - * @kref: kref of tty we are obliterating * * Releases memory associated with a tty structure, and clears out the * driver table slots. This function is called when a device is no longer @@ -1455,19 +1863,31 @@ EXPORT_SYMBOL(tty_shutdown); * tty_mutex - sometimes only * takes the file list lock internally when working on the list * of ttys that the driver keeps. + * FIXME: should we require tty_mutex is held here ?? */ -static void release_one_tty(struct kref *kref) +static void release_one_tty(struct tty_struct *tty, int idx) { - struct tty_struct *tty = container_of(kref, struct tty_struct, kref); - struct tty_driver *driver = tty->driver; + int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; + struct ktermios *tp; + + if (!devpts) + tty->driver->ttys[idx] = NULL; + + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { + tp = tty->termios; + if (!devpts) + tty->driver->termios[idx] = NULL; + kfree(tp); + + tp = tty->termios_locked; + if (!devpts) + tty->driver->termios_locked[idx] = NULL; + kfree(tp); + } + - if (tty->ops->shutdown) - tty->ops->shutdown(tty); - else - tty_shutdown(tty); tty->magic = 0; - tty_driver_kref_put(driver); - module_put(driver->owner); + tty->driver->refcount--; file_list_lock(); list_del_init(&tty->tty_files); @@ -1476,21 +1896,6 @@ static void release_one_tty(struct kref *kref) free_tty_struct(tty); } -/** - * tty_kref_put - release a tty kref - * @tty: tty device - * - * Release a reference to a tty device and if need be let the kref - * layer destruct the object for us - */ - -void tty_kref_put(struct tty_struct *tty) -{ - if (tty) - kref_put(&tty->kref, release_one_tty); -} -EXPORT_SYMBOL(tty_kref_put); - /** * release_tty - release tty structure memory * @@ -1502,16 +1907,15 @@ EXPORT_SYMBOL(tty_kref_put); * takes the file list lock internally when working on the list * of ttys that the driver keeps. * FIXME: should we require tty_mutex is held here ?? - * */ static void release_tty(struct tty_struct *tty, int idx) { - /* This should always be true but check for the moment */ - WARN_ON(tty->index != idx); + struct tty_driver *driver = tty->driver; if (tty->link) - tty_kref_put(tty->link); - tty_kref_put(tty); + release_one_tty(tty->link, idx); + release_one_tty(tty, idx); + module_put(driver->owner); } /* @@ -1522,21 +1926,20 @@ static void release_tty(struct tty_struct *tty, int idx) * WSH 09/09/97: rewritten to avoid some nasty race conditions that could * lead to double frees or releasing memory still in use. */ -void tty_release_dev(struct file *filp) +static void release_dev(struct file *filp) { struct tty_struct *tty, *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; int devpts; int idx; char buf[64]; - struct inode *inode; - inode = filp->f_path.dentry->d_inode; tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, inode, "tty_release_dev")) + if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, + "release_dev")) return; - check_tty_count(tty, "tty_release_dev"); + check_tty_count(tty, "release_dev"); tty_fasync(-1, filp, 0); @@ -1548,27 +1951,33 @@ void tty_release_dev(struct file *filp) #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver->num) { - printk(KERN_DEBUG "tty_release_dev: bad idx when trying to " + printk(KERN_DEBUG "release_dev: bad idx when trying to " "free (%s)\n", tty->name); return; } - if (!devpts) { + if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (tty != tty->driver->ttys[idx]) { - printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty " + printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " "for (%s)\n", idx, tty->name); return; } if (tty->termios != tty->driver->termios[idx]) { - printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios " + printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " "for (%s)\n", idx, tty->name); return; } + if (tty->termios_locked != tty->driver->termios_locked[idx]) { + printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " + "termios_locked for (%s)\n", + idx, tty->name); + return; + } } #endif #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...", + printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", tty_name(tty, buf), tty->count); #endif @@ -1576,19 +1985,26 @@ void tty_release_dev(struct file *filp) if (tty->driver->other && !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (o_tty != tty->driver->other->ttys[idx]) { - printk(KERN_DEBUG "tty_release_dev: other->table[%d] " + printk(KERN_DEBUG "release_dev: other->table[%d] " "not o_tty for (%s)\n", idx, tty->name); return; } if (o_tty->termios != tty->driver->other->termios[idx]) { - printk(KERN_DEBUG "tty_release_dev: other->termios[%d] " + printk(KERN_DEBUG "release_dev: other->termios[%d] " "not o_termios for (%s)\n", idx, tty->name); return; } + if (o_tty->termios_locked != + tty->driver->other->termios_locked[idx]) { + printk(KERN_DEBUG "release_dev: other->termios_locked[" + "%d] not o_termios_locked for (%s)\n", + idx, tty->name); + return; + } if (o_tty->link != tty) { - printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n"); + printk(KERN_DEBUG "release_dev: bad pty pointers\n"); return; } } @@ -1646,7 +2062,7 @@ void tty_release_dev(struct file *filp) if (!do_sleep) break; - printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue " + printk(KERN_WARNING "release_dev: %s: read/write wait queue " "active!\n", tty_name(tty, buf)); mutex_unlock(&tty_mutex); schedule(); @@ -1659,14 +2075,14 @@ void tty_release_dev(struct file *filp) */ if (pty_master) { if (--o_tty->count < 0) { - printk(KERN_WARNING "tty_release_dev: bad pty slave count " + printk(KERN_WARNING "release_dev: bad pty slave count " "(%d) for %s\n", o_tty->count, tty_name(o_tty, buf)); o_tty->count = 0; } } if (--tty->count < 0) { - printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n", + printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", tty->count, tty_name(tty, buf)); tty->count = 0; } @@ -1729,11 +2145,11 @@ void tty_release_dev(struct file *filp) /* Make this pty number available for reallocation */ if (devpts) - devpts_kill_index(inode, idx); + devpts_kill_index(idx); } /** - * __tty_open - open a tty device + * tty_open - open a tty device * @inode: inode of device file * @filp: file pointer to tty * @@ -1748,14 +2164,14 @@ void tty_release_dev(struct file *filp) * The termios state of a pty is reset on first open so that * settings don't persist across reuse. * - * Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work. + * Locking: tty_mutex protects tty, get_tty_driver and init_dev work. * tty->count should protect the rest. * ->siglock protects ->signal/->sighand */ static int __tty_open(struct inode *inode, struct file *filp) { - struct tty_struct *tty = NULL; + struct tty_struct *tty; int noctty, retval; struct tty_driver *driver; int index; @@ -1777,25 +2193,23 @@ static int __tty_open(struct inode *inode, struct file *filp) mutex_unlock(&tty_mutex); return -ENXIO; } - driver = tty_driver_kref_get(tty->driver); + driver = tty->driver; index = tty->index; filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ /* noctty = 1; */ - /* FIXME: Should we take a driver reference ? */ - tty_kref_put(tty); goto got_driver; } #ifdef CONFIG_VT if (device == MKDEV(TTY_MAJOR, 0)) { extern struct tty_driver *console_driver; - driver = tty_driver_kref_get(console_driver); + driver = console_driver; index = fg_console; noctty = 1; goto got_driver; } #endif if (device == MKDEV(TTYAUX_MAJOR, 1)) { - driver = tty_driver_kref_get(console_device(&index)); + driver = console_device(&index); if (driver) { /* Don't let /dev/console block */ filp->f_flags |= O_NONBLOCK; @@ -1812,25 +2226,10 @@ static int __tty_open(struct inode *inode, struct file *filp) return -ENODEV; } got_driver: - if (!tty) { - /* check whether we're reopening an existing tty */ - tty = tty_driver_lookup_tty(driver, inode, index); - - if (IS_ERR(tty)) - return PTR_ERR(tty); - } - - if (tty) { - retval = tty_reopen(tty); - if (retval) - tty = ERR_PTR(retval); - } else - tty = tty_init_dev(driver, index, 0); - + retval = init_dev(driver, index, &tty); mutex_unlock(&tty_mutex); - tty_driver_kref_put(driver); - if (IS_ERR(tty)) - return PTR_ERR(tty); + if (retval) + return retval; filp->private_data = tty; file_move(filp, &tty->tty_files); @@ -1858,7 +2257,7 @@ static int __tty_open(struct inode *inode, struct file *filp) printk(KERN_DEBUG "error %d in opening %s...", retval, tty->name); #endif - tty_release_dev(filp); + release_dev(filp); if (retval != -ERESTARTSYS) return retval; if (signal_pending(current)) @@ -1897,6 +2296,69 @@ static int tty_open(struct inode *inode, struct file *filp) +#ifdef CONFIG_UNIX98_PTYS +/** + * ptmx_open - open a unix 98 pty master + * @inode: inode of device file + * @filp: file pointer to tty + * + * Allocate a unix98 pty master device from the ptmx driver. + * + * Locking: tty_mutex protects theinit_dev work. tty->count should + * protect the rest. + * allocated_ptys_lock handles the list of free pty numbers + */ + +static int __ptmx_open(struct inode *inode, struct file *filp) +{ + struct tty_struct *tty; + int retval; + int index; + + nonseekable_open(inode, filp); + + /* find a device that is not in use. */ + index = devpts_new_index(); + if (index < 0) + return index; + + mutex_lock(&tty_mutex); + retval = init_dev(ptm_driver, index, &tty); + mutex_unlock(&tty_mutex); + + if (retval) + goto out; + + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ + filp->private_data = tty; + file_move(filp, &tty->tty_files); + + retval = devpts_pty_new(tty->link); + if (retval) + goto out1; + + check_tty_count(tty, "ptmx_open"); + retval = ptm_driver->ops->open(tty, filp); + if (!retval) + return 0; +out1: + release_dev(filp); + return retval; +out: + devpts_kill_index(index); + return retval; +} + +static int ptmx_open(struct inode *inode, struct file *filp) +{ + int ret; + + lock_kernel(); + ret = __ptmx_open(inode, filp); + unlock_kernel(); + return ret; +} +#endif /** * tty_release - vfs callback for close @@ -1907,13 +2369,13 @@ static int tty_open(struct inode *inode, struct file *filp) * this tty. There may however be several such references. * * Locking: - * Takes bkl. See tty_release_dev + * Takes bkl. See release_dev */ static int tty_release(struct inode *inode, struct file *filp) { lock_kernel(); - tty_release_dev(filp); + release_dev(filp); unlock_kernel(); return 0; } @@ -2062,7 +2524,7 @@ int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, /* For a PTY we need to lock the tty side */ mutex_lock(&real_tty->termios_mutex); - if (!memcmp(ws, &real_tty->winsize, sizeof(*ws))) + if (!memcmp(ws, &tty->winsize, sizeof(*ws))) goto done; /* Get the PID values and reference them so we can avoid holding the tty ctrl lock while sending signals */ @@ -2534,7 +2996,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCSTI: return tiocsti(tty, p); case TIOCGWINSZ: - return tiocgwinsz(real_tty, p); + return tiocgwinsz(tty, p); case TIOCSWINSZ: return tiocswinsz(tty, real_tty, p); case TIOCCONS: @@ -2564,6 +3026,10 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return put_user(tty->ldisc.ops->num, (int __user *)p); case TIOCSETD: return tiocsetd(tty, p); +#ifdef CONFIG_VT + case TIOCLINUX: + return tioclinux(tty, arg); +#endif /* * Break handling */ @@ -2753,6 +3219,113 @@ void do_SAK(struct tty_struct *tty) EXPORT_SYMBOL(do_SAK); +/** + * flush_to_ldisc + * @work: tty structure passed from work queue. + * + * This routine is called out of the software interrupt to flush data + * from the buffer chain to the line discipline. + * + * Locking: holds tty->buf.lock to guard buffer list. Drops the lock + * while invoking the line discipline receive_buf method. The + * receive_buf method is single threaded for each tty instance. + */ + +static void flush_to_ldisc(struct work_struct *work) +{ + struct tty_struct *tty = + container_of(work, struct tty_struct, buf.work.work); + unsigned long flags; + struct tty_ldisc *disc; + struct tty_buffer *tbuf, *head; + char *char_buf; + unsigned char *flag_buf; + + disc = tty_ldisc_ref(tty); + if (disc == NULL) /* !TTY_LDISC */ + return; + + spin_lock_irqsave(&tty->buf.lock, flags); + /* So we know a flush is running */ + set_bit(TTY_FLUSHING, &tty->flags); + head = tty->buf.head; + if (head != NULL) { + tty->buf.head = NULL; + for (;;) { + int count = head->commit - head->read; + if (!count) { + if (head->next == NULL) + break; + tbuf = head; + head = head->next; + tty_buffer_free(tty, tbuf); + continue; + } + /* Ldisc or user is trying to flush the buffers + we are feeding to the ldisc, stop feeding the + line discipline as we want to empty the queue */ + if (test_bit(TTY_FLUSHPENDING, &tty->flags)) + break; + if (!tty->receive_room) { + schedule_delayed_work(&tty->buf.work, 1); + break; + } + if (count > tty->receive_room) + count = tty->receive_room; + char_buf = head->char_buf_ptr + head->read; + flag_buf = head->flag_buf_ptr + head->read; + head->read += count; + spin_unlock_irqrestore(&tty->buf.lock, flags); + disc->ops->receive_buf(tty, char_buf, + flag_buf, count); + spin_lock_irqsave(&tty->buf.lock, flags); + } + /* Restore the queue head */ + tty->buf.head = head; + } + /* We may have a deferred request to flush the input buffer, + if so pull the chain under the lock and empty the queue */ + if (test_bit(TTY_FLUSHPENDING, &tty->flags)) { + __tty_buffer_flush(tty); + clear_bit(TTY_FLUSHPENDING, &tty->flags); + wake_up(&tty->read_wait); + } + clear_bit(TTY_FLUSHING, &tty->flags); + spin_unlock_irqrestore(&tty->buf.lock, flags); + + tty_ldisc_deref(disc); +} + +/** + * tty_flip_buffer_push - terminal + * @tty: tty to push + * + * Queue a push of the terminal flip buffers to the line discipline. This + * function must not be called from IRQ context if tty->low_latency is set. + * + * In the event of the queue being busy for flipping the work will be + * held off and retried later. + * + * Locking: tty buffer lock. Driver locks in low latency mode. + */ + +void tty_flip_buffer_push(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + if (tty->buf.tail != NULL) + tty->buf.tail->commit = tty->buf.tail->used; + spin_unlock_irqrestore(&tty->buf.lock, flags); + + if (tty->low_latency) + flush_to_ldisc(&tty->buf.work.work); + else + schedule_delayed_work(&tty->buf.work, 1); +} + +EXPORT_SYMBOL(tty_flip_buffer_push); + + /** * initialize_tty_struct * @tty: tty to initialize @@ -2763,11 +3336,9 @@ EXPORT_SYMBOL(do_SAK); * Locking: none - tty in question must not be exposed at this point */ -void initialize_tty_struct(struct tty_struct *tty, - struct tty_driver *driver, int idx) +static void initialize_tty_struct(struct tty_struct *tty) { memset(tty, 0, sizeof(struct tty_struct)); - kref_init(&tty->kref); tty->magic = TTY_MAGIC; tty_ldisc_init(tty); tty->session = NULL; @@ -2775,6 +3346,7 @@ void initialize_tty_struct(struct tty_struct *tty, tty->overrun_time = jiffies; tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); + INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); @@ -2785,11 +3357,6 @@ void initialize_tty_struct(struct tty_struct *tty, spin_lock_init(&tty->ctrl_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_WORK(&tty->SAK_work, do_SAK_work); - - tty->driver = driver; - tty->ops = driver->ops; - tty->index = idx; - tty_line_name(driver, idx, tty->name); } /** @@ -2810,9 +3377,10 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch) return tty->ops->put_char(tty, ch); return tty->ops->write(tty, &ch, 1); } + EXPORT_SYMBOL_GPL(tty_put_char); -struct class *tty_class; +static struct class *tty_class; /** * tty_register_device - register a tty device @@ -2852,7 +3420,6 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, return device_create_drvdata(tty_class, device, dev, NULL, name); } -EXPORT_SYMBOL(tty_register_device); /** * tty_unregister_device - unregister a tty device @@ -2870,6 +3437,8 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); } + +EXPORT_SYMBOL(tty_register_device); EXPORT_SYMBOL(tty_unregister_device); struct tty_driver *alloc_tty_driver(int lines) @@ -2878,65 +3447,27 @@ struct tty_driver *alloc_tty_driver(int lines) driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); if (driver) { - kref_init(&driver->kref); driver->magic = TTY_DRIVER_MAGIC; driver->num = lines; /* later we'll move allocation of tables here */ } return driver; } -EXPORT_SYMBOL(alloc_tty_driver); -static void destruct_tty_driver(struct kref *kref) +void put_tty_driver(struct tty_driver *driver) { - struct tty_driver *driver = container_of(kref, struct tty_driver, kref); - int i; - struct ktermios *tp; - void *p; - - if (driver->flags & TTY_DRIVER_INSTALLED) { - /* - * Free the termios and termios_locked structures because - * we don't want to get memory leaks when modular tty - * drivers are removed from the kernel. - */ - for (i = 0; i < driver->num; i++) { - tp = driver->termios[i]; - if (tp) { - driver->termios[i] = NULL; - kfree(tp); - } - if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) - tty_unregister_device(driver, i); - } - p = driver->ttys; - proc_tty_unregister_driver(driver); - driver->ttys = NULL; - driver->termios = NULL; - kfree(p); - cdev_del(&driver->cdev); - } kfree(driver); } -void tty_driver_kref_put(struct tty_driver *driver) -{ - kref_put(&driver->kref, destruct_tty_driver); -} -EXPORT_SYMBOL(tty_driver_kref_put); - void tty_set_operations(struct tty_driver *driver, const struct tty_operations *op) { driver->ops = op; }; -EXPORT_SYMBOL(tty_set_operations); -void put_tty_driver(struct tty_driver *d) -{ - tty_driver_kref_put(d); -} +EXPORT_SYMBOL(alloc_tty_driver); EXPORT_SYMBOL(put_tty_driver); +EXPORT_SYMBOL(tty_set_operations); /* * Called by a tty driver to register itself. @@ -2948,8 +3479,11 @@ int tty_register_driver(struct tty_driver *driver) dev_t dev; void **p = NULL; + if (driver->flags & TTY_DRIVER_INSTALLED) + return 0; + if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { - p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL); + p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); if (!p) return -ENOMEM; } @@ -2973,9 +3507,12 @@ int tty_register_driver(struct tty_driver *driver) if (p) { driver->ttys = (struct tty_struct **)p; driver->termios = (struct ktermios **)(p + driver->num); + driver->termios_locked = (struct ktermios **) + (p + driver->num * 2); } else { driver->ttys = NULL; driver->termios = NULL; + driver->termios_locked = NULL; } cdev_init(&driver->cdev, &tty_fops); @@ -2984,7 +3521,7 @@ int tty_register_driver(struct tty_driver *driver) if (error) { unregister_chrdev_region(dev, driver->num); driver->ttys = NULL; - driver->termios = NULL; + driver->termios = driver->termios_locked = NULL; kfree(p); return error; } @@ -2998,7 +3535,6 @@ int tty_register_driver(struct tty_driver *driver) tty_register_device(driver, i, NULL); } proc_tty_register_driver(driver); - driver->flags |= TTY_DRIVER_INSTALLED; return 0; } @@ -3009,19 +3545,46 @@ EXPORT_SYMBOL(tty_register_driver); */ int tty_unregister_driver(struct tty_driver *driver) { -#if 0 - /* FIXME */ + int i; + struct ktermios *tp; + void *p; + if (driver->refcount) return -EBUSY; -#endif + unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), driver->num); mutex_lock(&tty_mutex); list_del(&driver->tty_drivers); mutex_unlock(&tty_mutex); + + /* + * Free the termios and termios_locked structures because + * we don't want to get memory leaks when modular tty + * drivers are removed from the kernel. + */ + for (i = 0; i < driver->num; i++) { + tp = driver->termios[i]; + if (tp) { + driver->termios[i] = NULL; + kfree(tp); + } + tp = driver->termios_locked[i]; + if (tp) { + driver->termios_locked[i] = NULL; + kfree(tp); + } + if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) + tty_unregister_device(driver, i); + } + p = driver->ttys; + proc_tty_unregister_driver(driver); + driver->ttys = NULL; + driver->termios = driver->termios_locked = NULL; + kfree(p); + cdev_del(&driver->cdev); return 0; } - EXPORT_SYMBOL(tty_unregister_driver); dev_t tty_devnum(struct tty_struct *tty) @@ -3032,12 +3595,9 @@ EXPORT_SYMBOL(tty_devnum); void proc_clear_tty(struct task_struct *p) { - struct tty_struct *tty; spin_lock_irq(&p->sighand->siglock); - tty = p->signal->tty; p->signal->tty = NULL; spin_unlock_irq(&p->sighand->siglock); - tty_kref_put(tty); } /* Called under the sighand lock */ @@ -3053,13 +3613,9 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) tty->pgrp = get_pid(task_pgrp(tsk)); spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty->session = get_pid(task_session(tsk)); - if (tsk->signal->tty) { - printk(KERN_DEBUG "tty not NULL!!\n"); - tty_kref_put(tsk->signal->tty); - } } put_pid(tsk->signal->tty_old_pgrp); - tsk->signal->tty = tty_kref_get(tty); + tsk->signal->tty = tty; tsk->signal->tty_old_pgrp = NULL; } @@ -3073,20 +3629,18 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) struct tty_struct *get_current_tty(void) { struct tty_struct *tty; - unsigned long flags; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - tty = tty_kref_get(current->signal->tty); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + WARN_ON_ONCE(!mutex_is_locked(&tty_mutex)); + tty = current->signal->tty; + /* + * session->tty can be changed/cleared from under us, make sure we + * issue the load. The obtained pointer, when not NULL, is valid as + * long as we hold tty_mutex. + */ + barrier(); return tty; } EXPORT_SYMBOL_GPL(get_current_tty); -void tty_default_fops(struct file_operations *fops) -{ - *fops = tty_fops; -} - /* * Initialize the console device. This is called *early*, so * we can't necessarily depend on lots of kernel help here. @@ -3124,6 +3678,12 @@ postcore_initcall(tty_class_init); /* 3/2004 jmc: why do these devices exist? */ static struct cdev tty_cdev, console_cdev; +#ifdef CONFIG_UNIX98_PTYS +static struct cdev ptmx_cdev; +#endif +#ifdef CONFIG_VT +static struct cdev vc0_cdev; +#endif /* * Ok, now we can initialize the rest of the tty devices and can count @@ -3135,18 +3695,32 @@ static int __init tty_init(void) if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); - device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, + device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, + device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); +#ifdef CONFIG_UNIX98_PTYS + cdev_init(&ptmx_cdev, &ptmx_fops); + if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || + register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) + panic("Couldn't register /dev/ptmx driver\n"); + device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); +#endif + #ifdef CONFIG_VT - vty_init(&console_fops); + cdev_init(&vc0_cdev, &console_fops); + if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || + register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) + panic("Couldn't register /dev/tty0 driver\n"); + device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + + vty_init(); #endif return 0; } diff --git a/trunk/drivers/char/tty_ioctl.c b/trunk/drivers/char/tty_ioctl.c index a408c8e487ec..bf34e4597421 100644 --- a/trunk/drivers/char/tty_ioctl.c +++ b/trunk/drivers/char/tty_ioctl.c @@ -40,15 +40,6 @@ #define TERMIOS_OLD 8 -/** - * tty_chars_in_buffer - characters pending - * @tty: terminal - * - * Return the number of bytes of data in the device private - * output queue. If no private method is supplied there is assumed - * to be no queue on the device. - */ - int tty_chars_in_buffer(struct tty_struct *tty) { if (tty->ops->chars_in_buffer) @@ -56,48 +47,25 @@ int tty_chars_in_buffer(struct tty_struct *tty) else return 0; } + EXPORT_SYMBOL(tty_chars_in_buffer); -/** - * tty_write_room - write queue space - * @tty: terminal - * - * Return the number of bytes that can be queued to this device - * at the present time. The result should be treated as a guarantee - * and the driver cannot offer a value it later shrinks by more than - * the number of bytes written. If no method is provided 2K is always - * returned and data may be lost as there will be no flow control. - */ - int tty_write_room(struct tty_struct *tty) { if (tty->ops->write_room) return tty->ops->write_room(tty); return 2048; } + EXPORT_SYMBOL(tty_write_room); -/** - * tty_driver_flush_buffer - discard internal buffer - * @tty: terminal - * - * Discard the internal output buffer for this device. If no method - * is provided then either the buffer cannot be hardware flushed or - * there is no buffer driver side. - */ void tty_driver_flush_buffer(struct tty_struct *tty) { if (tty->ops->flush_buffer) tty->ops->flush_buffer(tty); } -EXPORT_SYMBOL(tty_driver_flush_buffer); -/** - * tty_throttle - flow control - * @tty: terminal - * - * Indicate that a tty should stop transmitting data down the stack. - */ +EXPORT_SYMBOL(tty_driver_flush_buffer); void tty_throttle(struct tty_struct *tty) { @@ -108,13 +76,6 @@ void tty_throttle(struct tty_struct *tty) } EXPORT_SYMBOL(tty_throttle); -/** - * tty_unthrottle - flow control - * @tty: terminal - * - * Indicate that a tty may continue transmitting data down the stack. - */ - void tty_unthrottle(struct tty_struct *tty) { if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && @@ -151,11 +112,6 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout) } EXPORT_SYMBOL(tty_wait_until_sent); - -/* - * Termios Helper Methods - */ - static void unset_locked_termios(struct ktermios *termios, struct ktermios *old, struct ktermios *locked) @@ -390,16 +346,6 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, } EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); -/** - * tty_encode_baud_rate - set baud rate of the tty - * @ibaud: input baud rate - * @obad: output baud rate - * - * Update the current termios data for the tty with the new speed - * settings. The caller must hold the termios_mutex for the tty in - * question. - */ - void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) { tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); @@ -484,11 +430,12 @@ EXPORT_SYMBOL(tty_termios_hw_change); * is a bit of layering violation here with n_tty in terms of the * internal knowledge of this function. * - * Locking: termios_mutex + * Locking: termios_sem */ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) { + int canon_change; struct ktermios old_termios; struct tty_ldisc *ld; unsigned long flags; @@ -504,6 +451,18 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) old_termios = *tty->termios; *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); + canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; + if (canon_change) { + memset(&tty->read_flags, 0, sizeof tty->read_flags); + tty->canon_head = tty->read_tail; + tty->canon_data = 0; + tty->erasing = 0; + } + + /* This bit should be in the ldisc code */ + if (canon_change && !L_ICANON(tty) && tty->read_cnt) + /* Get characters left over from canonical mode. */ + wake_up_interruptible(&tty->read_wait); /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { @@ -549,7 +508,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) * functions before using change_termios to do the actual changes. * * Locking: - * Called functions take ldisc and termios_mutex locks + * Called functions take ldisc and termios_sem locks */ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) @@ -620,51 +579,25 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio) return 0; } - -#ifdef TCGETX - -/** - * set_termiox - set termiox fields if possible - * @tty: terminal - * @arg: termiox structure from user - * @opt: option flags for ioctl type - * - * Implement the device calling points for the SYS5 termiox ioctl - * interface in Linux - */ - -static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) +static unsigned long inq_canon(struct tty_struct *tty) { - struct termiox tnew; - struct tty_ldisc *ld; + int nr, head, tail; - if (tty->termiox == NULL) - return -EINVAL; - if (copy_from_user(&tnew, arg, sizeof(struct termiox))) - return -EFAULT; - - ld = tty_ldisc_ref(tty); - if (ld != NULL) { - if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); - tty_ldisc_deref(ld); - } - if (opt & TERMIOS_WAIT) { - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; + if (!tty->canon_data || !tty->read_buf) + return 0; + head = tty->canon_head; + tail = tty->read_tail; + nr = (head - tail) & (N_TTY_BUF_SIZE-1); + /* Skip EOF-chars.. */ + while (head != tail) { + if (test_bit(tail, tty->read_flags) && + tty->read_buf[tail] == __DISABLED_CHAR) + nr--; + tail = (tail+1) & (N_TTY_BUF_SIZE-1); } - - mutex_lock(&tty->termios_mutex); - if (tty->ops->set_termiox) - tty->ops->set_termiox(tty, &tnew); - mutex_unlock(&tty->termios_mutex); - return 0; + return nr; } -#endif - - #ifdef TIOCGETP /* * These are deprecated, but there is limited support.. @@ -738,7 +671,7 @@ static void set_sgflags(struct ktermios *termios, int flags) * Updates a terminal from the legacy BSD style terminal information * structure. * - * Locking: termios_mutex + * Locking: termios_sem */ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) @@ -916,7 +849,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, { struct tty_struct *real_tty; void __user *p = (void __user *)arg; - int ret = 0; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -952,24 +884,18 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termios(real_tty, p, TERMIOS_OLD); #ifndef TCGETS2 case TCGETS: - mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; #else case TCGETS: - mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; case TCGETS2: - mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; case TCSETSF2: return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); case TCSETSW2: @@ -987,59 +913,34 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termios(real_tty, p, TERMIOS_TERMIO); #ifndef TCGETS2 case TIOCGLCKTRMIOS: - mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - mutex_lock(&real_tty->termios_mutex); if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; #else case TIOCGLCKTRMIOS: - mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) - ret = -EPERM; - mutex_lock(&real_tty->termios_mutex); + return -EPERM; if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; + return -EFAULT; + return 0; #endif -#ifdef TCGETX - case TCGETX: - if (real_tty->termiox == NULL) - return -EINVAL; - mutex_lock(&real_tty->termios_mutex); - if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox))) - ret = -EFAULT; - mutex_unlock(&real_tty->termios_mutex); - return ret; - case TCSETX: - return set_termiox(real_tty, p, 0); - case TCSETXW: - return set_termiox(real_tty, p, TERMIOS_WAIT); - case TCSETXF: - return set_termiox(real_tty, p, TERMIOS_FLUSH); -#endif case TIOCGSOFTCAR: - mutex_lock(&real_tty->termios_mutex); - ret = put_user(C_CLOCAL(real_tty) ? 1 : 0, + /* FIXME: for correctness we may need to take the termios + lock here - review */ + return put_user(C_CLOCAL(real_tty) ? 1 : 0, (int __user *)arg); - mutex_unlock(&real_tty->termios_mutex); - return ret; case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; @@ -1079,7 +980,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) } EXPORT_SYMBOL_GPL(tty_perform_flush); -int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, +int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long flags; @@ -1117,6 +1018,13 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, return 0; case TCFLSH: return tty_perform_flush(tty, arg); + case TIOCOUTQ: + return put_user(tty_chars_in_buffer(tty), (int __user *) arg); + case TIOCINQ: + retval = tty->read_cnt; + if (L_ICANON(tty)) + retval = inq_canon(tty); + return put_user(retval, (unsigned int __user *) arg); case TIOCPKT: { int pktmode; @@ -1142,4 +1050,4 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, return tty_mode_ioctl(tty, file, cmd, arg); } } -EXPORT_SYMBOL(n_tty_ioctl_helper); +EXPORT_SYMBOL(n_tty_ioctl); diff --git a/trunk/drivers/char/tty_port.c b/trunk/drivers/char/tty_port.c deleted file mode 100644 index 553b0e9d8d17..000000000000 --- a/trunk/drivers/char/tty_port.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Tty port functions - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void tty_port_init(struct tty_port *port) -{ - memset(port, 0, sizeof(*port)); - init_waitqueue_head(&port->open_wait); - init_waitqueue_head(&port->close_wait); - mutex_init(&port->mutex); - spin_lock_init(&port->lock); - port->close_delay = (50 * HZ) / 100; - port->closing_wait = (3000 * HZ) / 100; -} -EXPORT_SYMBOL(tty_port_init); - -int tty_port_alloc_xmit_buf(struct tty_port *port) -{ - /* We may sleep in get_zeroed_page() */ - mutex_lock(&port->mutex); - if (port->xmit_buf == NULL) - port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); - mutex_unlock(&port->mutex); - if (port->xmit_buf == NULL) - return -ENOMEM; - return 0; -} -EXPORT_SYMBOL(tty_port_alloc_xmit_buf); - -void tty_port_free_xmit_buf(struct tty_port *port) -{ - mutex_lock(&port->mutex); - if (port->xmit_buf != NULL) { - free_page((unsigned long)port->xmit_buf); - port->xmit_buf = NULL; - } - mutex_unlock(&port->mutex); -} -EXPORT_SYMBOL(tty_port_free_xmit_buf); - - -/** - * tty_port_tty_get - get a tty reference - * @port: tty port - * - * Return a refcount protected tty instance or NULL if the port is not - * associated with a tty (eg due to close or hangup) - */ - -struct tty_struct *tty_port_tty_get(struct tty_port *port) -{ - unsigned long flags; - struct tty_struct *tty; - - spin_lock_irqsave(&port->lock, flags); - tty = tty_kref_get(port->tty); - spin_unlock_irqrestore(&port->lock, flags); - return tty; -} -EXPORT_SYMBOL(tty_port_tty_get); - -/** - * tty_port_tty_set - set the tty of a port - * @port: tty port - * @tty: the tty - * - * Associate the port and tty pair. Manages any internal refcounts. - * Pass NULL to deassociate a port - */ - -void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) -{ - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - if (port->tty) - tty_kref_put(port->tty); - port->tty = tty; - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL(tty_port_tty_set); diff --git a/trunk/drivers/char/vt.c b/trunk/drivers/char/vt.c index 57029fefd64a..60359c360912 100644 --- a/trunk/drivers/char/vt.c +++ b/trunk/drivers/char/vt.c @@ -100,10 +100,10 @@ #include #include #include -#include -#include + +#include #include -#include +#include #define MAX_NR_CON_DRIVER 16 @@ -2136,9 +2136,27 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co release_console_sem(); return 0; } + release_console_sem(); + orig_buf = buf; orig_count = count; + /* At this point 'buf' is guaranteed to be a kernel buffer + * and therefore no access to userspace (and therefore sleeping) + * will be needed. The con_buf_mtx serializes all tty based + * console rendering and vcs write/read operations. We hold + * the console spinlock during the entire write. + */ + + acquire_console_sem(); + + vc = tty->driver_data; + if (vc == NULL) { + printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n"); + release_console_sem(); + goto out; + } + himask = vc->vc_hi_font_mask; charmask = himask ? 0x1ff : 0xff; @@ -2352,6 +2370,8 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co FLUSH console_conditional_schedule(); release_console_sem(); + +out: notify_update(vc); return n; #undef FLUSH @@ -2563,6 +2583,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) int lines; int ret; + if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE) + return -EINVAL; if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(type, p)) @@ -2756,12 +2778,6 @@ static int con_open(struct tty_struct *tty, struct file *filp) ret = vc_allocate(currcons); if (ret == 0) { struct vc_data *vc = vc_cons[currcons].d; - - /* Still being freed */ - if (vc->vc_tty) { - release_console_sem(); - return -ERESTARTSYS; - } tty->driver_data = vc; vc->vc_tty = tty; @@ -2782,20 +2798,34 @@ static int con_open(struct tty_struct *tty, struct file *filp) return ret; } +/* + * We take tty_mutex in here to prevent another thread from coming in via init_dev + * and taking a ref against the tty while we're in the process of forgetting + * about it and cleaning things up. + * + * This is because vcs_remove_sysfs() can sleep and will drop the BKL. + */ static void con_close(struct tty_struct *tty, struct file *filp) { - /* Nothing to do - we defer to shutdown */ -} - -static void con_shutdown(struct tty_struct *tty) -{ - struct vc_data *vc = tty->driver_data; - BUG_ON(vc == NULL); + mutex_lock(&tty_mutex); acquire_console_sem(); - vc->vc_tty = NULL; - vcs_remove_sysfs(tty); + if (tty && tty->count == 1) { + struct vc_data *vc = tty->driver_data; + + if (vc) + vc->vc_tty = NULL; + tty->driver_data = NULL; + vcs_remove_sysfs(tty); + release_console_sem(); + mutex_unlock(&tty_mutex); + /* + * tty_mutex is released, but we still hold BKL, so there is + * still exclusion against init_dev() + */ + return; + } release_console_sem(); - tty_shutdown(tty); + mutex_unlock(&tty_mutex); } static int default_italic_color = 2; // green (ASCII) @@ -2920,19 +2950,10 @@ static const struct tty_operations con_ops = { .throttle = con_throttle, .unthrottle = con_unthrottle, .resize = vt_resize, - .shutdown = con_shutdown }; -static struct cdev vc0_cdev; - -int __init vty_init(const struct file_operations *console_fops) +int __init vty_init(void) { - cdev_init(&vc0_cdev, console_fops); - if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || - register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) - panic("Couldn't register /dev/tty0 driver\n"); - device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); - vcs_init(); console_driver = alloc_tty_driver(MAX_NR_CONSOLES); @@ -2951,6 +2972,7 @@ int __init vty_init(const struct file_operations *console_fops) tty_set_operations(console_driver, &con_ops); if (tty_register_driver(console_driver)) panic("Couldn't register console driver\n"); + kbd_init(); console_map_init(); #ifdef CONFIG_PROM_CONSOLE @@ -3444,7 +3466,7 @@ int register_con_driver(const struct consw *csw, int first, int last) if (retval) goto err; - con_driver->dev = device_create(vtconsole_class, NULL, + con_driver->dev = device_create_drvdata(vtconsole_class, NULL, MKDEV(0, con_driver->node), NULL, "vtcon%i", con_driver->node); @@ -3555,7 +3577,7 @@ static int __init vtconsole_class_init(void) struct con_driver *con = ®istered_con_driver[i]; if (con->con && !con->dev) { - con->dev = device_create(vtconsole_class, NULL, + con->dev = device_create_drvdata(vtconsole_class, NULL, MKDEV(0, con->node), NULL, "vtcon%i", con->node); diff --git a/trunk/drivers/char/vt_ioctl.c b/trunk/drivers/char/vt_ioctl.c index 8944ce508e2f..c904e9ad4a71 100644 --- a/trunk/drivers/char/vt_ioctl.c +++ b/trunk/drivers/char/vt_ioctl.c @@ -395,8 +395,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, kbd = kbd_table + console; switch (cmd) { - case TIOCLINUX: - return tioclinux(tty, arg); case KIOCSOUND: if (!perm) goto eperm; diff --git a/trunk/drivers/isdn/capi/capi.c b/trunk/drivers/isdn/capi/capi.c index 798d7f3e42ef..871b0cbca5e4 100644 --- a/trunk/drivers/isdn/capi/capi.c +++ b/trunk/drivers/isdn/capi/capi.c @@ -1231,7 +1231,7 @@ static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file, int error = 0; switch (cmd) { default: - error = n_tty_ioctl_helper(tty, file, cmd, arg); + error = n_tty_ioctl (tty, file, cmd, arg); break; } return error; diff --git a/trunk/drivers/isdn/gigaset/ser-gigaset.c b/trunk/drivers/isdn/gigaset/ser-gigaset.c index 07052ed2a0c5..5e89fa177816 100644 --- a/trunk/drivers/isdn/gigaset/ser-gigaset.c +++ b/trunk/drivers/isdn/gigaset/ser-gigaset.c @@ -571,7 +571,6 @@ gigaset_tty_close(struct tty_struct *tty) } /* prevent other callers from entering ldisc methods */ - /* FIXME: should use the tty state flags */ tty->disc_data = NULL; if (!cs->hw.ser) @@ -643,11 +642,10 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, return -ENXIO; switch (cmd) { - - case FIONREAD: - /* unused, always return zero */ - val = 0; - rc = put_user(val, p); + case TCGETS: + case TCGETA: + /* pass through to underlying serial device */ + rc = n_tty_ioctl(tty, file, cmd, arg); break; case TCFLSH: @@ -661,13 +659,20 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, flush_send_queue(cs); break; } - /* Pass through */ + /* flush the serial port's buffer */ + rc = n_tty_ioctl(tty, file, cmd, arg); + break; - default: - /* pass through to underlying serial device */ - rc = n_tty_ioctl_helper(tty, file, cmd, arg); + case FIONREAD: + /* unused, always return zero */ + val = 0; + rc = put_user(val, p); break; + + default: + rc = -ENOIOCTLCMD; } + cs_put(cs); return rc; } @@ -675,8 +680,6 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, /* * Poll on the tty. * Unused, always return zero. - * - * FIXME: should probably return an exception - especially on hangup */ static unsigned int gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) diff --git a/trunk/drivers/net/wan/Kconfig b/trunk/drivers/net/wan/Kconfig index 21efd99b9294..2ae2ec40015d 100644 --- a/trunk/drivers/net/wan/Kconfig +++ b/trunk/drivers/net/wan/Kconfig @@ -205,7 +205,7 @@ config WANXL_BUILD_FIRMWARE config PC300 tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)" - depends on HDLC && PCI && BROKEN + depends on HDLC && PCI ---help--- Driver for the Cyclades-PC300 synchronous communication boards. diff --git a/trunk/drivers/s390/char/fs3270.c b/trunk/drivers/s390/char/fs3270.c index 40759c33477d..d18e6d2e0b49 100644 --- a/trunk/drivers/s390/char/fs3270.c +++ b/trunk/drivers/s390/char/fs3270.c @@ -418,22 +418,25 @@ fs3270_open(struct inode *inode, struct file *filp) { struct fs3270 *fp; struct idal_buffer *ib; - int minor, rc = 0; + int minor, rc; if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR) return -ENODEV; + lock_kernel(); minor = iminor(filp->f_path.dentry->d_inode); /* Check for minor 0 multiplexer. */ if (minor == 0) { - struct tty_struct *tty = get_current_tty(); + struct tty_struct *tty; + mutex_lock(&tty_mutex); + tty = get_current_tty(); if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) { - tty_kref_put(tty); - return -ENODEV; + mutex_unlock(&tty_mutex); + rc = -ENODEV; + goto out; } minor = tty->index + RAW3270_FIRSTMINOR; - tty_kref_put(tty); + mutex_unlock(&tty_mutex); } - lock_kernel(); /* Check if some other program is already using fullscreen mode. */ fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor); if (!IS_ERR(fp)) { @@ -475,7 +478,7 @@ fs3270_open(struct inode *inode, struct file *filp) filp->private_data = fp; out: unlock_kernel(); - return rc; + return 0; } /* diff --git a/trunk/drivers/serial/8250.c b/trunk/drivers/serial/8250.c index d4104a3bbe87..9ccc563d8730 100644 --- a/trunk/drivers/serial/8250.c +++ b/trunk/drivers/serial/8250.c @@ -44,10 +44,6 @@ #include "8250.h" -#ifdef CONFIG_SPARC -#include "suncore.h" -#endif - /* * Configuration: * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option @@ -57,13 +53,6 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; -static struct uart_driver serial8250_reg; - -static int serial_index(struct uart_port *port) -{ - return (serial8250_reg.minor - 64) + port->line; -} - /* * Debugging. */ @@ -547,7 +536,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) /* * FIFO support. */ -static void serial8250_clear_fifos(struct uart_8250_port *p) +static inline void serial8250_clear_fifos(struct uart_8250_port *p) { if (p->capabilities & UART_CAP_FIFO) { serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); @@ -562,7 +551,7 @@ static void serial8250_clear_fifos(struct uart_8250_port *p) * capability" bit enabled. Note that on XR16C850s, we need to * reset LCR to write to IER. */ -static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { @@ -1004,7 +993,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) return; DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ", - serial_index(&up->port), up->port.iobase, up->port.membase); + up->port.line, up->port.iobase, up->port.membase); /* * We really do need global IRQs disabled here - we're going to @@ -1139,8 +1128,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) if (up->capabilities != uart_config[up->port.type].flags) { printk(KERN_WARNING "ttyS%d: detected caps %08x should be %08x\n", - serial_index(&up->port), up->capabilities, - uart_config[up->port.type].flags); + up->port.line, up->capabilities, + uart_config[up->port.type].flags); } up->port.fifosize = uart_config[up->port.type].fifo_size; @@ -1435,7 +1424,8 @@ static unsigned int check_modem_status(struct uart_8250_port *up) /* * This handles the interrupt from one port. */ -static void serial8250_handle_port(struct uart_8250_port *up) +static inline void +serial8250_handle_port(struct uart_8250_port *up) { unsigned int status; unsigned long flags; @@ -1729,7 +1719,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) /* * Wait for transmitter & holding register to empty */ -static void wait_for_xmitr(struct uart_8250_port *up, int bits) +static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) { unsigned int status, tmout = 10000; @@ -1864,8 +1854,7 @@ static int serial8250_startup(struct uart_port *port) */ if (!(up->port.flags & UPF_BUGGY_UART) && (serial_inp(up, UART_LSR) == 0xff)) { - printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n", - serial_index(&up->port)); + printk("ttyS%d: LSR safety check engaged!\n", up->port.line); return -ENODEV; } @@ -1920,8 +1909,7 @@ static int serial8250_startup(struct uart_port *port) */ if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { up->bugs |= UART_BUG_THRE; - pr_debug("ttyS%d - using backup timer\n", - serial_index(port)); + pr_debug("ttyS%d - using backup timer\n", port->line); } } @@ -1981,7 +1969,7 @@ static int serial8250_startup(struct uart_port *port) if (!(up->bugs & UART_BUG_TXEN)) { up->bugs |= UART_BUG_TXEN; pr_debug("ttyS%d - enabling bad tx status workarounds\n", - serial_index(port)); + port->line); } } else { up->bugs &= ~UART_BUG_TXEN; @@ -2642,6 +2630,7 @@ static int serial8250_console_early_setup(void) return serial8250_find_port_for_earlycon(); } +static struct uart_driver serial8250_reg; static struct console serial8250_console = { .name = "ttyS", .write = serial8250_console_write, @@ -2688,6 +2677,7 @@ static struct uart_driver serial8250_reg = { .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, + .nr = UART_NR, .cons = SERIAL8250_CONSOLE, }; @@ -2969,12 +2959,10 @@ static int __init serial8250_init(void) "%d ports, IRQ sharing %sabled\n", nr_uarts, share_irqs ? "en" : "dis"); -#ifdef CONFIG_SPARC - ret = sunserial_register_minors(&serial8250_reg, UART_NR); -#else - serial8250_reg.nr = UART_NR; + for (i = 0; i < NR_IRQS; i++) + spin_lock_init(&irq_lists[i].lock); + ret = uart_register_driver(&serial8250_reg); -#endif if (ret) goto out; @@ -2999,11 +2987,7 @@ static int __init serial8250_init(void) put_dev: platform_device_put(serial8250_isa_devs); unreg_uart_drv: -#ifdef CONFIG_SPARC - sunserial_unregister_minors(&serial8250_reg, UART_NR); -#else uart_unregister_driver(&serial8250_reg); -#endif out: return ret; } @@ -3022,11 +3006,7 @@ static void __exit serial8250_exit(void) platform_driver_unregister(&serial8250_isa_driver); platform_device_unregister(isa_dev); -#ifdef CONFIG_SPARC - sunserial_unregister_minors(&serial8250_reg, UART_NR); -#else uart_unregister_driver(&serial8250_reg); -#endif } module_init(serial8250_init); diff --git a/trunk/drivers/serial/8250_pci.c b/trunk/drivers/serial/8250_pci.c index c014ffb110e9..c2f23933155b 100644 --- a/trunk/drivers/serial/8250_pci.c +++ b/trunk/drivers/serial/8250_pci.c @@ -2041,9 +2041,9 @@ static int pciserial_resume_one(struct pci_dev *dev) * The device may have been disabled. Re-enable it. */ err = pci_enable_device(dev); - /* FIXME: We cannot simply error out here */ if (err) - printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); + return err; + pciserial_resume_ports(priv); } return 0; diff --git a/trunk/drivers/serial/Kconfig b/trunk/drivers/serial/Kconfig index 31786b3b0a68..77cb34270fc1 100644 --- a/trunk/drivers/serial/Kconfig +++ b/trunk/drivers/serial/Kconfig @@ -9,6 +9,7 @@ menu "Serial drivers" # The new 8250/16550 serial drivers config SERIAL_8250 tristate "8250/16550 and compatible serial support" + depends on (BROKEN || !SPARC) select SERIAL_CORE ---help--- This selects whether you want to include the driver for the standard @@ -993,12 +994,24 @@ config SERIAL_68328_RTS_CTS bool "Support RTS/CTS on 68328 serial port" depends on SERIAL_68328 +config SERIAL_COLDFIRE + bool "ColdFire serial support (DEPRECATED)" + depends on COLDFIRE + help + This driver supports the built-in serial ports of the Motorola ColdFire + family of CPUs. + This driver is deprecated because it supports only the old interface + for serial drivers and features like magic keys are not working. + Please switch to the new style driver because this driver will be + removed soon. + config SERIAL_MCF - bool "Coldfire serial support" + bool "Coldfire serial support (new style driver)" depends on COLDFIRE select SERIAL_CORE help - This serial driver supports the Freescale Coldfire serial ports. + This new serial driver supports the Freescale Coldfire serial ports + using the new serial driver subsystem. config SERIAL_MCF_BAUDRATE int "Default baudrate for Coldfire serial ports" diff --git a/trunk/drivers/serial/Makefile b/trunk/drivers/serial/Makefile index 0c17c8ddb19d..7e7383e890d8 100644 --- a/trunk/drivers/serial/Makefile +++ b/trunk/drivers/serial/Makefile @@ -4,16 +4,6 @@ obj-$(CONFIG_SERIAL_CORE) += serial_core.o obj-$(CONFIG_SERIAL_21285) += 21285.o - -# These Sparc drivers have to appear before others such as 8250 -# which share ttySx minor node space. Otherwise console device -# names change and other unplesantries. -obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o -obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o -obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o -obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o -obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o - obj-$(CONFIG_SERIAL_8250) += 8250.o obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o @@ -41,10 +31,16 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o +obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o +obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o +obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o +obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o +obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_68360) += 68360serial.o +obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o diff --git a/trunk/drivers/serial/bfin_5xx.c b/trunk/drivers/serial/bfin_5xx.c index 569f0e2476c6..4a0d30bed9f1 100644 --- a/trunk/drivers/serial/bfin_5xx.c +++ b/trunk/drivers/serial/bfin_5xx.c @@ -1,7 +1,7 @@ /* * Blackfin On-Chip Serial Driver * - * Copyright 2006-2008 Analog Devices Inc. + * Copyright 2006-2007 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -42,9 +42,6 @@ #define BFIN_SERIAL_MAJOR 204 #define BFIN_SERIAL_MINOR 64 -static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; -static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource); - /* * Setup for console. Argument comes from the menuconfig */ @@ -129,13 +126,13 @@ static int kgdb_entry_state; void kgdb_put_debug_char(int chr) { struct bfin_serial_port *uart; - + if (CONFIG_KGDB_UART_PORT < 0 || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS) uart = &bfin_serial_ports[0]; else uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - + while (!(UART_GET_LSR(uart) & THRE)) { SSYNC(); } @@ -155,7 +152,7 @@ int kgdb_get_debug_char(void) uart = &bfin_serial_ports[0]; else uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - + while(!(UART_GET_LSR(uart) & DR)) { SSYNC(); } @@ -301,11 +298,7 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) bfin_serial_mctrl_check(uart); if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { -#ifdef CONFIG_BF54x - /* Clear TFI bit */ - UART_PUT_LSR(uart, TFI); -#endif - UART_CLEAR_IER(uart, ETBEI); + bfin_serial_stop_tx(&uart->port); return; } @@ -324,6 +317,9 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uart->port); + + if (uart_circ_empty(xmit)) + bfin_serial_stop_tx(&uart->port); } static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) @@ -649,42 +645,6 @@ static int bfin_serial_startup(struct uart_port *port) free_irq(uart->port.irq, uart); return -EBUSY; } - -# ifdef CONFIG_BF54x - { - unsigned uart_dma_ch_rx, uart_dma_ch_tx; - - switch (uart->port.irq) { - case IRQ_UART3_RX: - uart_dma_ch_rx = CH_UART3_RX; - uart_dma_ch_tx = CH_UART3_TX; - break; - case IRQ_UART2_RX: - uart_dma_ch_rx = CH_UART2_RX; - uart_dma_ch_tx = CH_UART2_TX; - break; - default: - uart_dma_ch_rx = uart_dma_ch_tx = 0; - break; - }; - - if (uart_dma_ch_rx && - request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { - printk(KERN_NOTICE"Fail to attach UART interrupt\n"); - free_irq(uart->port.irq, uart); - free_irq(uart->port.irq + 1, uart); - return -EBUSY; - } - if (uart_dma_ch_tx && - request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) { - printk(KERN_NOTICE "Fail to attach UART interrupt\n"); - free_dma(uart_dma_ch_rx); - free_irq(uart->port.irq, uart); - free_irq(uart->port.irq + 1, uart); - return -EBUSY; - } - } -# endif #endif UART_SET_IER(uart, ERBFI); return 0; @@ -702,20 +662,6 @@ static void bfin_serial_shutdown(struct uart_port *port) del_timer(&(uart->rx_dma_timer)); dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0); #else -#ifdef CONFIG_BF54x - switch (uart->port.irq) { - case IRQ_UART3_RX: - free_dma(CH_UART3_RX); - free_dma(CH_UART3_TX); - break; - case IRQ_UART2_RX: - free_dma(CH_UART2_RX); - free_dma(CH_UART2_TX); - break; - default: - break; - }; -#endif #ifdef CONFIG_KGDB_UART if (uart->port.line != CONFIG_KGDB_UART_PORT) #endif @@ -811,9 +757,6 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, val |= UCEN; UART_PUT_GCTL(uart, val); - /* Port speed changed, update the per-port timeout. */ - uart_update_timeout(port, termios->c_cflag, baud); - spin_unlock_irqrestore(&uart->port.lock, flags); } @@ -916,9 +859,8 @@ static void __init bfin_serial_init_ports(void) return; first = 0; - for (i = 0; i < nr_active_ports; i++) { + for (i = 0; i < nr_ports; i++) { bfin_serial_ports[i].port.uartclk = get_sclk(); - bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE; bfin_serial_ports[i].port.ops = &bfin_serial_pops; bfin_serial_ports[i].port.line = i; bfin_serial_ports[i].port.iotype = UPIO_MEM; @@ -1019,7 +961,7 @@ bfin_serial_console_setup(struct console *co, char *options) * if so, search for the first available port that does have * console support. */ - if (co->index == -1 || co->index >= nr_active_ports) + if (co->index == -1 || co->index >= nr_ports) co->index = 0; uart = &bfin_serial_ports[co->index]; @@ -1114,7 +1056,7 @@ static __init void early_serial_write(struct console *con, const char *s, } } -static struct __initdata console bfin_early_serial_console = { +static struct __init console bfin_early_serial_console = { .name = "early_BFuart", .write = early_serial_write, .device = uart_console_device, @@ -1130,7 +1072,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port, struct bfin_serial_port *uart; struct ktermios t; - if (port == -1 || port >= nr_active_ports) + if (port == -1 || port >= nr_ports) port = 0; bfin_serial_init_ports(); bfin_early_serial_console.index = port; @@ -1158,26 +1100,20 @@ static struct uart_driver bfin_serial_reg = { static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state) { - int i; + struct bfin_serial_port *uart = platform_get_drvdata(dev); - for (i = 0; i < nr_active_ports; i++) { - if (bfin_serial_ports[i].port.dev != &dev->dev) - continue; - uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port); - } + if (uart) + uart_suspend_port(&bfin_serial_reg, &uart->port); return 0; } static int bfin_serial_resume(struct platform_device *dev) { - int i; + struct bfin_serial_port *uart = platform_get_drvdata(dev); - for (i = 0; i < nr_active_ports; i++) { - if (bfin_serial_ports[i].port.dev != &dev->dev) - continue; - uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port); - } + if (uart) + uart_resume_port(&bfin_serial_reg, &uart->port); return 0; } @@ -1192,31 +1128,32 @@ static int bfin_serial_probe(struct platform_device *dev) break; if (i < dev->num_resources) { - for (i = 0; i < nr_active_ports; i++, res++) { + for (i = 0; i < nr_ports; i++, res++) { if (bfin_serial_ports[i].port.mapbase != res->start) continue; bfin_serial_ports[i].port.dev = &dev->dev; uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + platform_set_drvdata(dev, &bfin_serial_ports[i]); } } return 0; } -static int bfin_serial_remove(struct platform_device *dev) +static int bfin_serial_remove(struct platform_device *pdev) { - int i; + struct bfin_serial_port *uart = platform_get_drvdata(pdev); + - for (i = 0; i < nr_active_ports; i++) { - if (bfin_serial_ports[i].port.dev != &dev->dev) - continue; - uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); - bfin_serial_ports[i].port.dev = NULL; #ifdef CONFIG_SERIAL_BFIN_CTSRTS - gpio_free(bfin_serial_ports[i].cts_pin); - gpio_free(bfin_serial_ports[i].rts_pin); + gpio_free(uart->cts_pin); + gpio_free(uart->rts_pin); #endif - } + + platform_set_drvdata(pdev, NULL); + + if (uart) + uart_remove_one_port(&bfin_serial_reg, &uart->port); return 0; } diff --git a/trunk/drivers/serial/crisv10.c b/trunk/drivers/serial/crisv10.c index 211c21797ce0..bf94a770bb44 100644 --- a/trunk/drivers/serial/crisv10.c +++ b/trunk/drivers/serial/crisv10.c @@ -457,6 +457,7 @@ static struct e100_serial rs_table[] = { #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) static struct ktermios *serial_termios[NR_PORTS]; +static struct ktermios *serial_termios_locked[NR_PORTS]; #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER static struct fast_timer fast_timers[NR_PORTS]; #endif @@ -4418,7 +4419,6 @@ rs_init(void) rs485_pa_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); - put_tty_driver(driver); return -EBUSY; } #endif @@ -4427,7 +4427,6 @@ rs_init(void) rs485_port_g_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); - put_tty_driver(driver); return -EBUSY; } #endif @@ -4447,6 +4446,8 @@ rs_init(void) driver->init_termios.c_ispeed = 115200; driver->init_termios.c_ospeed = 115200; driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + driver->termios = serial_termios; + driver->termios_locked = serial_termios_locked; tty_set_operations(driver, &rs_ops); serial_driver = driver; diff --git a/trunk/drivers/serial/mcfserial.c b/trunk/drivers/serial/mcfserial.c new file mode 100644 index 000000000000..fbe3835f6b77 --- /dev/null +++ b/trunk/drivers/serial/mcfserial.c @@ -0,0 +1,1965 @@ +#warning This driver is deprecated. Check Kconfig for details. +/* + * mcfserial.c -- serial driver for ColdFire internal UARTS. + * + * Copyright (C) 1999-2003 Greg Ungerer + * Copyright (c) 2000-2001 Lineo, Inc. + * Copyright (C) 2001-2002 SnapGear Inc. + * + * Based on code from 68332serial.c which was: + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 TSHG + * Copyright (c) 1999 Rt-Control Inc. + * + * Changes: + * 08/07/2003 Daniele Bellucci + * some cleanups in mcfrs_write. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mcfserial.h" + +struct timer_list mcfrs_timer_struct; + +/* + * Default console baud rate, we use this as the default + * for all ports so init can just open /dev/console and + * keep going. Perhaps one day the cflag settings for the + * console can be used instead. + */ +#if defined(CONFIG_HW_FEITH) +#define CONSOLE_BAUD_RATE 38400 +#define DEFAULT_CBAUD B38400 +#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \ + defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO) +#define CONSOLE_BAUD_RATE 115200 +#define DEFAULT_CBAUD B115200 +#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \ + defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET) +#define CONSOLE_BAUD_RATE 19200 +#define DEFAULT_CBAUD B19200 +#endif + +#ifndef CONSOLE_BAUD_RATE +#define CONSOLE_BAUD_RATE 9600 +#define DEFAULT_CBAUD B9600 +#endif + +int mcfrs_console_inited = 0; +int mcfrs_console_port = -1; +int mcfrs_console_baud = CONSOLE_BAUD_RATE; +int mcfrs_console_cbaud = DEFAULT_CBAUD; + +/* + * Driver data structures. + */ +static struct tty_driver *mcfrs_serial_driver; + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* Debugging... + */ +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW + +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) || defined(CONFIG_M532x) +#define IRQBASE (MCFINT_VECBASE+MCFINT_UART0) +#else +#define IRQBASE 73 +#endif + +/* + * Configuration table, UARTs to look for at startup. + */ +static struct mcf_serial mcfrs_table[] = { + { /* ttyS0 */ + .magic = 0, + .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1), + .irq = IRQBASE, + .flags = ASYNC_BOOT_AUTOCONF, + }, +#ifdef MCFUART_BASE2 + { /* ttyS1 */ + .magic = 0, + .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2), + .irq = IRQBASE+1, + .flags = ASYNC_BOOT_AUTOCONF, + }, +#endif +#ifdef MCFUART_BASE3 + { /* ttyS2 */ + .magic = 0, + .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3), + .irq = IRQBASE+2, + .flags = ASYNC_BOOT_AUTOCONF, + }, +#endif +#ifdef MCFUART_BASE4 + { /* ttyS3 */ + .magic = 0, + .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4), + .irq = IRQBASE+3, + .flags = ASYNC_BOOT_AUTOCONF, + }, +#endif +}; + + +#define NR_PORTS (sizeof(mcfrs_table) / sizeof(struct mcf_serial)) + +/* + * This is used to figure out the divisor speeds and the timeouts. + */ +static int mcfrs_baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 +}; +#define MCFRS_BAUD_TABLE_SIZE \ + (sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0])) + + +#ifdef CONFIG_MAGIC_SYSRQ +/* + * Magic system request keys. Used for debugging... + */ +extern int magic_sysrq_key(int ch); +#endif + + +/* + * Forware declarations... + */ +static void mcfrs_change_speed(struct mcf_serial *info); +static void mcfrs_wait_until_sent(struct tty_struct *tty, int timeout); + + +static inline int serial_paranoia_check(struct mcf_serial *info, + char *name, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char badmagic[] = + "MCFRS(warning): bad magic number for serial struct %s in %s\n"; + static const char badinfo[] = + "MCFRS(warning): null mcf_serial for %s in %s\n"; + + if (!info) { + printk(badinfo, name, routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, name, routine); + return 1; + } +#endif + return 0; +} + +/* + * Sets or clears DTR and RTS on the requested line. + */ +static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts) +{ + volatile unsigned char *uartp; + unsigned long flags; + +#if 0 + printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n", + __FILE__, __LINE__, info, dtr, rts); +#endif + + local_irq_save(flags); + if (dtr >= 0) { +#ifdef MCFPP_DTR0 + if (info->line) + mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1)); + else + mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0)); +#endif + } + if (rts >= 0) { + uartp = info->addr; + if (rts) { + info->sigs |= TIOCM_RTS; + uartp[MCFUART_UOP1] = MCFUART_UOP_RTS; + } else { + info->sigs &= ~TIOCM_RTS; + uartp[MCFUART_UOP0] = MCFUART_UOP_RTS; + } + } + local_irq_restore(flags); + return; +} + +/* + * Gets values of serial signals. + */ +static int mcfrs_getsignals(struct mcf_serial *info) +{ + volatile unsigned char *uartp; + unsigned long flags; + int sigs; +#if defined(CONFIG_NETtel) && defined(CONFIG_M5307) + unsigned short ppdata; +#endif + +#if 0 + printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__); +#endif + + local_irq_save(flags); + uartp = info->addr; + sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS; + sigs |= (info->sigs & TIOCM_RTS); + +#ifdef MCFPP_DCD0 +{ + unsigned int ppdata; + ppdata = mcf_getppdata(); + if (info->line == 0) { + sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD; + sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR; + } else if (info->line == 1) { + sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD; + sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR; + } +} +#endif + + local_irq_restore(flags); + return(sigs); +} + +/* + * ------------------------------------------------------------ + * mcfrs_stop() and mcfrs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void mcfrs_stop(struct tty_struct *tty) +{ + volatile unsigned char *uartp; + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "mcfrs_stop")) + return; + + local_irq_save(flags); + uartp = info->addr; + info->imr &= ~MCFUART_UIR_TXREADY; + uartp[MCFUART_UIMR] = info->imr; + local_irq_restore(flags); +} + +static void mcfrs_start(struct tty_struct *tty) +{ + volatile unsigned char *uartp; + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "mcfrs_start")) + return; + + local_irq_save(flags); + if (info->xmit_cnt && info->xmit_buf) { + uartp = info->addr; + info->imr |= MCFUART_UIR_TXREADY; + uartp[MCFUART_UIMR] = info->imr; + } + local_irq_restore(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * mcfrs_interrupt(). They were separated out for readability's sake. + * + * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * mcfrs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +static inline void receive_chars(struct mcf_serial *info) +{ + volatile unsigned char *uartp; + struct tty_struct *tty = info->port.tty; + unsigned char status, ch, flag; + + if (!tty) + return; + + uartp = info->addr; + + while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) { + ch = uartp[MCFUART_URB]; + info->stats.rx++; + +#ifdef CONFIG_MAGIC_SYSRQ + if (mcfrs_console_inited && (info->line == mcfrs_console_port)) { + if (magic_sysrq_key(ch)) + continue; + } +#endif + + flag = TTY_NORMAL; + if (status & MCFUART_USR_RXERR) { + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR; + if (status & MCFUART_USR_RXBREAK) { + info->stats.rxbreak++; + flag = TTY_BREAK; + } else if (status & MCFUART_USR_RXPARITY) { + info->stats.rxparity++; + flag = TTY_PARITY; + } else if (status & MCFUART_USR_RXOVERRUN) { + info->stats.rxoverrun++; + flag = TTY_OVERRUN; + } else if (status & MCFUART_USR_RXFRAMING) { + info->stats.rxframing++; + flag = TTY_FRAME; + } + } + tty_insert_flip_char(tty, ch, flag); + } + tty_schedule_flip(tty); + return; +} + +static inline void transmit_chars(struct mcf_serial *info) +{ + volatile unsigned char *uartp; + + uartp = info->addr; + + if (info->x_char) { + /* Send special char - probably flow control */ + uartp[MCFUART_UTB] = info->x_char; + info->x_char = 0; + info->stats.tx++; + } + + if ((info->xmit_cnt <= 0) || info->port.tty->stopped) { + info->imr &= ~MCFUART_UIR_TXREADY; + uartp[MCFUART_UIMR] = info->imr; + return; + } + + while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) { + uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->stats.tx++; + if (--info->xmit_cnt <= 0) + break; + } + + if (info->xmit_cnt < WAKEUP_CHARS) + schedule_work(&info->tqueue); + return; +} + +/* + * This is the serial driver's generic interrupt routine + */ +irqreturn_t mcfrs_interrupt(int irq, void *dev_id) +{ + struct mcf_serial *info; + unsigned char isr; + + info = &mcfrs_table[(irq - IRQBASE)]; + isr = info->addr[MCFUART_UISR] & info->imr; + + if (isr & MCFUART_UIR_RXREADY) + receive_chars(info); + if (isr & MCFUART_UIR_TXREADY) + transmit_chars(info); + return IRQ_HANDLED; +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +static void mcfrs_offintr(struct work_struct *work) +{ + struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue); + struct tty_struct *tty = info->port.tty; + + if (tty) + tty_wakeup(tty); +} + + +/* + * Change of state on a DCD line. + */ +void mcfrs_modem_change(struct mcf_serial *info, int dcd) +{ + if (info->count == 0) + return; + + if (info->flags & ASYNC_CHECK_CD) { + if (dcd) + wake_up_interruptible(&info->open_wait); + else + schedule_work(&info->tqueue_hangup); + } +} + + +#ifdef MCFPP_DCD0 + +unsigned short mcfrs_ppstatus; + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * to monitor the state of the DCD lines - since they have no edge + * sensors and interrupt generators. + */ +static void mcfrs_timer(void) +{ + unsigned int ppstatus, dcdval, i; + + ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1); + + if (ppstatus != mcfrs_ppstatus) { + for (i = 0; (i < 2); i++) { + dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0); + if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) { + mcfrs_modem_change(&mcfrs_table[i], + ((ppstatus & dcdval) ? 0 : 1)); + } + } + } + mcfrs_ppstatus = ppstatus; + + /* Re-arm timer */ + mcfrs_timer_struct.expires = jiffies + HZ/25; + add_timer(&mcfrs_timer_struct); +} + +#endif /* MCFPP_DCD0 */ + + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> mcfrs_hangup() + * + */ +static void do_serial_hangup(struct work_struct *work) +{ + struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup); + struct tty_struct *tty = info->port.tty; + + if (tty) + tty_hangup(tty); +} + +static int startup(struct mcf_serial * info) +{ + volatile unsigned char *uartp; + unsigned long flags; + + if (info->flags & ASYNC_INITIALIZED) + return 0; + + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL); + if (!info->xmit_buf) + return -ENOMEM; + } + + local_irq_save(flags); + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq); +#endif + + /* + * Reset UART, get it into known state... + */ + uartp = info->addr; + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ + mcfrs_setsignals(info, 1, 1); + + if (info->port.tty) + clear_bit(TTY_IO_ERROR, &info->port.tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * and set the speed of the serial port + */ + mcfrs_change_speed(info); + + /* + * Lastly enable the UART transmitter and receiver, and + * interrupt enables. + */ + info->imr = MCFUART_UIR_RXREADY; + uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; + uartp[MCFUART_UIMR] = info->imr; + + info->flags |= ASYNC_INITIALIZED; + local_irq_restore(flags); + return 0; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct mcf_serial * info) +{ + volatile unsigned char *uartp; + unsigned long flags; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....\n", info->line, + info->irq); +#endif + + local_irq_save(flags); + + uartp = info->addr; + uartp[MCFUART_UIMR] = 0; /* mask all interrupts */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ + + if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) + mcfrs_setsignals(info, 0, 0); + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + if (info->port.tty) + set_bit(TTY_IO_ERROR, &info->port.tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + local_irq_restore(flags); +} + + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void mcfrs_change_speed(struct mcf_serial *info) +{ + volatile unsigned char *uartp; + unsigned int baudclk, cflag; + unsigned long flags; + unsigned char mr1, mr2; + int i; +#ifdef CONFIG_M5272 + unsigned int fraction; +#endif + + if (!info->port.tty || !info->port.tty->termios) + return; + cflag = info->port.tty->termios->c_cflag; + if (info->addr == 0) + return; + +#if 0 + printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__); +#endif + + i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~CBAUDEX; + if (i < 1 || i > 4) + info->port.tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + if (i == 0) { + mcfrs_setsignals(info, 0, -1); + return; + } + + /* compute the baudrate clock */ +#ifdef CONFIG_M5272 + /* + * For the MCF5272, also compute the baudrate fraction. + */ + baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32; + fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]); + fraction *= 16; + fraction /= (32 * mcfrs_baud_table[i]); +#else + baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32; +#endif + + info->baud = mcfrs_baud_table[i]; + + mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; + mr2 = 0; + + switch (cflag & CSIZE) { + case CS5: mr1 |= MCFUART_MR1_CS5; break; + case CS6: mr1 |= MCFUART_MR1_CS6; break; + case CS7: mr1 |= MCFUART_MR1_CS7; break; + case CS8: + default: mr1 |= MCFUART_MR1_CS8; break; + } + + if (cflag & PARENB) { + if (cflag & CMSPAR) { + if (cflag & PARODD) + mr1 |= MCFUART_MR1_PARITYMARK; + else + mr1 |= MCFUART_MR1_PARITYSPACE; + } else { + if (cflag & PARODD) + mr1 |= MCFUART_MR1_PARITYODD; + else + mr1 |= MCFUART_MR1_PARITYEVEN; + } + } else { + mr1 |= MCFUART_MR1_PARITYNONE; + } + + if (cflag & CSTOPB) + mr2 |= MCFUART_MR2_STOP2; + else + mr2 |= MCFUART_MR2_STOP1; + + if (cflag & CRTSCTS) { + mr1 |= MCFUART_MR1_RXRTS; + mr2 |= MCFUART_MR2_TXCTS; + } + + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + uartp = info->addr; + + local_irq_save(flags); +#if 0 + printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__, + mr1, mr2, baudclk); +#endif + /* + Note: pg 12-16 of MCF5206e User's Manual states that a + software reset should be performed prior to changing + UMR1,2, UCSR, UACR, bit 7 + */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ + uartp[MCFUART_UMR] = mr1; + uartp[MCFUART_UMR] = mr2; + uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8; /* set msb byte */ + uartp[MCFUART_UBG2] = (baudclk & 0xff); /* set lsb byte */ +#ifdef CONFIG_M5272 + uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ +#endif + uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; + uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; + mcfrs_setsignals(info, 1, -1); + local_irq_restore(flags); + return; +} + +static void mcfrs_flush_chars(struct tty_struct *tty) +{ + volatile unsigned char *uartp; + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars")) + return; + + uartp = (volatile unsigned char *) info->addr; + + /* + * re-enable receiver interrupt + */ + local_irq_save(flags); + if ((!(info->imr & MCFUART_UIR_RXREADY)) && + (info->flags & ASYNC_INITIALIZED) ) { + info->imr |= MCFUART_UIR_RXREADY; + uartp[MCFUART_UIMR] = info->imr; + } + local_irq_restore(flags); + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + /* Enable transmitter */ + local_irq_save(flags); + info->imr |= MCFUART_UIR_TXREADY; + uartp[MCFUART_UIMR] = info->imr; + local_irq_restore(flags); +} + +static int mcfrs_write(struct tty_struct * tty, + const unsigned char *buf, int count) +{ + volatile unsigned char *uartp; + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; + unsigned long flags; + int c, total = 0; + +#if 0 + printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n", + __FILE__, __LINE__, (int)tty, (int)buf, count); +#endif + + if (serial_paranoia_check(info, tty->name, "mcfrs_write")) + return 0; + + if (!tty || !info->xmit_buf) + return 0; + + local_save_flags(flags); + while (1) { + local_irq_disable(); + c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1, + ((int)SERIAL_XMIT_SIZE) - info->xmit_head)); + local_irq_restore(flags); + + if (c <= 0) + break; + + memcpy(info->xmit_buf + info->xmit_head, buf, c); + + local_irq_disable(); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + local_irq_restore(flags); + + buf += c; + count -= c; + total += c; + } + + local_irq_disable(); + uartp = info->addr; + info->imr |= MCFUART_UIR_TXREADY; + uartp[MCFUART_UIMR] = info->imr; + local_irq_restore(flags); + + return total; +} + +static int mcfrs_write_room(struct tty_struct *tty) +{ + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->name, "mcfrs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int mcfrs_chars_in_buffer(struct tty_struct *tty) +{ + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "mcfrs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void mcfrs_flush_buffer(struct tty_struct *tty) +{ + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->name, "mcfrs_flush_buffer")) + return; + + local_irq_save(flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + local_irq_restore(flags); + + tty_wakeup(tty); +} + +/* + * ------------------------------------------------------------ + * mcfrs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void mcfrs_throttle(struct tty_struct * tty) +{ + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->name, "mcfrs_throttle")) + return; + + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); + + /* Turn off RTS line (do this atomic) */ +} + +static void mcfrs_unthrottle(struct tty_struct * tty) +{ + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->name, "mcfrs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } + + /* Assert RTS line (do this atomic) */ +} + +/* + * ------------------------------------------------------------ + * mcfrs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct mcf_serial * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = (unsigned int) info->addr; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0; +} + +static int set_serial_info(struct mcf_serial * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct mcf_serial old_info; + int retval = 0; + + if (!new_info) + return -EFAULT; + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; + old_info = *info; + + if (!capable(CAP_SYS_ADMIN)) { + if ((new_serial.baud_base != info->baud_base) || + (new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if (info->count > 1) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->baud_base = new_serial.baud_base; + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + +check_and_exit: + retval = startup(info); + return retval; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct mcf_serial * info, unsigned int *value) +{ + volatile unsigned char *uartp; + unsigned long flags; + unsigned char status; + + local_irq_save(flags); + uartp = info->addr; + status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0; + local_irq_restore(flags); + + return put_user(status,value); +} + +/* + * This routine sends a break character out the serial port. + */ +static void send_break( struct mcf_serial * info, int duration) +{ + volatile unsigned char *uartp; + unsigned long flags; + + if (!info->addr) + return; + set_current_state(TASK_INTERRUPTIBLE); + uartp = info->addr; + + local_irq_save(flags); + uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART; + schedule_timeout(duration); + uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP; + local_irq_restore(flags); +} + +static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) + return -ENODEV; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + + return mcfrs_getsignals(info); +} + +static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; + int rts = -1, dtr = -1; + + if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) + return -ENODEV; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + + if (set & TIOCM_RTS) + rts = 1; + if (set & TIOCM_DTR) + dtr = 1; + if (clear & TIOCM_RTS) + rts = 0; + if (clear & TIOCM_DTR) + dtr = 0; + + mcfrs_setsignals(info, dtr, rts); + + return 0; +} + +static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; + int retval, error; + + if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + send_break(info, HZ/4); /* 1/4 second */ + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + send_break(info, arg ? arg*(HZ/10) : HZ/4); + return 0; + case TIOCGSERIAL: + if (access_ok(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) + return get_serial_info(info, + (struct serial_struct *) arg); + return -EFAULT; + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERGETLSR: /* Get line status register */ + if (access_ok(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) + return get_lsr_info(info, (unsigned int *) arg); + return -EFAULT; + case TIOCSERGSTRUCT: + error = copy_to_user((struct mcf_serial *) arg, + info, sizeof(struct mcf_serial)); + if (error) + return -EFAULT; + return 0; + +#ifdef TIOCSET422 + case TIOCSET422: { + unsigned int val; + get_user(val, (unsigned int *) arg); + mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11)); + break; + } + case TIOCGET422: { + unsigned int val; + val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1; + put_user(val, (unsigned int *) arg); + break; + } +#endif + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +{ + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + + mcfrs_change_speed(info); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + mcfrs_setsignals(info, -1, 1); +#if 0 + mcfrs_start(tty); +#endif + } +} + +/* + * ------------------------------------------------------------ + * mcfrs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * S structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void mcfrs_close(struct tty_struct *tty, struct file * filp) +{ + volatile unsigned char *uartp; + struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close")) + return; + + local_irq_save(flags); + + if (tty_hung_up_p(filp)) { + local_irq_restore(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count); +#endif + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("MCFRS: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("MCFRS: bad serial port count for ttyS%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) { + local_irq_restore(flags); + return; + } + info->flags |= ASYNC_CLOSING; + + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->imr &= ~MCFUART_UIR_RXREADY; + uartp = info->addr; + uartp[MCFUART_UIMR] = info->imr; + +#if 0 + /* FIXME: do we need to keep this enabled for console?? */ + if (mcfrs_console_inited && (mcfrs_console_port == info->line)) { + /* Do not disable the UART */ ; + } else +#endif + shutdown(info); + mcfrs_flush_buffer(tty); + tty_ldisc_flush(tty); + + tty->closing = 0; + info->event = 0; + info->port.tty = NULL; +#if 0 + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } +#endif + if (info->blocked_open) { + if (info->close_delay) { + msleep_interruptible(jiffies_to_msecs(info->close_delay)); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + local_irq_restore(flags); +} + +/* + * mcfrs_wait_until_sent() --- wait until the transmitter is empty + */ +static void +mcfrs_wait_until_sent(struct tty_struct *tty, int timeout) +{ +#ifdef CONFIG_M5272 +#define MCF5272_FIFO_SIZE 25 /* fifo size + shift reg */ + + struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; + volatile unsigned char *uartp; + unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt; + + if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent")) + return; + + orig_jiffies = jiffies; + + /* + * Set the check interval to be 1/5 of the approximate time + * to send the entire fifo, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + lock_kernel(); + + fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud; + char_time = fifo_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout && timeout < char_time) + char_time = timeout; + + /* + * Clamp the timeout period at 2 * the time to empty the + * fifo. Just to be safe, set the minimum at .5 seconds. + */ + fifo_time *= 2; + if (fifo_time < (HZ/2)) + fifo_time = HZ/2; + if (!timeout || timeout > fifo_time) + timeout = fifo_time; + + /* + * Account for the number of bytes in the UART + * transmitter FIFO plus any byte being shifted out. + */ + uartp = (volatile unsigned char *) info->addr; + for (;;) { + fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB); + if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY| + MCFUART_USR_TXEMPTY)) == + MCFUART_USR_TXREADY) + fifo_cnt++; + if (fifo_cnt == 0) + break; + msleep_interruptible(jiffies_to_msecs(char_time)); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + unlock_kernel(); +#else + /* + * For the other coldfire models, assume all data has been sent + */ +#endif +} + +/* + * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void mcfrs_hangup(struct tty_struct *tty) +{ + struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->name, "mcfrs_hangup")) + return; + + mcfrs_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~ASYNC_NORMAL_ACTIVE; + info->port.tty = NULL; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * mcfrs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct mcf_serial *info) +{ + DECLARE_WAITQUEUE(wait, current); + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * mcfrs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttyS%d, count = %d\n", + info->line, info->count); +#endif + info->count--; + info->blocked_open++; + while (1) { + local_irq_disable(); + mcfrs_setsignals(info, 1, 1); + local_irq_enable(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CLOSING) && + (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttyS%d, count = %d\n", + info->line, info->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttyS%d, count = %d\n", + info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +int mcfrs_open(struct tty_struct *tty, struct file * filp) +{ + struct mcf_serial *info; + int retval, line; + + line = tty->index; + if ((line < 0) || (line >= NR_PORTS)) + return -ENODEV; + info = mcfrs_table + line; + if (serial_paranoia_check(info, tty->name, "mcfrs_open")) + return -ENODEV; +#ifdef SERIAL_DEBUG_OPEN + printk("mcfrs_open %s, count = %d\n", tty->name, info->count); +#endif + info->count++; + tty->driver_data = info; + info->port.tty = tty; + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + return retval; + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("mcfrs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("mcfrs_open %s successful...\n", tty->name); +#endif + return 0; +} + +/* + * Based on the line number set up the internal interrupt stuff. + */ +static void mcfrs_irqinit(struct mcf_serial *info) +{ +#if defined(CONFIG_M5272) + volatile unsigned long *icrp; + volatile unsigned long *portp; + volatile unsigned char *uartp; + + uartp = info->addr; + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2); + + switch (info->line) { + case 0: + *icrp = 0xe0000000; + break; + case 1: + *icrp = 0x0e000000; + break; + default: + printk("MCFRS: don't know how to handle UART %d interrupt?\n", + info->line); + return; + } + + /* Enable the output lines for the serial ports */ + portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT); + *portp = (*portp & ~0x000000ff) | 0x00000055; + portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT); + *portp = (*portp & ~0x000003fc) | 0x000002a8; +#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) + volatile unsigned char *icrp, *uartp; + volatile unsigned long *imrp; + + uartp = info->addr; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + + MCFINTC_ICR0 + MCFINT_UART0 + info->line); + *icrp = 0x30 + info->line; /* level 6, line based priority */ + + imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + + MCFINTC_IMRL); + *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); +#if defined(CONFIG_M527x) + { + /* + * External Pin Mask Setting & Enable External Pin for Interface + * mrcbis@aliceposta.it + */ + u16 *serpin_enable_mask; + serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART); + if (info->line == 0) + *serpin_enable_mask |= UART0_ENABLE_MASK; + else if (info->line == 1) + *serpin_enable_mask |= UART1_ENABLE_MASK; + else if (info->line == 2) + *serpin_enable_mask |= UART2_ENABLE_MASK; + } +#endif +#if defined(CONFIG_M528x) + /* make sure PUAPAR is set for UART0 and UART1 */ + if (info->line < 2) { + volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR); + *portp |= (0x03 << (info->line * 2)); + } +#endif +#elif defined(CONFIG_M520x) + volatile unsigned char *icrp, *uartp; + volatile unsigned long *imrp; + + uartp = info->addr; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + + MCFINTC_ICR0 + MCFINT_UART0 + info->line); + *icrp = 0x03; + + imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + + MCFINTC_IMRL); + *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); + if (info->line < 2) { + unsigned short *uart_par; + uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART); + if (info->line == 0) + *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0 + | MCF_GPIO_PAR_UART_PAR_URXD0; + else if (info->line == 1) + *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1 + | MCF_GPIO_PAR_UART_PAR_URXD1; + } else if (info->line == 2) { + unsigned char *feci2c_par; + feci2c_par = (unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); + *feci2c_par &= ~0x0F; + *feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 + | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; + } +#elif defined(CONFIG_M532x) + volatile unsigned char *uartp; + uartp = info->addr; + switch (info->line) { + case 0: + MCF_INTC0_ICR26 = 0x3; + MCF_INTC0_CIMR = 26; + /* GPIO initialization */ + MCF_GPIO_PAR_UART |= 0x000F; + break; + case 1: + MCF_INTC0_ICR27 = 0x3; + MCF_INTC0_CIMR = 27; + /* GPIO initialization */ + MCF_GPIO_PAR_UART |= 0x0FF0; + break; + case 2: + MCF_INTC0_ICR28 = 0x3; + MCF_INTC0_CIMR = 28; + /* GPIOs also must be initalized, depends on board */ + break; + } +#else + volatile unsigned char *icrp, *uartp; + + switch (info->line) { + case 0: + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR); + *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | + MCFSIM_ICR_PRI1; + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); + break; + case 1: + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR); + *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | + MCFSIM_ICR_PRI2; + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); + break; + default: + printk("MCFRS: don't know how to handle UART %d interrupt?\n", + info->line); + return; + } + + uartp = info->addr; + uartp[MCFUART_UIVR] = info->irq; +#endif + + /* Clear mask, so no surprise interrupts. */ + uartp[MCFUART_UIMR] = 0; + + if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED, + "ColdFire UART", NULL)) { + printk("MCFRS: Unable to attach ColdFire UART %d interrupt " + "vector=%d\n", info->line, info->irq); + } + + return; +} + + +char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n"; + + +/* + * Serial stats reporting... + */ +int mcfrs_readproc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + struct mcf_serial *info; + char str[20]; + int len, sigs, i; + + len = sprintf(page, mcfrs_drivername); + for (i = 0; (i < NR_PORTS); i++) { + info = &mcfrs_table[i]; + len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ", + i, (unsigned int) info->addr, info->irq, info->baud); + if (info->stats.rx || info->stats.tx) + len += sprintf((page + len), "tx:%d rx:%d ", + info->stats.tx, info->stats.rx); + if (info->stats.rxframing) + len += sprintf((page + len), "fe:%d ", + info->stats.rxframing); + if (info->stats.rxparity) + len += sprintf((page + len), "pe:%d ", + info->stats.rxparity); + if (info->stats.rxbreak) + len += sprintf((page + len), "brk:%d ", + info->stats.rxbreak); + if (info->stats.rxoverrun) + len += sprintf((page + len), "oe:%d ", + info->stats.rxoverrun); + + str[0] = str[1] = 0; + if ((sigs = mcfrs_getsignals(info))) { + if (sigs & TIOCM_RTS) + strcat(str, "|RTS"); + if (sigs & TIOCM_CTS) + strcat(str, "|CTS"); + if (sigs & TIOCM_DTR) + strcat(str, "|DTR"); + if (sigs & TIOCM_CD) + strcat(str, "|CD"); + } + + len += sprintf((page + len), "%s\n", &str[1]); + } + + return(len); +} + + +/* Finally, routines used to initialize the serial driver. */ + +static void show_serial_version(void) +{ + printk(mcfrs_drivername); +} + +static const struct tty_operations mcfrs_ops = { + .open = mcfrs_open, + .close = mcfrs_close, + .write = mcfrs_write, + .flush_chars = mcfrs_flush_chars, + .write_room = mcfrs_write_room, + .chars_in_buffer = mcfrs_chars_in_buffer, + .flush_buffer = mcfrs_flush_buffer, + .ioctl = mcfrs_ioctl, + .throttle = mcfrs_throttle, + .unthrottle = mcfrs_unthrottle, + .set_termios = mcfrs_set_termios, + .stop = mcfrs_stop, + .start = mcfrs_start, + .hangup = mcfrs_hangup, + .read_proc = mcfrs_readproc, + .wait_until_sent = mcfrs_wait_until_sent, + .tiocmget = mcfrs_tiocmget, + .tiocmset = mcfrs_tiocmset, +}; + +/* mcfrs_init inits the driver */ +static int __init +mcfrs_init(void) +{ + struct mcf_serial *info; + unsigned long flags; + int i; + + /* Setup base handler, and timer table. */ +#ifdef MCFPP_DCD0 + init_timer(&mcfrs_timer_struct); + mcfrs_timer_struct.function = mcfrs_timer; + mcfrs_timer_struct.data = 0; + mcfrs_timer_struct.expires = jiffies + HZ/25; + add_timer(&mcfrs_timer_struct); + mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1); +#endif + mcfrs_serial_driver = alloc_tty_driver(NR_PORTS); + if (!mcfrs_serial_driver) + return -ENOMEM; + + show_serial_version(); + + /* Initialize the tty_driver structure */ + mcfrs_serial_driver->owner = THIS_MODULE; + mcfrs_serial_driver->name = "ttyS"; + mcfrs_serial_driver->driver_name = "mcfserial"; + mcfrs_serial_driver->major = TTY_MAJOR; + mcfrs_serial_driver->minor_start = 64; + mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL; + mcfrs_serial_driver->init_termios = tty_std_termios; + + mcfrs_serial_driver->init_termios.c_cflag = + mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL; + mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW; + + tty_set_operations(mcfrs_serial_driver, &mcfrs_ops); + + if (tty_register_driver(mcfrs_serial_driver)) { + printk("MCFRS: Couldn't register serial driver\n"); + put_tty_driver(mcfrs_serial_driver); + return(-EBUSY); + } + + local_irq_save(flags); + + /* + * Configure all the attached serial ports. + */ + for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) { + info->magic = SERIAL_MAGIC; + info->line = i; + info->port.tty = NULL; + info->custom_divisor = 16; + info->close_delay = 50; + info->closing_wait = 3000; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + INIT_WORK(&info->tqueue, mcfrs_offintr); + INIT_WORK(&info->tqueue_hangup, do_serial_hangup); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + + info->imr = 0; + mcfrs_setsignals(info, 0, 0); + mcfrs_irqinit(info); + + printk("ttyS%d at 0x%04x (irq = %d)", info->line, + (unsigned int) info->addr, info->irq); + printk(" is a builtin ColdFire UART\n"); + } + + local_irq_restore(flags); + return 0; +} + +module_init(mcfrs_init); + +/****************************************************************************/ +/* Serial Console */ +/****************************************************************************/ + +/* + * Quick and dirty UART initialization, for console output. + */ + +void mcfrs_init_console(void) +{ + volatile unsigned char *uartp; + unsigned int clk; + + /* + * Reset UART, get it into known state... + */ + uartp = (volatile unsigned char *) (MCF_MBAR + + (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); + + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ + + /* + * Set port for defined baud , 8 data bits, 1 stop bit, no parity. + */ + uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8; + uartp[MCFUART_UMR] = MCFUART_MR2_STOP1; + +#ifdef CONFIG_M5272 +{ + /* + * For the MCF5272, also compute the baudrate fraction. + */ + int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud); + fraction *= 16; + fraction /= (32 * mcfrs_console_baud); + uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ + clk = (MCF_BUSCLK / mcfrs_console_baud) / 32; +} +#else + clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */ +#endif + + uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8; /* set msb baud */ + uartp[MCFUART_UBG2] = (clk & 0xff); /* set lsb baud */ + uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; + uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; + + mcfrs_console_inited++; + return; +} + + +/* + * Setup for console. Argument comes from the boot command line. + */ + +int mcfrs_console_setup(struct console *cp, char *arg) +{ + int i, n = CONSOLE_BAUD_RATE; + + if (!cp) + return(-1); + + if (!strncmp(cp->name, "ttyS", 4)) + mcfrs_console_port = cp->index; + else if (!strncmp(cp->name, "cua", 3)) + mcfrs_console_port = cp->index; + else + return(-1); + + if (arg) + n = simple_strtoul(arg,NULL,0); + for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++) + if (mcfrs_baud_table[i] == n) + break; + if (i < MCFRS_BAUD_TABLE_SIZE) { + mcfrs_console_baud = n; + mcfrs_console_cbaud = 0; + if (i > 15) { + mcfrs_console_cbaud |= CBAUDEX; + i -= 15; + } + mcfrs_console_cbaud |= i; + } + mcfrs_init_console(); /* make sure baud rate changes */ + return(0); +} + + +static struct tty_driver *mcfrs_console_device(struct console *c, int *index) +{ + *index = c->index; + return mcfrs_serial_driver; +} + + +/* + * Output a single character, using UART polled mode. + * This is used for console output. + */ + +int mcfrs_put_char(char ch) +{ + volatile unsigned char *uartp; + unsigned long flags; + int i; + + uartp = (volatile unsigned char *) (MCF_MBAR + + (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); + + local_irq_save(flags); + for (i = 0; (i < 0x10000); i++) { + if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) + break; + } + if (i < 0x10000) { + uartp[MCFUART_UTB] = ch; + for (i = 0; (i < 0x10000); i++) + if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) + break; + } + if (i >= 0x10000) + mcfrs_init_console(); /* try and get it back */ + local_irq_restore(flags); + + return 1; +} + + +/* + * rs_console_write is registered for printk output. + */ + +void mcfrs_console_write(struct console *cp, const char *p, unsigned len) +{ + if (!mcfrs_console_inited) + mcfrs_init_console(); + while (len-- > 0) { + if (*p == '\n') + mcfrs_put_char('\r'); + mcfrs_put_char(*p++); + } +} + +/* + * declare our consoles + */ + +struct console mcfrs_console = { + .name = "ttyS", + .write = mcfrs_console_write, + .device = mcfrs_console_device, + .setup = mcfrs_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +static int __init mcfrs_console_init(void) +{ + register_console(&mcfrs_console); + return 0; +} + +console_initcall(mcfrs_console_init); + +/****************************************************************************/ diff --git a/trunk/drivers/serial/mcfserial.h b/trunk/drivers/serial/mcfserial.h new file mode 100644 index 000000000000..56420e2cb110 --- /dev/null +++ b/trunk/drivers/serial/mcfserial.h @@ -0,0 +1,74 @@ +/* + * mcfserial.c -- serial driver for ColdFire internal UARTS. + * + * Copyright (c) 1999 Greg Ungerer + * Copyright (c) 2000-2001 Lineo, Inc. + * Copyright (c) 2002 SnapGear Inc., + * + * Based on code from 68332serial.c which was: + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 TSHG + * Copyright (c) 1999 Rt-Control Inc. + */ +#ifndef _MCF_SERIAL_H +#define _MCF_SERIAL_H + +#include + +#ifdef __KERNEL__ + +/* + * Define a local serial stats structure. + */ + +struct mcf_stats { + unsigned int rx; + unsigned int tx; + unsigned int rxbreak; + unsigned int rxframing; + unsigned int rxparity; + unsigned int rxoverrun; +}; + + +/* + * This is our internal structure for each serial port's state. + * Each serial port has one of these structures associated with it. + */ + +struct mcf_serial { + int magic; + volatile unsigned char *addr; /* UART memory address */ + int irq; + int flags; /* defined in tty.h */ + int type; /* UART type */ + struct tty_struct *tty; + unsigned char imr; /* Software imr register */ + unsigned int baud; + int sigs; + int custom_divisor; + int x_char; /* xon/xoff character */ + int baud_base; + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + unsigned long event; + int line; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct mcf_stats stats; + struct work_struct tqueue; + struct work_struct tqueue_hangup; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + +}; + +#endif /* __KERNEL__ */ + +#endif /* _MCF_SERIAL_H */ diff --git a/trunk/drivers/serial/serial_core.c b/trunk/drivers/serial/serial_core.c index 6bdf3362e3b1..f977c98cfa95 100644 --- a/trunk/drivers/serial/serial_core.c +++ b/trunk/drivers/serial/serial_core.c @@ -2051,8 +2051,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) "transmitter\n", port->dev ? port->dev->bus_id : "", port->dev ? ": " : "", - drv->dev_name, - drv->tty_driver->name_base + port->line); + drv->dev_name, port->line); ops->shutdown(port); } @@ -2155,11 +2154,12 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) switch (port->iotype) { case UPIO_PORT: - snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); + snprintf(address, sizeof(address), + "I/O 0x%x", port->iobase); break; case UPIO_HUB6: snprintf(address, sizeof(address), - "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); + "I/O 0x%x offset 0x%x", port->iobase, port->hub6); break; case UPIO_MEM: case UPIO_MEM32: @@ -2177,9 +2177,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", port->dev ? port->dev->bus_id : "", port->dev ? ": " : "", - drv->dev_name, - drv->tty_driver->name_base + port->line, - address, port->irq, uart_type(port)); + drv->dev_name, port->line, address, port->irq, uart_type(port)); } static void diff --git a/trunk/drivers/usb/serial/aircable.c b/trunk/drivers/usb/serial/aircable.c index 99fb7dc59c45..79ea98c66fa8 100644 --- a/trunk/drivers/usb/serial/aircable.c +++ b/trunk/drivers/usb/serial/aircable.c @@ -272,7 +272,7 @@ static void aircable_read(struct work_struct *work) * 64 bytes, to ensure I do not get throttled. * Ask USB mailing list for better aproach. */ - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) { schedule_work(&priv->rx_work); @@ -283,13 +283,12 @@ static void aircable_read(struct work_struct *work) count = min(64, serial_buf_data_avail(priv->rx_buf)); if (count <= 0) - goto out; /* We have finished sending everything. */ + return; /* We have finished sending everything. */ tty_prepare_flip_string(tty, &data, count); if (!data) { - dev_err(&port->dev, "%s- kzalloc(%d) failed.", - __func__, count); - goto out; + err("%s- kzalloc(%d) failed.", __func__, count); + return; } serial_buf_get(priv->rx_buf, data, count); @@ -298,8 +297,7 @@ static void aircable_read(struct work_struct *work) if (serial_buf_data_avail(priv->rx_buf)) schedule_work(&priv->rx_work); -out: - tty_kref_put(tty); + return; } /* End of private methods */ @@ -497,7 +495,7 @@ static void aircable_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, urb->transfer_buffer); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { if (urb->actual_length <= 2) { /* This is an incomplete package */ @@ -529,7 +527,6 @@ static void aircable_read_bulk_callback(struct urb *urb) } aircable_read(&priv->rx_work); } - tty_kref_put(tty); /* Schedule the next read _if_ we are still open */ if (port->port.count) { diff --git a/trunk/drivers/usb/serial/belkin_sa.c b/trunk/drivers/usb/serial/belkin_sa.c index 1913bc7c5f0b..2ebe06c3405a 100644 --- a/trunk/drivers/usb/serial/belkin_sa.c +++ b/trunk/drivers/usb/serial/belkin_sa.c @@ -322,7 +322,7 @@ static void belkin_sa_read_int_callback(struct urb *urb) * to look in to this before committing any code. */ if (priv->last_lsr & BELKIN_SA_LSR_ERR) { - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; /* Overrun Error */ if (priv->last_lsr & BELKIN_SA_LSR_OE) { } @@ -335,7 +335,6 @@ static void belkin_sa_read_int_callback(struct urb *urb) /* Break Indicator */ if (priv->last_lsr & BELKIN_SA_LSR_BI) { } - tty_kref_put(tty); } #endif spin_unlock_irqrestore(&priv->lock, flags); diff --git a/trunk/drivers/usb/serial/console.c b/trunk/drivers/usb/serial/console.c index 5b20de130e08..e980766bb84b 100644 --- a/trunk/drivers/usb/serial/console.c +++ b/trunk/drivers/usb/serial/console.c @@ -117,7 +117,7 @@ static int usb_console_setup(struct console *co, char *options) } port = serial->port[0]; - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; info->port = port; @@ -143,7 +143,7 @@ static int usb_console_setup(struct console *co, char *options) } memset(&dummy, 0, sizeof(struct ktermios)); tty->termios = termios; - tty_port_tty_set(&port->port, tty); + port->port.tty = tty; } /* only call the device specific open if this @@ -163,7 +163,7 @@ static int usb_console_setup(struct console *co, char *options) tty_termios_encode_baud_rate(termios, baud, baud); serial->type->set_termios(tty, port, &dummy); - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; kfree(termios); kfree(tty); } @@ -176,7 +176,7 @@ static int usb_console_setup(struct console *co, char *options) return retval; free_termios: kfree(termios); - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; free_tty: kfree(tty); reset_open_count: diff --git a/trunk/drivers/usb/serial/cyberjack.c b/trunk/drivers/usb/serial/cyberjack.c index 94ef36c4764b..b4d72351cb96 100644 --- a/trunk/drivers/usb/serial/cyberjack.c +++ b/trunk/drivers/usb/serial/cyberjack.c @@ -384,7 +384,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb) return; } - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) { dbg("%s - ignoring since device not open\n", __func__); return; @@ -394,7 +394,6 @@ static void cyberjack_read_bulk_callback(struct urb *urb) tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } - tty_kref_put(tty); spin_lock(&priv->lock); diff --git a/trunk/drivers/usb/serial/cypress_m8.c b/trunk/drivers/usb/serial/cypress_m8.c index f3514a91f915..22837a3f2f89 100644 --- a/trunk/drivers/usb/serial/cypress_m8.c +++ b/trunk/drivers/usb/serial/cypress_m8.c @@ -1286,7 +1286,7 @@ static void cypress_read_int_callback(struct urb *urb) } spin_unlock_irqrestore(&priv->lock, flags); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) { dbg("%s - bad tty pointer - exiting", __func__); return; @@ -1362,7 +1362,7 @@ static void cypress_read_int_callback(struct urb *urb) data[i]); tty_insert_flip_char(tty, data[i], tty_flag); } - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port->port.tty); } spin_lock_irqsave(&priv->lock, flags); @@ -1371,7 +1371,6 @@ static void cypress_read_int_callback(struct urb *urb) spin_unlock_irqrestore(&priv->lock, flags); continue_read: - tty_kref_put(tty); /* Continue trying to always read... unless the port has closed. */ diff --git a/trunk/drivers/usb/serial/digi_acceleport.c b/trunk/drivers/usb/serial/digi_acceleport.c index 5756ac6d6c92..240aad1acaab 100644 --- a/trunk/drivers/usb/serial/digi_acceleport.c +++ b/trunk/drivers/usb/serial/digi_acceleport.c @@ -604,9 +604,7 @@ static void digi_wakeup_write_lock(struct work_struct *work) static void digi_wakeup_write(struct usb_serial_port *port) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - tty_wakeup(tty); - tty_kref_put(tty); + tty_wakeup(port->port.tty); } @@ -1670,7 +1668,7 @@ static int digi_read_inb_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct tty_struct *tty; + struct tty_struct *tty = port->port.tty; struct digi_port *priv = usb_get_serial_port_data(port); int opcode = ((unsigned char *)urb->transfer_buffer)[0]; int len = ((unsigned char *)urb->transfer_buffer)[1]; @@ -1694,7 +1692,6 @@ static int digi_read_inb_callback(struct urb *urb) return -1; } - tty = tty_port_tty_get(&port->port); spin_lock(&priv->dp_port_lock); /* check for throttle; if set, do not resubmit read urb */ @@ -1738,7 +1735,6 @@ static int digi_read_inb_callback(struct urb *urb) } } spin_unlock(&priv->dp_port_lock); - tty_kref_put(tty); if (opcode == DIGI_CMD_RECEIVE_DISABLE) dbg("%s: got RECEIVE_DISABLE", __func__); @@ -1764,7 +1760,6 @@ static int digi_read_oob_callback(struct urb *urb) struct usb_serial_port *port = urb->context; struct usb_serial *serial = port->serial; - struct tty_struct *tty; struct digi_port *priv = usb_get_serial_port_data(port); int opcode, line, status, val; int i; @@ -1792,11 +1787,10 @@ static int digi_read_oob_callback(struct urb *urb) if (priv == NULL) return -1; - tty = tty_port_tty_get(&port->port); rts = 0; if (port->port.count) - rts = tty->termios->c_cflag & CRTSCTS; - + rts = port->port.tty->termios->c_cflag & CRTSCTS; + if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) { spin_lock(&priv->dp_port_lock); /* convert from digi flags to termiox flags */ @@ -1804,14 +1798,14 @@ static int digi_read_oob_callback(struct urb *urb) priv->dp_modem_signals |= TIOCM_CTS; /* port must be open to use tty struct */ if (rts) { - tty->hw_stopped = 0; + port->port.tty->hw_stopped = 0; digi_wakeup_write(port); } } else { priv->dp_modem_signals &= ~TIOCM_CTS; /* port must be open to use tty struct */ if (rts) - tty->hw_stopped = 1; + port->port.tty->hw_stopped = 1; } if (val & DIGI_READ_INPUT_SIGNALS_DSR) priv->dp_modem_signals |= TIOCM_DSR; @@ -1836,7 +1830,6 @@ static int digi_read_oob_callback(struct urb *urb) } else if (opcode == DIGI_CMD_IFLUSH_FIFO) { wake_up_interruptible(&priv->dp_flush_wait); } - tty_kref_put(tty); } return 0; diff --git a/trunk/drivers/usb/serial/empeg.c b/trunk/drivers/usb/serial/empeg.c index 1072e847280f..a6ab5b58d9ca 100644 --- a/trunk/drivers/usb/serial/empeg.c +++ b/trunk/drivers/usb/serial/empeg.c @@ -33,8 +33,9 @@ * Moved MOD_DEC_USE_COUNT to end of empeg_close(). * * (12/03/2000) gb - * Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open(). - * This notifies the tty driver that the termios have changed. + * Added port->port.tty->ldisc.set_termios(port->port.tty, NULL) to + * empeg_open(). This notifies the tty driver that the termios have + * changed. * * (11/13/2000) gb * Moved tty->low_latency = 1 from empeg_read_bulk_callback() to @@ -353,7 +354,7 @@ static void empeg_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length); @@ -361,7 +362,6 @@ static void empeg_read_bulk_callback(struct urb *urb) tty_flip_buffer_push(tty); bytes_in += urb->actual_length; } - tty_kref_put(tty); /* Continue trying to always read */ usb_fill_bulk_urb( diff --git a/trunk/drivers/usb/serial/ftdi_sio.c b/trunk/drivers/usb/serial/ftdi_sio.c index c2ac129557aa..3dc93b542b30 100644 --- a/trunk/drivers/usb/serial/ftdi_sio.c +++ b/trunk/drivers/usb/serial/ftdi_sio.c @@ -860,7 +860,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, kfree(buf); if (rv < 0) { - dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", + err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", __func__, (set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged", @@ -1808,7 +1808,7 @@ static void ftdi_read_bulk_callback(struct urb *urb) if (port->port.count <= 0) return; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) { dbg("%s - bad tty pointer - exiting", __func__); return; @@ -1817,7 +1817,7 @@ static void ftdi_read_bulk_callback(struct urb *urb) priv = usb_get_serial_port_data(port); if (!priv) { dbg("%s - bad port private data pointer - exiting", __func__); - goto out; + return; } if (urb != port->read_urb) @@ -1827,7 +1827,7 @@ static void ftdi_read_bulk_callback(struct urb *urb) /* This will happen at close every time so it is a dbg not an err */ dbg("(this is ok on close) nonzero read bulk status received: %d", status); - goto out; + return; } /* count data bytes, but not status bytes */ @@ -1838,8 +1838,7 @@ static void ftdi_read_bulk_callback(struct urb *urb) spin_unlock_irqrestore(&priv->rx_lock, flags); ftdi_process_read(&priv->rx_work.work); -out: - tty_kref_put(tty); + } /* ftdi_read_bulk_callback */ @@ -1864,7 +1863,7 @@ static void ftdi_process_read(struct work_struct *work) if (port->port.count <= 0) return; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) { dbg("%s - bad tty pointer - exiting", __func__); return; @@ -1873,13 +1872,13 @@ static void ftdi_process_read(struct work_struct *work) priv = usb_get_serial_port_data(port); if (!priv) { dbg("%s - bad port private data pointer - exiting", __func__); - goto out; + return; } urb = port->read_urb; if (!urb) { dbg("%s - bad read_urb pointer - exiting", __func__); - goto out; + return; } data = urb->transfer_buffer; @@ -2021,7 +2020,7 @@ static void ftdi_process_read(struct work_struct *work) schedule_delayed_work(&priv->rx_work, 1); else dbg("%s - port is closed", __func__); - goto out; + return; } /* urb is completely processed */ @@ -2042,8 +2041,6 @@ static void ftdi_process_read(struct work_struct *work) err("%s - failed resubmitting read urb, error %d", __func__, result); } -out: - tty_kref_put(tty); } /* ftdi_process_read */ @@ -2259,7 +2256,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) 0, 0, buf, 1, WDR_TIMEOUT); if (ret < 0) { - dbg("%s Could not get modem status of device - err: %d", __func__, + err("%s Could not get modem status of device - err: %d", __func__, ret); return ret; } @@ -2278,7 +2275,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file) 0, priv->interface, buf, 2, WDR_TIMEOUT); if (ret < 0) { - dbg("%s Could not get modem status of device - err: %d", __func__, + err("%s Could not get modem status of device - err: %d", __func__, ret); return ret; } diff --git a/trunk/drivers/usb/serial/garmin_gps.c b/trunk/drivers/usb/serial/garmin_gps.c index 2ad0569bcf19..d95382088075 100644 --- a/trunk/drivers/usb/serial/garmin_gps.c +++ b/trunk/drivers/usb/serial/garmin_gps.c @@ -276,7 +276,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf) static void send_to_tty(struct usb_serial_port *port, char *data, unsigned int actual_length) { - struct tty_struct *tty = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->port.tty; if (tty && actual_length) { @@ -287,7 +287,6 @@ static void send_to_tty(struct usb_serial_port *port, tty_insert_flip_string(tty, data, actual_length); tty_flip_buffer_push(tty); } - tty_kref_put(tty); } diff --git a/trunk/drivers/usb/serial/generic.c b/trunk/drivers/usb/serial/generic.c index 814909f1ee63..fe84c88ec20c 100644 --- a/trunk/drivers/usb/serial/generic.c +++ b/trunk/drivers/usb/serial/generic.c @@ -330,7 +330,7 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) static void flush_and_resubmit_read_urb(struct usb_serial_port *port) { struct urb *urb = port->read_urb; - struct tty_struct *tty = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->port.tty; int room; /* Push data to tty */ @@ -341,7 +341,6 @@ static void flush_and_resubmit_read_urb(struct usb_serial_port *port) tty_flip_buffer_push(tty); } } - tty_kref_put(tty); resubmit_read_urb(port, GFP_ATOMIC); } diff --git a/trunk/drivers/usb/serial/io_edgeport.c b/trunk/drivers/usb/serial/io_edgeport.c index 611f97fd62f1..bfa508ddb0fe 100644 --- a/trunk/drivers/usb/serial/io_edgeport.c +++ b/trunk/drivers/usb/serial/io_edgeport.c @@ -600,7 +600,6 @@ static void edge_interrupt_callback(struct urb *urb) struct edgeport_serial *edge_serial = urb->context; struct edgeport_port *edge_port; struct usb_serial_port *port; - struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int length = urb->actual_length; int bytes_avail; @@ -676,12 +675,9 @@ static void edge_interrupt_callback(struct urb *urb) /* tell the tty driver that something has changed */ - tty = tty_port_tty_get( - &edge_port->port->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } + if (edge_port->port->port.tty) + tty_wakeup(edge_port->port->port.tty); + /* Since we have more credit, check if more data can be sent */ send_more_port_data(edge_serial, @@ -782,14 +778,13 @@ static void edge_bulk_out_data_callback(struct urb *urb) __func__, status); } - tty = tty_port_tty_get(&edge_port->port->port); + tty = edge_port->port->port.tty; if (tty && edge_port->open) { /* let the tty driver wakeup if it has a special write_wakeup function */ tty_wakeup(tty); } - tty_kref_put(tty); /* Release the Write URB */ edge_port->write_in_progress = false; @@ -831,12 +826,11 @@ static void edge_bulk_out_cmd_callback(struct urb *urb) } /* Get pointer to tty */ - tty = tty_port_tty_get(&edge_port->port->port); + tty = edge_port->port->port.tty; /* tell the tty driver that something has changed */ if (tty && edge_port->open) tty_wakeup(tty); - tty_kref_put(tty); /* we have completed the command */ edge_port->commandPending = false; @@ -1938,13 +1932,11 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); if (edge_port->open) { - tty = tty_port_tty_get( - &edge_port->port->port); + tty = edge_port->port->port.tty; if (tty) { dbg("%s - Sending %d bytes to TTY for port %d", __func__, rxLen, edge_serial->rxPort); edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen); - tty_kref_put(tty); } edge_port->icount.rx += rxLen; } @@ -1979,7 +1971,6 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, { struct usb_serial_port *port; struct edgeport_port *edge_port; - struct tty_struct *tty; __u8 code = edge_serial->rxStatusCode; /* switch the port pointer to the one being currently talked about */ @@ -2029,12 +2020,10 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, /* send the current line settings to the port so we are in sync with any further termios calls */ - tty = tty_port_tty_get(&edge_port->port->port); - if (tty) { - change_port_settings(tty, - edge_port, tty->termios); - tty_kref_put(tty); - } + /* FIXME: locking on tty */ + if (edge_port->port->port.tty) + change_port_settings(edge_port->port->port.tty, + edge_port, edge_port->port->port.tty->termios); /* we have completed the open */ edge_port->openPending = false; @@ -2174,14 +2163,10 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, } /* Place LSR data byte into Rx buffer */ - if (lsrData) { - struct tty_struct *tty = - tty_port_tty_get(&edge_port->port->port); - if (tty) { - edge_tty_recv(&edge_port->port->dev, tty, &data, 1); - tty_kref_put(tty); - } - } + if (lsrData && edge_port->port->port.tty) + edge_tty_recv(&edge_port->port->dev, + edge_port->port->port.tty, &data, 1); + /* update input line counters */ icount = &edge_port->icount; if (newLsr & LSR_BREAK) diff --git a/trunk/drivers/usb/serial/io_ti.c b/trunk/drivers/usb/serial/io_ti.c index 541dd8e6e7a2..cb4c54316cf5 100644 --- a/trunk/drivers/usb/serial/io_ti.c +++ b/trunk/drivers/usb/serial/io_ti.c @@ -572,7 +572,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, int flush) { int baud_rate; - struct tty_struct *tty = tty_port_tty_get(&port->port->port); + struct tty_struct *tty = port->port->port.tty; wait_queue_t wait; unsigned long flags; @@ -599,7 +599,6 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, if (flush) edge_buf_clear(port->ep_out_buf); spin_unlock_irqrestore(&port->ep_lock, flags); - tty_kref_put(tty); /* wait for data to drain from the device */ timeout += jiffies; @@ -1555,7 +1554,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) /* Save the new modem status */ edge_port->shadow_msr = msr & 0xf0; - tty = tty_port_tty_get(&edge_port->port->port); + tty = edge_port->port->port.tty; /* handle CTS flow control */ if (tty && C_CRTSCTS(tty)) { if (msr & EDGEPORT_MSR_CTS) { @@ -1565,7 +1564,6 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) tty->hw_stopped = 1; } } - tty_kref_put(tty); return; } @@ -1576,7 +1574,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, struct async_icount *icount; __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); - struct tty_struct *tty; dbg("%s - %02x", __func__, new_lsr); @@ -1590,13 +1587,8 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); /* Place LSR data byte into Rx buffer */ - if (lsr_data) { - tty = tty_port_tty_get(&edge_port->port->port); - if (tty) { - edge_tty_recv(&edge_port->port->dev, tty, &data, 1); - tty_kref_put(tty); - } - } + if (lsr_data && edge_port->port->port.tty) + edge_tty_recv(&edge_port->port->dev, edge_port->port->port.tty, &data, 1); /* update input line counters */ icount = &edge_port->icount; @@ -1757,7 +1749,7 @@ static void edge_bulk_in_callback(struct urb *urb) ++data; } - tty = tty_port_tty_get(&edge_port->port->port); + tty = edge_port->port->port.tty; if (tty && urb->actual_length) { usb_serial_debug_data(debug, &edge_port->port->dev, __func__, urb->actual_length, data); @@ -1769,7 +1761,6 @@ static void edge_bulk_in_callback(struct urb *urb) urb->actual_length); edge_port->icount.rx += urb->actual_length; } - tty_kref_put(tty); exit: /* continue read unless stopped */ @@ -1805,7 +1796,6 @@ static void edge_bulk_out_callback(struct urb *urb) struct usb_serial_port *port = urb->context; struct edgeport_port *edge_port = usb_get_serial_port_data(port); int status = urb->status; - struct tty_struct *tty; dbg("%s - port %d", __func__, port->number); @@ -1828,9 +1818,7 @@ static void edge_bulk_out_callback(struct urb *urb) } /* send any buffered data */ - tty = tty_port_tty_get(&port->port); - edge_send(tty); - tty_kref_put(tty); + edge_send(port->port.tty); } static int edge_open(struct tty_struct *tty, @@ -1888,7 +1876,7 @@ static int edge_open(struct tty_struct *tty, /* set up the port settings */ if (tty) - edge_set_termios(tty, port, tty->termios); + edge_set_termios(tty, port, port->port.tty->termios); /* open up the port */ diff --git a/trunk/drivers/usb/serial/ipaq.c b/trunk/drivers/usb/serial/ipaq.c index 2affa9c118b2..cd9a2e138c8b 100644 --- a/trunk/drivers/usb/serial/ipaq.c +++ b/trunk/drivers/usb/serial/ipaq.c @@ -764,14 +764,13 @@ static void ipaq_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); bytes_in += urb->actual_length; } - tty_kref_put(tty); /* Continue trying to always read */ usb_fill_bulk_urb(port->read_urb, port->serial->dev, diff --git a/trunk/drivers/usb/serial/ipw.c b/trunk/drivers/usb/serial/ipw.c index 480cac27d646..a842025b9b57 100644 --- a/trunk/drivers/usb/serial/ipw.c +++ b/trunk/drivers/usb/serial/ipw.c @@ -170,13 +170,12 @@ static void ipw_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } - tty_kref_put(tty); /* Continue trying to always read */ usb_fill_bulk_urb(port->read_urb, port->serial->dev, diff --git a/trunk/drivers/usb/serial/ir-usb.c b/trunk/drivers/usb/serial/ir-usb.c index 45d4043e04ab..e59155c6607d 100644 --- a/trunk/drivers/usb/serial/ir-usb.c +++ b/trunk/drivers/usb/serial/ir-usb.c @@ -465,12 +465,11 @@ static void ir_read_bulk_callback(struct urb *urb) ir_baud = *data & 0x0f; usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty_buffer_request_room(tty, urb->actual_length - 1)) { tty_insert_flip_string(tty, data+1, urb->actual_length - 1); tty_flip_buffer_push(tty); } - tty_kref_put(tty); /* * No break here. diff --git a/trunk/drivers/usb/serial/iuu_phoenix.c b/trunk/drivers/usb/serial/iuu_phoenix.c index 53710aa7eadd..ddff37fa6339 100644 --- a/trunk/drivers/usb/serial/iuu_phoenix.c +++ b/trunk/drivers/usb/serial/iuu_phoenix.c @@ -629,14 +629,13 @@ static void read_buf_callback(struct urb *urb) } dbg("%s - %i chars to write", __func__, urb->actual_length); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (data == NULL) dbg("%s - data is NULL !!!", __func__); if (tty && urb->actual_length && data) { tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } - tty_kref_put(tty); iuu_led_activity_on(urb); } diff --git a/trunk/drivers/usb/serial/keyspan.c b/trunk/drivers/usb/serial/keyspan.c index 15447af48691..704716f6f6d3 100644 --- a/trunk/drivers/usb/serial/keyspan.c +++ b/trunk/drivers/usb/serial/keyspan.c @@ -430,7 +430,7 @@ static void usa26_indat_callback(struct urb *urb) } port = urb->context; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { @@ -459,7 +459,6 @@ static void usa26_indat_callback(struct urb *urb) } tty_flip_buffer_push(tty); } - tty_kref_put(tty); /* Resubmit urb so we continue receiving */ urb->dev = port->serial->dev; @@ -514,7 +513,6 @@ static void usa26_instat_callback(struct urb *urb) struct usb_serial *serial; struct usb_serial_port *port; struct keyspan_port_private *p_priv; - struct tty_struct *tty; int old_dcd_state, err; int status = urb->status; @@ -555,11 +553,12 @@ static void usa26_instat_callback(struct urb *urb) p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0); - if (old_dcd_state != p_priv->dcd_state) { - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); + if (port->port.tty && !C_CLOCAL(port->port.tty) + && old_dcd_state != p_priv->dcd_state) { + if (old_dcd_state) + tty_hangup(port->port.tty); + /* else */ + /* wake_up_interruptible(&p_priv->open_wait); */ } /* Resubmit urb so we continue receiving */ @@ -605,12 +604,11 @@ static void usa28_indat_callback(struct urb *urb) p_priv = usb_get_serial_port_data(port); data = urb->transfer_buffer; - tty =tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { + tty = port->port.tty; + if (urb->actual_length) { tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } - tty_kref_put(tty); /* Resubmit urb so we continue receiving */ urb->dev = port->serial->dev; @@ -654,7 +652,6 @@ static void usa28_instat_callback(struct urb *urb) struct usb_serial *serial; struct usb_serial_port *port; struct keyspan_port_private *p_priv; - struct tty_struct *tty; int old_dcd_state; int status = urb->status; @@ -692,11 +689,12 @@ static void usa28_instat_callback(struct urb *urb) p_priv->dcd_state = ((msg->dcd) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0); - if( old_dcd_state != p_priv->dcd_state && old_dcd_state) { - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); + if (port->port.tty && !C_CLOCAL(port->port.tty) + && old_dcd_state != p_priv->dcd_state) { + if (old_dcd_state) + tty_hangup(port->port.tty); + /* else */ + /* wake_up_interruptible(&p_priv->open_wait); */ } /* Resubmit urb so we continue receiving */ @@ -787,11 +785,12 @@ static void usa49_instat_callback(struct urb *urb) p_priv->dcd_state = ((msg->dcd) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0); - if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); + if (port->port.tty && !C_CLOCAL(port->port.tty) + && old_dcd_state != p_priv->dcd_state) { + if (old_dcd_state) + tty_hangup(port->port.tty); + /* else */ + /* wake_up_interruptible(&p_priv->open_wait); */ } /* Resubmit urb so we continue receiving */ @@ -828,7 +827,7 @@ static void usa49_indat_callback(struct urb *urb) } port = urb->context; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { /* 0x80 bit is error flag */ if ((data[0] & 0x80) == 0) { @@ -851,7 +850,6 @@ static void usa49_indat_callback(struct urb *urb) } tty_flip_buffer_push(tty); } - tty_kref_put(tty); /* Resubmit urb so we continue receiving */ urb->dev = port->serial->dev; @@ -895,7 +893,7 @@ static void usa49wg_indat_callback(struct urb *urb) return; } port = serial->port[data[i++]]; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; len = data[i++]; /* 0x80 bit is error flag */ @@ -929,7 +927,6 @@ static void usa49wg_indat_callback(struct urb *urb) } if (port->port.count) tty_flip_buffer_push(tty); - tty_kref_put(tty); } } @@ -970,8 +967,8 @@ static void usa90_indat_callback(struct urb *urb) port = urb->context; p_priv = usb_get_serial_port_data(port); + tty = port->port.tty; if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); /* if current mode is DMA, looks like usa28 format otherwise looks like usa26 data format */ @@ -1007,7 +1004,6 @@ static void usa90_indat_callback(struct urb *urb) } } tty_flip_buffer_push(tty); - tty_kref_put(tty); } /* Resubmit urb so we continue receiving */ @@ -1029,7 +1025,6 @@ static void usa90_instat_callback(struct urb *urb) struct usb_serial *serial; struct usb_serial_port *port; struct keyspan_port_private *p_priv; - struct tty_struct *tty; int old_dcd_state, err; int status = urb->status; @@ -1058,11 +1053,12 @@ static void usa90_instat_callback(struct urb *urb) p_priv->dcd_state = ((msg->dcd) ? 1 : 0); p_priv->ri_state = ((msg->ri) ? 1 : 0); - if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); + if (port->port.tty && !C_CLOCAL(port->port.tty) + && old_dcd_state != p_priv->dcd_state) { + if (old_dcd_state) + tty_hangup(port->port.tty); + /* else */ + /* wake_up_interruptible(&p_priv->open_wait); */ } /* Resubmit urb so we continue receiving */ @@ -1134,11 +1130,12 @@ static void usa67_instat_callback(struct urb *urb) p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0); p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); - if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); + if (port->port.tty && !C_CLOCAL(port->port.tty) + && old_dcd_state != p_priv->dcd_state) { + if (old_dcd_state) + tty_hangup(port->port.tty); + /* else */ + /* wake_up_interruptible(&p_priv->open_wait); */ } /* Resubmit urb so we continue receiving */ @@ -1335,7 +1332,7 @@ static void keyspan_close(struct tty_struct *tty, stop_urb(p_priv->out_urbs[i]); } } - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; } /* download the firmware to a pre-renumeration device */ diff --git a/trunk/drivers/usb/serial/keyspan_pda.c b/trunk/drivers/usb/serial/keyspan_pda.c index 99e9a14c5bf6..040040a267d9 100644 --- a/trunk/drivers/usb/serial/keyspan_pda.c +++ b/trunk/drivers/usb/serial/keyspan_pda.c @@ -172,9 +172,8 @@ static void keyspan_pda_wakeup_write(struct work_struct *work) struct keyspan_pda_private *priv = container_of(work, struct keyspan_pda_private, wakeup_work); struct usb_serial_port *port = priv->port; - struct tty_struct *tty = tty_port_tty_get(&port->port); - tty_wakeup(tty); - tty_kref_put(tty); + + tty_wakeup(port->port.tty); } static void keyspan_pda_request_unthrottle(struct work_struct *work) @@ -206,7 +205,7 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work) static void keyspan_pda_rx_interrupt(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct tty_struct *tty = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->port.tty; unsigned char *data = urb->transfer_buffer; int retval; int status = urb->status; @@ -223,7 +222,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __func__, status); - goto out; + return; default: dbg("%s - nonzero urb status received: %d", __func__, status); @@ -262,11 +261,8 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) - dev_err(&port->dev, - "%s - usb_submit_urb failed with result %d", - __func__, retval); -out: - tty_kref_put(tty); + err("%s - usb_submit_urb failed with result %d", + __func__, retval); } diff --git a/trunk/drivers/usb/serial/kl5kusb105.c b/trunk/drivers/usb/serial/kl5kusb105.c index ff3a07f5102f..b84dddc71124 100644 --- a/trunk/drivers/usb/serial/kl5kusb105.c +++ b/trunk/drivers/usb/serial/kl5kusb105.c @@ -658,7 +658,7 @@ static void klsi_105_read_bulk_callback(struct urb *urb) } else { int bytes_sent = ((__u8 *) data)[0] + ((unsigned int) ((__u8 *) data)[1] << 8); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; /* we should immediately resubmit the URB, before attempting * to pass the data on to the tty layer. But that needs locking * against re-entry an then mixed-up data because of @@ -679,7 +679,6 @@ static void klsi_105_read_bulk_callback(struct urb *urb) tty_buffer_request_room(tty, bytes_sent); tty_insert_flip_string(tty, data + 2, bytes_sent); tty_flip_buffer_push(tty); - tty_kref_put(tty); /* again lockless, but debug info only */ priv->bytes_in += bytes_sent; diff --git a/trunk/drivers/usb/serial/kobil_sct.c b/trunk/drivers/usb/serial/kobil_sct.c index cfcf37c2b957..deba28ec77e8 100644 --- a/trunk/drivers/usb/serial/kobil_sct.c +++ b/trunk/drivers/usb/serial/kobil_sct.c @@ -383,7 +383,7 @@ static void kobil_read_int_callback(struct urb *urb) return; } - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (urb->actual_length) { /* BEGIN DEBUG */ @@ -405,7 +405,6 @@ static void kobil_read_int_callback(struct urb *urb) tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } - tty_kref_put(tty); /* someone sets the dev to 0 if the close method has been called */ port->interrupt_in_urb->dev = port->serial->dev; diff --git a/trunk/drivers/usb/serial/mct_u232.c b/trunk/drivers/usb/serial/mct_u232.c index 9b2cef81cde0..0ded8bd6ec85 100644 --- a/trunk/drivers/usb/serial/mct_u232.c +++ b/trunk/drivers/usb/serial/mct_u232.c @@ -563,11 +563,10 @@ static void mct_u232_read_int_callback(struct urb *urb) * Work-a-round: handle the 'usual' bulk-in pipe here */ if (urb->transfer_buffer_length > 2) { - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (urb->actual_length) { tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); - tty_kref_put(tty); } goto exit; } @@ -592,7 +591,7 @@ static void mct_u232_read_int_callback(struct urb *urb) * to look in to this before committing any code. */ if (priv->last_lsr & MCT_U232_LSR_ERR) { - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; /* Overrun Error */ if (priv->last_lsr & MCT_U232_LSR_OE) { } @@ -605,7 +604,6 @@ static void mct_u232_read_int_callback(struct urb *urb) /* Break Indicator */ if (priv->last_lsr & MCT_U232_LSR_BI) { } - tty_kref_put(tty); } #endif spin_unlock_irqrestore(&priv->lock, flags); diff --git a/trunk/drivers/usb/serial/mos7720.c b/trunk/drivers/usb/serial/mos7720.c index 7b538caec37f..7c4917d77c0a 100644 --- a/trunk/drivers/usb/serial/mos7720.c +++ b/trunk/drivers/usb/serial/mos7720.c @@ -216,13 +216,12 @@ static void mos7720_bulk_in_callback(struct urb *urb) data = urb->transfer_buffer; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } - tty_kref_put(tty); if (!port->read_urb) { dbg("URB KILLED !!!"); @@ -263,11 +262,10 @@ static void mos7720_bulk_out_data_callback(struct urb *urb) dbg("Entering ........."); - tty = tty_port_tty_get(&mos7720_port->port->port); + tty = mos7720_port->port->port.tty; if (tty && mos7720_port->open) tty_wakeup(tty); - tty_kref_put(tty); } /* @@ -1269,6 +1267,29 @@ static int get_lsr_info(struct tty_struct *tty, return 0; } +/* + * get_number_bytes_avail - get number of bytes available + * + * Purpose: Let user call ioctl to get the count of number of bytes available. + */ +static int get_number_bytes_avail(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + unsigned int result = 0; + struct tty_struct *tty = mos7720_port->port->port.tty; + + if (!tty) + return -ENOIOCTLCMD; + + result = tty->read_cnt; + + dbg("%s(%d) = %d", __func__, mos7720_port->port->number, result); + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + + return -ENOIOCTLCMD; +} + static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, unsigned int __user *value) { @@ -1388,6 +1409,13 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file, dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); switch (cmd) { + case TIOCINQ: + /* return number of bytes available */ + dbg("%s (%d) TIOCINQ", __func__, port->number); + return get_number_bytes_avail(mos7720_port, + (unsigned int __user *)arg); + break; + case TIOCSERGETLSR: dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); return get_lsr_info(tty, mos7720_port, diff --git a/trunk/drivers/usb/serial/mos7840.c b/trunk/drivers/usb/serial/mos7840.c index 60543d79ef56..09d82062b973 100644 --- a/trunk/drivers/usb/serial/mos7840.c +++ b/trunk/drivers/usb/serial/mos7840.c @@ -709,13 +709,12 @@ static void mos7840_bulk_in_callback(struct urb *urb) dbg("%s", "Entering ........... \n"); if (urb->actual_length) { - tty = tty_port_tty_get(&mos7840_port->port->port); + tty = mos7840_port->port->port.tty; if (tty) { tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); dbg(" %s \n", data); tty_flip_buffer_push(tty); - tty_kref_put(tty); } mos7840_port->icount.rx += urb->actual_length; smp_wmb(); @@ -774,10 +773,10 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) dbg("%s \n", "Entering ........."); - tty = tty_port_tty_get(&mos7840_port->port->port); + tty = mos7840_port->port->port.tty; + if (tty && mos7840_port->open) tty_wakeup(tty); - tty_kref_put(tty); } diff --git a/trunk/drivers/usb/serial/navman.c b/trunk/drivers/usb/serial/navman.c index bcdcbb822705..d6736531a0fa 100644 --- a/trunk/drivers/usb/serial/navman.c +++ b/trunk/drivers/usb/serial/navman.c @@ -64,13 +64,12 @@ static void navman_read_int_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } - tty_kref_put(tty); exit: result = usb_submit_urb(urb, GFP_ATOMIC); diff --git a/trunk/drivers/usb/serial/omninet.c b/trunk/drivers/usb/serial/omninet.c index c4d70b0f1e48..ae8e227f3db2 100644 --- a/trunk/drivers/usb/serial/omninet.c +++ b/trunk/drivers/usb/serial/omninet.c @@ -172,7 +172,7 @@ static int omninet_open(struct tty_struct *tty, dbg("%s - port %d", __func__, port->number); wport = serial->port[1]; - tty_port_tty_set(&wport->port, tty); + wport->port.tty = tty; /* FIXME */ /* Start reading from the device */ usb_fill_bulk_urb(port->read_urb, serial->dev, @@ -229,11 +229,9 @@ static void omninet_read_bulk_callback(struct urb *urb) } if (urb->actual_length && header->oh_len) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET, - header->oh_len); - tty_flip_buffer_push(tty); - tty_kref_put(tty); + tty_insert_flip_string(port->port.tty, + data + OMNINET_DATAOFFSET, header->oh_len); + tty_flip_buffer_push(port->port.tty); } /* Continue trying to always read */ diff --git a/trunk/drivers/usb/serial/option.c b/trunk/drivers/usb/serial/option.c index 6b1727e751e3..73f8277f88f2 100644 --- a/trunk/drivers/usb/serial/option.c +++ b/trunk/drivers/usb/serial/option.c @@ -571,14 +571,14 @@ static void option_indat_callback(struct urb *urb) dbg("%s: nonzero status: %d on endpoint %02x.", __func__, status, endpoint); } else { - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); - } else + } else { dbg("%s: empty read urb received", __func__); - tty_kref_put(tty); + } /* Resubmit urb so we continue receiving */ if (port->port.count && status != -ESHUTDOWN) { @@ -647,13 +647,9 @@ static void option_instat_callback(struct urb *urb) portdata->dsr_state = ((signals & 0x02) ? 1 : 0); portdata->ri_state = ((signals & 0x08) ? 1 : 0); - if (old_dcd_state && !portdata->dcd_state) { - struct tty_struct *tty = - tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } + if (port->port.tty && !C_CLOCAL(port->port.tty) && + old_dcd_state && !portdata->dcd_state) + tty_hangup(port->port.tty); } else { dbg("%s: type %x req %x", __func__, req_pkt->bRequestType, req_pkt->bRequest); @@ -797,7 +793,7 @@ static void option_close(struct tty_struct *tty, for (i = 0; i < N_OUT_URB; i++) usb_kill_urb(portdata->out_urbs[i]); } - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; /* FIXME */ } /* Helper functions used by option_setup_urbs */ diff --git a/trunk/drivers/usb/serial/oti6858.c b/trunk/drivers/usb/serial/oti6858.c index ba551f00f16f..81db5715ee25 100644 --- a/trunk/drivers/usb/serial/oti6858.c +++ b/trunk/drivers/usb/serial/oti6858.c @@ -224,6 +224,10 @@ struct oti6858_private { struct usb_serial_port *port; /* USB port with which associated */ }; +#undef dbg +/* #define dbg(format, arg...) printk(KERN_INFO "%s: " format "\n", __FILE__, ## arg) */ +#define dbg(format, arg...) printk(KERN_INFO "" format "\n", ## arg) + static void setup_line(struct work_struct *work) { struct oti6858_private *priv = container_of(work, @@ -998,12 +1002,11 @@ static void oti6858_read_bulk_callback(struct urb *urb) return; } - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty != NULL && urb->actual_length > 0) { tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); } - tty_kref_put(tty); /* schedule the interrupt urb if we are still open */ if (port->port.count != 0) { diff --git a/trunk/drivers/usb/serial/pl2303.c b/trunk/drivers/usb/serial/pl2303.c index 908437847165..1ede1441cb1b 100644 --- a/trunk/drivers/usb/serial/pl2303.c +++ b/trunk/drivers/usb/serial/pl2303.c @@ -154,6 +154,7 @@ struct pl2303_private { wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; + u8 termios_initialized; enum pl2303_type type; }; @@ -525,6 +526,16 @@ static void pl2303_set_termios(struct tty_struct *tty, dbg("%s - port %d", __func__, port->number); + spin_lock_irqsave(&priv->lock, flags); + if (!priv->termios_initialized) { + *(tty->termios) = tty_std_termios; + tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios->c_ispeed = 9600; + tty->termios->c_ospeed = 9600; + priv->termios_initialized = 1; + } + spin_unlock_irqrestore(&priv->lock, flags); + /* The PL2303 is reported to lose bytes if you change serial settings even to the same values as before. Thus we actually need to filter in this specific case */ @@ -1046,7 +1057,7 @@ static void pl2303_read_bulk_callback(struct urb *urb) tty_flag = TTY_FRAME; dbg("%s - tty_flag = %d", __func__, tty_flag); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length + 1); /* overrun is special, not associated with a char */ @@ -1056,7 +1067,7 @@ static void pl2303_read_bulk_callback(struct urb *urb) tty_insert_flip_char(tty, data[i], tty_flag); tty_flip_buffer_push(tty); } - tty_kref_put(tty); + /* Schedule the next read _if_ we are still open */ if (port->port.count) { urb->dev = port->serial->dev; diff --git a/trunk/drivers/usb/serial/safe_serial.c b/trunk/drivers/usb/serial/safe_serial.c index 72903ac9f5c0..def52d07a4ea 100644 --- a/trunk/drivers/usb/serial/safe_serial.c +++ b/trunk/drivers/usb/serial/safe_serial.c @@ -217,7 +217,6 @@ static void safe_read_bulk_callback(struct urb *urb) struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; unsigned char length = urb->actual_length; - struct tty_struct *tty; int result; int status = urb->status; @@ -243,7 +242,6 @@ static void safe_read_bulk_callback(struct urb *urb) printk("\n"); } #endif - tty = tty_port_tty_get(&port->port); if (safe) { __u16 fcs; fcs = fcs_compute10(data, length, CRC10_INITFCS); @@ -252,9 +250,9 @@ static void safe_read_bulk_callback(struct urb *urb) if (actual_length <= (length - 2)) { info("%s - actual: %d", __func__, actual_length); - tty_insert_flip_string(tty, + tty_insert_flip_string(port->port.tty, data, actual_length); - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port->port.tty); } else { err("%s - inconsistent lengths %d:%d", __func__, actual_length, length); @@ -263,10 +261,9 @@ static void safe_read_bulk_callback(struct urb *urb) err("%s - bad CRC %x", __func__, fcs); } } else { - tty_insert_flip_string(tty, data, length); - tty_flip_buffer_push(tty); + tty_insert_flip_string(port->port.tty, data, length); + tty_flip_buffer_push(port->port.tty); } - tty_kref_put(tty); /* Continue trying to always read */ usb_fill_bulk_urb(urb, port->serial->dev, diff --git a/trunk/drivers/usb/serial/sierra.c b/trunk/drivers/usb/serial/sierra.c index 8b9eaf383679..ea1a103c99be 100644 --- a/trunk/drivers/usb/serial/sierra.c +++ b/trunk/drivers/usb/serial/sierra.c @@ -440,14 +440,14 @@ static void sierra_indat_callback(struct urb *urb) dbg("%s: nonzero status: %d on endpoint %02x.", __func__, status, endpoint); } else { + tty = port->port.tty; if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); tty_buffer_request_room(tty, urb->actual_length); tty_insert_flip_string(tty, data, urb->actual_length); tty_flip_buffer_push(tty); - tty_kref_put(tty); - } else + } else { dbg("%s: empty read urb received", __func__); + } /* Resubmit urb so we continue receiving */ if (port->port.count && status != -ESHUTDOWN) { @@ -485,7 +485,6 @@ static void sierra_instat_callback(struct urb *urb) unsigned char signals = *((unsigned char *) urb->transfer_buffer + sizeof(struct usb_ctrlrequest)); - struct tty_struct *tty; dbg("%s: signal x%x", __func__, signals); @@ -495,11 +494,9 @@ static void sierra_instat_callback(struct urb *urb) portdata->dsr_state = ((signals & 0x02) ? 1 : 0); portdata->ri_state = ((signals & 0x08) ? 1 : 0); - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty) && + if (port->port.tty && !C_CLOCAL(port->port.tty) && old_dcd_state && !portdata->dcd_state) - tty_hangup(tty); - tty_kref_put(tty); + tty_hangup(port->port.tty); } else { dbg("%s: type %x req %x", __func__, req_pkt->bRequestType, req_pkt->bRequest); @@ -619,7 +616,8 @@ static void sierra_close(struct tty_struct *tty, } usb_kill_urb(port->interrupt_in_urb); - tty_port_tty_set(&port->port, NULL); + + port->port.tty = NULL; /* FIXME */ } static int sierra_startup(struct usb_serial *serial) diff --git a/trunk/drivers/usb/serial/spcp8x5.c b/trunk/drivers/usb/serial/spcp8x5.c index 1533d6e12238..283cf6b36b2c 100644 --- a/trunk/drivers/usb/serial/spcp8x5.c +++ b/trunk/drivers/usb/serial/spcp8x5.c @@ -755,7 +755,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb) tty_flag = TTY_FRAME; dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (tty && urb->actual_length) { tty_buffer_request_room(tty, urb->actual_length + 1); /* overrun is special, not associated with a char */ @@ -765,7 +765,6 @@ static void spcp8x5_read_bulk_callback(struct urb *urb) tty_insert_flip_char(tty, data[i], tty_flag); tty_flip_buffer_push(tty); } - tty_kref_put(tty); /* Schedule the next read _if_ we are still open */ if (port->port.count) { diff --git a/trunk/drivers/usb/serial/ti_usb_3410_5052.c b/trunk/drivers/usb/serial/ti_usb_3410_5052.c index c90237d48b0e..9a3e495c769c 100644 --- a/trunk/drivers/usb/serial/ti_usb_3410_5052.c +++ b/trunk/drivers/usb/serial/ti_usb_3410_5052.c @@ -179,7 +179,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr); static int ti_get_lsr(struct ti_port *tport); static int ti_get_serial_info(struct ti_port *tport, struct serial_struct __user *ret_arg); -static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, +static int ti_set_serial_info(struct ti_port *tport, struct serial_struct __user *new_arg); static void ti_handle_new_msr(struct ti_port *tport, __u8 msr); @@ -857,8 +857,8 @@ static int ti_ioctl(struct tty_struct *tty, struct file *file, (struct serial_struct __user *)arg); case TIOCSSERIAL: dbg("%s - (%d) TIOCSSERIAL", __func__, port->number); - return ti_set_serial_info(tty, tport, - (struct serial_struct __user *)arg); + return ti_set_serial_info(tport, + (struct serial_struct __user *)arg); case TIOCMIWAIT: dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); cprev = tport->tp_icount; @@ -1211,7 +1211,6 @@ static void ti_bulk_in_callback(struct urb *urb) struct device *dev = &urb->dev->dev; int status = urb->status; int retval = 0; - struct tty_struct *tty; dbg("%s", __func__); @@ -1240,22 +1239,20 @@ static void ti_bulk_in_callback(struct urb *urb) return; } - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { + if (port->port.tty && urb->actual_length) { usb_serial_debug_data(debug, dev, __func__, urb->actual_length, urb->transfer_buffer); if (!tport->tp_is_open) dbg("%s - port closed, dropping data", __func__); else - ti_recv(&urb->dev->dev, tty, + ti_recv(&urb->dev->dev, port->port.tty, urb->transfer_buffer, urb->actual_length); spin_lock(&tport->tp_lock); tport->tp_icount.rx += urb->actual_length; spin_unlock(&tport->tp_lock); - tty_kref_put(tty); } exit: @@ -1333,7 +1330,7 @@ static void ti_send(struct ti_port *tport) { int count, result; struct usb_serial_port *port = tport->tp_port; - struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */ + struct tty_struct *tty = port->port.tty; /* FIXME */ unsigned long flags; @@ -1341,15 +1338,19 @@ static void ti_send(struct ti_port *tport) spin_lock_irqsave(&tport->tp_lock, flags); - if (tport->tp_write_urb_in_use) - goto unlock; + if (tport->tp_write_urb_in_use) { + spin_unlock_irqrestore(&tport->tp_lock, flags); + return; + } count = ti_buf_get(tport->tp_write_buf, port->write_urb->transfer_buffer, port->bulk_out_size); - if (count == 0) - goto unlock; + if (count == 0) { + spin_unlock_irqrestore(&tport->tp_lock, flags); + return; + } tport->tp_write_urb_in_use = 1; @@ -1379,13 +1380,7 @@ static void ti_send(struct ti_port *tport) /* more room in the buffer for new writes, wakeup */ if (tty) tty_wakeup(tty); - tty_kref_put(tty); wake_up_interruptible(&tport->tp_write_wait); - return; -unlock: - spin_unlock_irqrestore(&tport->tp_lock, flags); - tty_kref_put(tty); - return; } @@ -1469,16 +1464,20 @@ static int ti_get_serial_info(struct ti_port *tport, } -static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, +static int ti_set_serial_info(struct ti_port *tport, struct serial_struct __user *new_arg) { + struct usb_serial_port *port = tport->tp_port; struct serial_struct new_serial; if (copy_from_user(&new_serial, new_arg, sizeof(new_serial))) return -EFAULT; tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS; - tty->low_latency = (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0; + /* FIXME */ + if (port->port.tty) + port->port.tty->low_latency = + (tport->tp_flags & ASYNC_LOW_LATENCY) ? 1 : 0; tport->tp_closing_wait = new_serial.closing_wait; return 0; @@ -1511,7 +1510,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) tport->tp_msr = msr & TI_MSR_MASK; /* handle CTS flow control */ - tty = tty_port_tty_get(&tport->tp_port->port); + tty = tport->tp_port->port.tty; if (tty && C_CRTSCTS(tty)) { if (msr & TI_MSR_CTS) { tty->hw_stopped = 0; @@ -1520,7 +1519,6 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) tty->hw_stopped = 1; } } - tty_kref_put(tty); } diff --git a/trunk/drivers/usb/serial/usb-serial.c b/trunk/drivers/usb/serial/usb-serial.c index e7d4246027b2..4f7f9e3ae0a4 100644 --- a/trunk/drivers/usb/serial/usb-serial.c +++ b/trunk/drivers/usb/serial/usb-serial.c @@ -214,7 +214,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp) /* set up our port structure making the tty driver * remember our port object, and us it */ tty->driver_data = port; - tty_port_tty_set(&port->port, tty); + port->port.tty = tty; if (port->port.count == 1) { @@ -246,7 +246,7 @@ static int serial_open (struct tty_struct *tty, struct file *filp) bailout_mutex_unlock: port->port.count = 0; tty->driver_data = NULL; - tty_port_tty_set(&port->port, NULL); + port->port.tty = NULL; mutex_unlock(&port->mutex); bailout_kref_put: usb_serial_put(serial); @@ -276,11 +276,10 @@ static void serial_close(struct tty_struct *tty, struct file *filp) port->serial->type->close(tty, port, filp); if (port->port.count == (port->console? 1 : 0)) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) { - if (tty->driver_data) - tty->driver_data = NULL; - tty_port_tty_set(&port->port, NULL); + if (port->port.tty) { + if (port->port.tty->driver_data) + port->port.tty->driver_data = NULL; + port->port.tty = NULL; } } @@ -509,12 +508,11 @@ static void usb_serial_port_work(struct work_struct *work) if (!port) return; - tty = tty_port_tty_get(&port->port); + tty = port->port.tty; if (!tty) return; tty_wakeup(tty); - tty_kref_put(tty); } static void port_release(struct device *dev) @@ -821,7 +819,6 @@ int usb_serial_probe(struct usb_interface *interface, port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); if (!port) goto probe_error; - tty_port_init(&port->port); port->serial = serial; spin_lock_init(&port->lock); mutex_init(&port->mutex); @@ -1043,11 +1040,8 @@ void usb_serial_disconnect(struct usb_interface *interface) for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (port) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } + if (port->port.tty) + tty_hangup(port->port.tty); kill_traffic(port); } } diff --git a/trunk/drivers/usb/serial/visor.c b/trunk/drivers/usb/serial/visor.c index a6d1c75a1c89..cf8924f9a2cc 100644 --- a/trunk/drivers/usb/serial/visor.c +++ b/trunk/drivers/usb/serial/visor.c @@ -499,7 +499,7 @@ static void visor_read_bulk_callback(struct urb *urb) int status = urb->status; struct tty_struct *tty; int result; - int available_room = 0; + int available_room; dbg("%s - port %d", __func__, port->number); @@ -512,17 +512,13 @@ static void visor_read_bulk_callback(struct urb *urb) usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); - if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); - if (tty) { - available_room = tty_buffer_request_room(tty, + tty = port->port.tty; + if (tty && urb->actual_length) { + available_room = tty_buffer_request_room(tty, urb->actual_length); - if (available_room) { - tty_insert_flip_string(tty, data, - available_room); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); + if (available_room) { + tty_insert_flip_string(tty, data, available_room); + tty_flip_buffer_push(tty); } spin_lock(&priv->lock); priv->bytes_in += available_room; diff --git a/trunk/drivers/usb/serial/whiteheat.c b/trunk/drivers/usb/serial/whiteheat.c index 11c8b97a5177..3a9d14384a43 100644 --- a/trunk/drivers/usb/serial/whiteheat.c +++ b/trunk/drivers/usb/serial/whiteheat.c @@ -1481,7 +1481,7 @@ static void rx_data_softint(struct work_struct *work) struct whiteheat_private *info = container_of(work, struct whiteheat_private, rx_work); struct usb_serial_port *port = info->port; - struct tty_struct *tty = tty_port_tty_get(&port->port); + struct tty_struct *tty = port->port.tty; struct whiteheat_urb_wrap *wrap; struct urb *urb; unsigned long flags; @@ -1493,7 +1493,7 @@ static void rx_data_softint(struct work_struct *work) spin_lock_irqsave(&info->lock, flags); if (info->flags & THROTTLED) { spin_unlock_irqrestore(&info->lock, flags); - goto out; + return; } list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { @@ -1513,7 +1513,7 @@ static void rx_data_softint(struct work_struct *work) spin_unlock_irqrestore(&info->lock, flags); tty_flip_buffer_push(tty); schedule_work(&info->rx_work); - goto out; + return; } tty_insert_flip_string(tty, urb->transfer_buffer, len); sent += len; @@ -1536,8 +1536,6 @@ static void rx_data_softint(struct work_struct *work) if (sent) tty_flip_buffer_push(tty); -out: - tty_kref_put(tty); } diff --git a/trunk/fs/devpts/inode.c b/trunk/fs/devpts/inode.c index a70d5d0890c7..488eb424f662 100644 --- a/trunk/fs/devpts/inode.c +++ b/trunk/fs/devpts/inode.c @@ -27,7 +27,6 @@ #define DEVPTS_SUPER_MAGIC 0x1cd1 #define DEVPTS_DEFAULT_MODE 0600 -#define PTMX_MINOR 2 extern int pty_limit; /* Config limit on Unix98 ptys */ static DEFINE_IDA(allocated_ptys); @@ -170,7 +169,15 @@ static struct file_system_type devpts_fs_type = { * to the System V naming convention */ -int devpts_new_index(struct inode *ptmx_inode) +static struct dentry *get_node(int num) +{ + char s[12]; + struct dentry *root = devpts_root; + mutex_lock(&root->d_inode->i_mutex); + return lookup_one_len(s, root, sprintf(s, "%d", num)); +} + +int devpts_new_index(void) { int index; int ida_ret; @@ -198,21 +205,20 @@ int devpts_new_index(struct inode *ptmx_inode) return index; } -void devpts_kill_index(struct inode *ptmx_inode, int idx) +void devpts_kill_index(int idx) { mutex_lock(&allocated_ptys_lock); ida_remove(&allocated_ptys, idx); mutex_unlock(&allocated_ptys_lock); } -int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) +int devpts_pty_new(struct tty_struct *tty) { int number = tty->index; /* tty layer puts index from devpts_new_index() in here */ struct tty_driver *driver = tty->driver; dev_t device = MKDEV(driver->major, driver->minor_start+number); struct dentry *dentry; struct inode *inode = new_inode(devpts_mnt->mnt_sb); - char s[12]; /* We're supposed to be given the slave end of a pty */ BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY); @@ -227,15 +233,10 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; init_special_inode(inode, S_IFCHR|config.mode, device); inode->i_private = tty; - tty->driver_data = inode; - sprintf(s, "%d", number); - - mutex_lock(&devpts_root->d_inode->i_mutex); - - dentry = d_alloc_name(devpts_root, s); - if (!IS_ERR(dentry)) { - d_add(dentry, inode); + dentry = get_node(number); + if (!IS_ERR(dentry) && !dentry->d_inode) { + d_instantiate(dentry, inode); fsnotify_create(devpts_root->d_inode, dentry); } @@ -244,31 +245,36 @@ int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) return 0; } -struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number) +struct tty_struct *devpts_get_tty(int number) { - BUG_ON(pts_inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); + struct dentry *dentry = get_node(number); + struct tty_struct *tty; - if (pts_inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) - return (struct tty_struct *)pts_inode->i_private; - return NULL; -} + tty = NULL; + if (!IS_ERR(dentry)) { + if (dentry->d_inode) + tty = dentry->d_inode->i_private; + dput(dentry); + } -void devpts_pty_kill(struct tty_struct *tty) -{ - struct inode *inode = tty->driver_data; - struct dentry *dentry; + mutex_unlock(&devpts_root->d_inode->i_mutex); - BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); + return tty; +} - mutex_lock(&devpts_root->d_inode->i_mutex); +void devpts_pty_kill(int number) +{ + struct dentry *dentry = get_node(number); - dentry = d_find_alias(inode); - if (dentry && !IS_ERR(dentry)) { - inode->i_nlink--; - d_delete(dentry); + if (!IS_ERR(dentry)) { + struct inode *inode = dentry->d_inode; + if (inode) { + inode->i_nlink--; + d_delete(dentry); + dput(dentry); + } dput(dentry); } - mutex_unlock(&devpts_root->d_inode->i_mutex); } diff --git a/trunk/fs/dquot.c b/trunk/fs/dquot.c index ad7e59003e04..8ec4d6cc7633 100644 --- a/trunk/fs/dquot.c +++ b/trunk/fs/dquot.c @@ -895,9 +895,10 @@ static void print_warning(struct dquot *dquot, const int warntype) warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot)) return; + mutex_lock(&tty_mutex); tty = get_current_tty(); if (!tty) - return; + goto out_lock; tty_write_message(tty, dquot->dq_sb->s_id); if (warntype == QUOTA_NL_ISOFTWARN || warntype == QUOTA_NL_BSOFTWARN) tty_write_message(tty, ": warning, "); @@ -925,7 +926,8 @@ static void print_warning(struct dquot *dquot, const int warntype) break; } tty_write_message(tty, msg); - tty_kref_put(tty); +out_lock: + mutex_unlock(&tty_mutex); } #endif diff --git a/trunk/fs/open.c b/trunk/fs/open.c index 5596049863bf..07da9359481c 100644 --- a/trunk/fs/open.c +++ b/trunk/fs/open.c @@ -1141,7 +1141,8 @@ EXPORT_SYMBOL(sys_close); asmlinkage long sys_vhangup(void) { if (capable(CAP_SYS_TTY_CONFIG)) { - tty_vhangup_self(); + /* XXX: this needs locking */ + tty_vhangup(current->signal->tty); return 0; } return -EPERM; diff --git a/trunk/include/asm-x86/fixmap_64.h b/trunk/include/asm-x86/fixmap_64.h index dafb24bc0424..33df64fd0e18 100644 --- a/trunk/include/asm-x86/fixmap_64.h +++ b/trunk/include/asm-x86/fixmap_64.h @@ -49,6 +49,7 @@ enum fixed_addresses { #ifdef CONFIG_PARAVIRT FIX_PARAVIRT_BOOTMAP, #endif + __end_of_permanent_fixed_addresses, #ifdef CONFIG_ACPI FIX_ACPI_BEGIN, FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, @@ -56,18 +57,17 @@ enum fixed_addresses { #ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT FIX_OHCI1394_BASE, #endif - __end_of_permanent_fixed_addresses, /* * 256 temporary boot-time mappings, used by early_ioremap(), * before ioremap() is functional. * - * We round it up to the next 512 pages boundary so that we + * We round it up to the next 256 pages boundary so that we * can have a single pgd entry and a single pte table: */ #define NR_FIX_BTMAPS 64 #define FIX_BTMAPS_NESTING 4 - FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 512 - - (__end_of_permanent_fixed_addresses & 511), + FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 - + (__end_of_permanent_fixed_addresses & 255), FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_NESTING - 1, __end_of_fixed_addresses }; diff --git a/trunk/include/asm-x86/ioctls.h b/trunk/include/asm-x86/ioctls.h index 06752a649044..336603512399 100644 --- a/trunk/include/asm-x86/ioctls.h +++ b/trunk/include/asm-x86/ioctls.h @@ -51,15 +51,9 @@ #define TCSETS2 _IOW('T', 0x2B, struct termios2) #define TCSETSW2 _IOW('T', 0x2C, struct termios2) #define TCSETSF2 _IOW('T', 0x2D, struct termios2) -#define TIOCGRS485 0x542E -#define TIOCSRS485 0x542F #define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ -#define TCGETX 0x5432 /* SYS5 TCGETX compatibility */ -#define TCSETX 0x5433 -#define TCSETXF 0x5434 -#define TCSETXW 0x5435 #define FIONCLEX 0x5450 #define FIOCLEX 0x5451 diff --git a/trunk/include/linux/devpts_fs.h b/trunk/include/linux/devpts_fs.h index 5ce0e5fd712e..154769cad3f3 100644 --- a/trunk/include/linux/devpts_fs.h +++ b/trunk/include/linux/devpts_fs.h @@ -17,31 +17,20 @@ #ifdef CONFIG_UNIX98_PTYS -int devpts_new_index(struct inode *ptmx_inode); -void devpts_kill_index(struct inode *ptmx_inode, int idx); -/* mknod in devpts */ -int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty); -/* get tty structure */ -struct tty_struct *devpts_get_tty(struct inode *pts_inode, int number); -/* unlink */ -void devpts_pty_kill(struct tty_struct *tty); +int devpts_new_index(void); +void devpts_kill_index(int idx); +int devpts_pty_new(struct tty_struct *tty); /* mknod in devpts */ +struct tty_struct *devpts_get_tty(int number); /* get tty structure */ +void devpts_pty_kill(int number); /* unlink */ #else /* Dummy stubs in the no-pty case */ -static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; } -static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { } -static inline int devpts_pty_new(struct inode *ptmx_inode, - struct tty_struct *tty) -{ - return -EINVAL; -} -static inline struct tty_struct *devpts_get_tty(struct inode *pts_inode, - int number) -{ - return NULL; -} -static inline void devpts_pty_kill(struct tty_struct *tty) { } +static inline int devpts_new_index(void) { return -EINVAL; } +static inline void devpts_kill_index(int idx) { } +static inline int devpts_pty_new(struct tty_struct *tty) { return -EINVAL; } +static inline struct tty_struct *devpts_get_tty(int number) { return NULL; } +static inline void devpts_pty_kill(int number) { } #endif diff --git a/trunk/include/linux/serial.h b/trunk/include/linux/serial.h index 1ea8d9265bf6..deb714314fb1 100644 --- a/trunk/include/linux/serial.h +++ b/trunk/include/linux/serial.h @@ -173,22 +173,6 @@ struct serial_icounter_struct { int reserved[9]; }; -/* - * Serial interface for controlling RS485 settings on chips with suitable - * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your - * platform. The set function returns the new state, with any unsupported bits - * reverted appropriately. - */ - -struct serial_rs485 { - __u32 flags; /* RS485 feature flags */ -#define SER_RS485_ENABLED (1 << 0) -#define SER_RS485_RTS_ON_SEND (1 << 1) -#define SER_RS485_RTS_AFTER_SEND (1 << 2) - __u32 delay_rts_before_send; /* Milliseconds */ - __u32 padding[6]; /* Memory is cheap, new structs - are a royal PITA .. */ -}; #ifdef __KERNEL__ #include diff --git a/trunk/include/linux/serial_core.h b/trunk/include/linux/serial_core.h index e27f216361fc..3b2f6c04855e 100644 --- a/trunk/include/linux/serial_core.h +++ b/trunk/include/linux/serial_core.h @@ -241,7 +241,7 @@ typedef unsigned int __bitwise__ upf_t; struct uart_port { spinlock_t lock; /* port lock */ - unsigned long iobase; /* in/out[bwl] */ + unsigned int iobase; /* in/out[bwl] */ unsigned char __iomem *membase; /* read/write[bwl] */ unsigned int irq; /* irq number */ unsigned int uartclk; /* base uart clock */ diff --git a/trunk/include/linux/termios.h b/trunk/include/linux/termios.h index 2acd0c1f8a2a..478662889f48 100644 --- a/trunk/include/linux/termios.h +++ b/trunk/include/linux/termios.h @@ -4,19 +4,4 @@ #include #include -#define NFF 5 - -struct termiox -{ - __u16 x_hflag; - __u16 x_cflag; - __u16 x_rflag[NFF]; - __u16 x_sflag; -}; - -#define RTSXOFF 0x0001 /* RTS flow control on input */ -#define CTSXON 0x0002 /* CTS flow control on output */ -#define DTRXOFF 0x0004 /* DTR flow control on input */ -#define DSRXON 0x0008 /* DCD flow control on output */ - #endif diff --git a/trunk/include/linux/tty.h b/trunk/include/linux/tty.h index 3b8121d4e36f..0cbec74ec086 100644 --- a/trunk/include/linux/tty.h +++ b/trunk/include/linux/tty.h @@ -23,7 +23,7 @@ */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ -#define NR_LDISCS 19 +#define NR_LDISCS 18 /* line disciplines */ #define N_TTY 0 @@ -45,7 +45,6 @@ #define N_HCI 15 /* Bluetooth HCI UART */ #define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */ #define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ -#define N_PPS 18 /* Pulse per Second */ /* * This character is the same as _POSIX_VDISABLE: it cannot be used as @@ -182,7 +181,6 @@ struct signal_struct; struct tty_port { struct tty_struct *tty; /* Back pointer */ - spinlock_t lock; /* Lock protecting tty field */ int blocked_open; /* Waiting to open */ int count; /* Usage count */ wait_queue_head_t open_wait; /* Open waiters */ @@ -210,7 +208,6 @@ struct tty_operations; struct tty_struct { int magic; - struct kref kref; struct tty_driver *driver; const struct tty_operations *ops; int index; @@ -220,7 +217,6 @@ struct tty_struct { spinlock_t ctrl_lock; /* Termios values are protected by the termios mutex */ struct ktermios *termios, *termios_locked; - struct termiox *termiox; /* May be NULL for unsupported */ char name[64]; struct pid *pgrp; /* Protected by ctrl lock */ struct pid *session; @@ -314,25 +310,6 @@ extern int kmsg_redirect; extern void console_init(void); extern int vcs_init(void); -extern struct class *tty_class; - -/** - * tty_kref_get - get a tty reference - * @tty: tty device - * - * Return a new reference to a tty object. The caller must hold - * sufficient locks/counts to ensure that their existing reference cannot - * go away - */ - -extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty) -{ - if (tty) - kref_get(&tty->kref); - return tty; -} -extern void tty_kref_put(struct tty_struct *tty); - extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, const char *routine); extern char *tty_name(struct tty_struct *tty, char *buf); @@ -356,15 +333,13 @@ extern void tty_throttle(struct tty_struct *tty); extern void tty_unthrottle(struct tty_struct *tty); extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, struct winsize *ws); -extern void tty_shutdown(struct tty_struct *tty); -extern void tty_free_termios(struct tty_struct *tty); + extern int is_current_pgrp_orphaned(void); extern struct pid *tty_get_pgrp(struct tty_struct *tty); extern int is_ignored(int sig); extern int tty_signal(int sig, struct tty_struct *tty); extern void tty_hangup(struct tty_struct *tty); extern void tty_vhangup(struct tty_struct *tty); -extern void tty_vhangup_self(void); extern void tty_unhangup(struct file *filp); extern int tty_hung_up_p(struct file *filp); extern void do_SAK(struct tty_struct *tty); @@ -372,9 +347,6 @@ extern void __do_SAK(struct tty_struct *tty); extern void disassociate_ctty(int priv); extern void no_tty(void); extern void tty_flip_buffer_push(struct tty_struct *tty); -extern void tty_buffer_free_all(struct tty_struct *tty); -extern void tty_buffer_flush(struct tty_struct *tty); -extern void tty_buffer_init(struct tty_struct *tty); extern speed_t tty_get_baud_rate(struct tty_struct *tty); extern speed_t tty_termios_baud_rate(struct ktermios *termios); extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); @@ -400,15 +372,6 @@ extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg); extern dev_t tty_devnum(struct tty_struct *tty); extern void proc_clear_tty(struct task_struct *p); extern struct tty_struct *get_current_tty(void); -extern void tty_default_fops(struct file_operations *fops); -extern struct tty_struct *alloc_tty_struct(void); -extern void free_tty_struct(struct tty_struct *tty); -extern void initialize_tty_struct(struct tty_struct *tty, - struct tty_driver *driver, int idx); -extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, - int first_ok); -extern void tty_release_dev(struct file *filp); -extern int tty_init_termios(struct tty_struct *tty); extern struct mutex tty_mutex; @@ -419,8 +382,6 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay); extern void tty_port_init(struct tty_port *port); extern int tty_port_alloc_xmit_buf(struct tty_port *port); extern void tty_port_free_xmit_buf(struct tty_port *port); -extern struct tty_struct *tty_port_tty_get(struct tty_port *port); -extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); extern int tty_unregister_ldisc(int disc); @@ -466,7 +427,7 @@ static inline void tty_audit_push_task(struct task_struct *tsk, #endif /* tty_ioctl.c */ -extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, +extern int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); /* serial.c */ diff --git a/trunk/include/linux/tty_driver.h b/trunk/include/linux/tty_driver.h index 78416b901589..16d27944c321 100644 --- a/trunk/include/linux/tty_driver.h +++ b/trunk/include/linux/tty_driver.h @@ -7,28 +7,6 @@ * defined; unless noted otherwise, they are optional, and can be * filled in with a null pointer. * - * struct tty_struct * (*lookup)(struct tty_driver *self, int idx) - * - * Return the tty device corresponding to idx, NULL if there is not - * one currently in use and an ERR_PTR value on error. Called under - * tty_mutex (for now!) - * - * Optional method. Default behaviour is to use the ttys array - * - * int (*install)(struct tty_driver *self, struct tty_struct *tty) - * - * Install a new tty into the tty driver internal tables. Used in - * conjunction with lookup and remove methods. - * - * Optional method. Default behaviour is to use the ttys array - * - * void (*remove)(struct tty_driver *self, struct tty_struct *tty) - * - * Remove a closed tty from the tty driver internal tables. Used in - * conjunction with lookup and remove methods. - * - * Optional method. Default behaviour is to use the ttys array - * * int (*open)(struct tty_struct * tty, struct file * filp); * * This routine is called when a particular tty device is opened. @@ -43,11 +21,6 @@ * * Required method. * - * void (*shutdown)(struct tty_struct * tty); - * - * This routine is called when a particular tty device is closed for - * the last time freeing up the resources. - * * int (*write)(struct tty_struct * tty, * const unsigned char *buf, int count); * @@ -207,14 +180,6 @@ * not force errors here if they are not resizable objects (eg a serial * line). See tty_do_resize() if you need to wrap the standard method * in your own logic - the usual case. - * - * void (*set_termiox)(struct tty_struct *tty, struct termiox *new); - * - * Called when the device receives a termiox based ioctl. Passes down - * the requested data from user space. This method will not be invoked - * unless the tty also has a valid tty->termiox pointer. - * - * Optional: Called under the termios lock */ #include @@ -225,13 +190,8 @@ struct tty_struct; struct tty_driver; struct tty_operations { - struct tty_struct * (*lookup)(struct tty_driver *driver, - struct inode *inode, int idx); - int (*install)(struct tty_driver *driver, struct tty_struct *tty); - void (*remove)(struct tty_driver *driver, struct tty_struct *tty); int (*open)(struct tty_struct * tty, struct file * filp); void (*close)(struct tty_struct * tty, struct file * filp); - void (*shutdown)(struct tty_struct *tty); int (*write)(struct tty_struct * tty, const unsigned char *buf, int count); int (*put_char)(struct tty_struct *tty, unsigned char ch); @@ -260,7 +220,6 @@ struct tty_operations { unsigned int set, unsigned int clear); int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty, struct winsize *ws); - int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); #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); @@ -270,7 +229,6 @@ struct tty_operations { struct tty_driver { int magic; /* magic number for this structure */ - struct kref kref; /* Reference management */ struct cdev cdev; struct module *owner; const char *driver_name; @@ -284,6 +242,7 @@ struct tty_driver { short subtype; /* subtype of tty driver */ struct ktermios init_termios; /* Initial termios */ int flags; /* tty driver flags */ + int refcount; /* for loadable tty drivers */ struct proc_dir_entry *proc_entry; /* /proc fs entry */ struct tty_driver *other; /* only used for the PTY driver */ @@ -305,19 +264,12 @@ struct tty_driver { extern struct list_head tty_drivers; -extern struct tty_driver *alloc_tty_driver(int lines); -extern void put_tty_driver(struct tty_driver *driver); -extern void tty_set_operations(struct tty_driver *driver, +struct tty_driver *alloc_tty_driver(int lines); +void put_tty_driver(struct tty_driver *driver); +void tty_set_operations(struct tty_driver *driver, const struct tty_operations *op); extern struct tty_driver *tty_find_polling_driver(char *name, int *line); -extern void tty_driver_kref_put(struct tty_driver *driver); -extern inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) -{ - kref_get(&d->kref); - return d; -} - /* tty driver magic number */ #define TTY_DRIVER_MAGIC 0x5402 diff --git a/trunk/include/linux/vt_kern.h b/trunk/include/linux/vt_kern.h index 2f1113467f70..1cbd0a7db4e6 100644 --- a/trunk/include/linux/vt_kern.h +++ b/trunk/include/linux/vt_kern.h @@ -96,7 +96,7 @@ void change_console(struct vc_data *new_vc); void reset_vc(struct vc_data *vc); extern int unbind_con_driver(const struct consw *csw, int first, int last, int deflt); -int vty_init(const struct file_operations *console_fops); +int vty_init(void); /* * vc_screen.c shares this temporary buffer with the console write code so that diff --git a/trunk/kernel/acct.c b/trunk/kernel/acct.c index f6006a60df5d..dd68b9059418 100644 --- a/trunk/kernel/acct.c +++ b/trunk/kernel/acct.c @@ -548,7 +548,7 @@ static void do_acct_process(struct bsd_acct_struct *acct, #endif spin_lock_irq(¤t->sighand->siglock); - tty = current->signal->tty; /* Safe as we hold the siglock */ + tty = current->signal->tty; ac.ac_tty = tty ? old_encode_dev(tty_devnum(tty)) : 0; ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime))); ac.ac_stime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_stime))); diff --git a/trunk/kernel/auditsc.c b/trunk/kernel/auditsc.c index cf5bc2f5f9c3..59cedfb040e7 100644 --- a/trunk/kernel/auditsc.c +++ b/trunk/kernel/auditsc.c @@ -246,8 +246,8 @@ static int audit_match_perm(struct audit_context *ctx, int mask) unsigned n; if (unlikely(!ctx)) return 0; - n = ctx->major; + n = ctx->major; switch (audit_classify_syscall(ctx->arch, n)) { case 0: /* native */ if ((mask & AUDIT_PERM_WRITE) && @@ -1204,13 +1204,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts (context->return_valid==AUDITSC_SUCCESS)?"yes":"no", context->return_code); - spin_lock_irq(&tsk->sighand->siglock); + mutex_lock(&tty_mutex); + read_lock(&tasklist_lock); if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) tty = tsk->signal->tty->name; else tty = "(none)"; - spin_unlock_irq(&tsk->sighand->siglock); - + read_unlock(&tasklist_lock); audit_log_format(ab, " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" " ppid=%d pid=%d auid=%u uid=%u gid=%u" @@ -1230,6 +1230,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts context->egid, context->sgid, context->fsgid, tty, tsk->sessionid); + mutex_unlock(&tty_mutex); audit_log_task_info(ab, tsk); if (context->filterkey) { diff --git a/trunk/kernel/fork.c b/trunk/kernel/fork.c index 30de644a40c4..7ce2ebe84796 100644 --- a/trunk/kernel/fork.c +++ b/trunk/kernel/fork.c @@ -802,7 +802,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) sig->leader = 0; /* session leadership doesn't inherit */ sig->tty_old_pgrp = NULL; - sig->tty = NULL; sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero; sig->gtime = cputime_zero; @@ -839,7 +838,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) void __cleanup_signal(struct signal_struct *sig) { exit_thread_group_keys(sig); - tty_kref_put(sig->tty); kmem_cache_free(signal_cachep, sig); } @@ -1229,8 +1227,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->nsproxy->pid_ns->child_reaper = p; p->signal->leader_pid = pid; - tty_kref_put(p->signal->tty); - p->signal->tty = tty_kref_get(current->signal->tty); + p->signal->tty = current->signal->tty; set_task_pgrp(p, task_pgrp_nr(current)); set_task_session(p, task_session_nr(current)); attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); diff --git a/trunk/kernel/printk.c b/trunk/kernel/printk.c index a430fd04008b..b51b1567bb55 100644 --- a/trunk/kernel/printk.c +++ b/trunk/kernel/printk.c @@ -1291,6 +1291,22 @@ static int __init disable_boot_consoles(void) } late_initcall(disable_boot_consoles); +/** + * tty_write_message - write a message to a certain tty, not just the console. + * @tty: the destination tty_struct + * @msg: the message to write + * + * This is used for messages that need to be redirected to a specific tty. + * We don't put it into the syslog queue right now maybe in the future if + * really needed. + */ +void tty_write_message(struct tty_struct *tty, char *msg) +{ + if (tty && tty->ops->write) + tty->ops->write(tty, msg, strlen(msg)); + return; +} + #if defined CONFIG_PRINTK /* diff --git a/trunk/kernel/sys.c b/trunk/kernel/sys.c index 234d9454294e..038a7bc0901d 100644 --- a/trunk/kernel/sys.c +++ b/trunk/kernel/sys.c @@ -1060,7 +1060,9 @@ asmlinkage long sys_setsid(void) group_leader->signal->leader = 1; __set_special_pids(sid); - proc_clear_tty(group_leader); + spin_lock(&group_leader->sighand->siglock); + group_leader->signal->tty = NULL; + spin_unlock(&group_leader->sighand->siglock); err = session; out: diff --git a/trunk/security/selinux/hooks.c b/trunk/security/selinux/hooks.c index 48881394fbd4..4a7374c12d9c 100644 --- a/trunk/security/selinux/hooks.c +++ b/trunk/security/selinux/hooks.c @@ -2121,6 +2121,7 @@ static inline void flush_unauthorized_files(struct files_struct *files) long j = -1; int drop_tty = 0; + mutex_lock(&tty_mutex); tty = get_current_tty(); if (tty) { file_list_lock(); @@ -2138,8 +2139,8 @@ static inline void flush_unauthorized_files(struct files_struct *files) } } file_list_unlock(); - tty_kref_put(tty); } + mutex_unlock(&tty_mutex); /* Reset controlling tty. */ if (drop_tty) no_tty();