summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig31
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/agp/sworks-agp.c1
-rw-r--r--drivers/char/amiserial.c35
-rw-r--r--drivers/char/cs5535_gpio.c250
-rw-r--r--drivers/char/cyclades.c91
-rw-r--r--drivers/char/drm/drm_ioc32.c1
-rw-r--r--drivers/char/drm/i915_ioc32.c1
-rw-r--r--drivers/char/drm/mga_ioc32.c1
-rw-r--r--drivers/char/drm/r128_ioc32.c1
-rw-r--r--drivers/char/drm/radeon_ioc32.c1
-rw-r--r--drivers/char/epca.c17
-rw-r--r--drivers/char/esp.c67
-rw-r--r--drivers/char/hangcheck-timer.c2
-rw-r--r--drivers/char/hvc_console.c6
-rw-r--r--drivers/char/hvcs.c10
-rw-r--r--drivers/char/hvsi.c2
-rw-r--r--drivers/char/hw_random.c71
-rw-r--r--drivers/char/ip2/i2lib.c2
-rw-r--r--drivers/char/ip2main.c26
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c6
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c3
-rw-r--r--drivers/char/isicom.c2084
-rw-r--r--drivers/char/istallion.c45
-rw-r--r--drivers/char/mem.c46
-rw-r--r--drivers/char/mmtimer.c90
-rw-r--r--drivers/char/moxa.c75
-rw-r--r--drivers/char/mxser.c4
-rw-r--r--drivers/char/n_hdlc.c19
-rw-r--r--drivers/char/n_r3964.c10
-rw-r--r--drivers/char/n_tty.c66
-rw-r--r--drivers/char/nvram.c12
-rw-r--r--drivers/char/pcmcia/synclink_cs.c32
-rw-r--r--drivers/char/pty.c4
-rw-r--r--drivers/char/rio/rio_linux.c6
-rw-r--r--drivers/char/rio/riointr.c13
-rw-r--r--drivers/char/riscom8.c47
-rw-r--r--drivers/char/rocket.c19
-rw-r--r--drivers/char/s3c2410-rtc.c2
-rw-r--r--drivers/char/selection.c5
-rw-r--r--drivers/char/ser_a2232.c8
-rw-r--r--drivers/char/serial167.c37
-rw-r--r--drivers/char/sonypi.c381
-rw-r--r--drivers/char/specialix.c38
-rw-r--r--drivers/char/stallion.c65
-rw-r--r--drivers/char/sx.c19
-rw-r--r--drivers/char/synclink.c51
-rw-r--r--drivers/char/synclink_gt.c4499
-rw-r--r--drivers/char/synclinkmp.c38
-rw-r--r--drivers/char/sysrq.c19
-rw-r--r--drivers/char/tpm/Makefile3
-rw-r--r--drivers/char/tpm/tpm.c3
-rw-r--r--drivers/char/tpm/tpm.h15
-rw-r--r--drivers/char/tpm/tpm_bios.c540
-rw-r--r--drivers/char/tty_io.c266
-rw-r--r--drivers/char/viocons.c3
-rw-r--r--drivers/char/vme_scc.c20
-rw-r--r--drivers/char/vr41xx_giu.c4
-rw-r--r--drivers/char/vr41xx_rtc.c5
-rw-r--r--drivers/char/vt.c33
-rw-r--r--drivers/char/watchdog/Kconfig2
-rw-r--r--drivers/char/watchdog/cpu5wdt.c9
-rw-r--r--drivers/char/watchdog/mpc8xx_wdt.c20
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c4
-rw-r--r--drivers/char/watchdog/wdt977.c216
65 files changed, 7518 insertions, 1986 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 84e68cdd451..d6fcd0a36f9 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -80,7 +80,7 @@ config SERIAL_NONSTANDARD
config COMPUTONE
tristate "Computone IntelliPort Plus serial support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+ depends on SERIAL_NONSTANDARD
---help---
This driver supports the entire family of Intelliport II/Plus
controllers with the exception of the MicroChannel controllers and
@@ -153,7 +153,7 @@ config DIGIEPCA
config ESPSERIAL
tristate "Hayes ESP serial port support"
- depends on SERIAL_NONSTANDARD && ISA && BROKEN_ON_SMP && ISA_DMA_API
+ depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API
help
This is a driver which supports Hayes ESP serial ports. Both single
port cards and multiport cards are supported. Make sure to read
@@ -166,7 +166,7 @@ config ESPSERIAL
config MOXA_INTELLIO
tristate "Moxa Intellio support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+ depends on SERIAL_NONSTANDARD
help
Say Y here if you have a Moxa Intellio multiport serial card.
@@ -220,6 +220,14 @@ config SYNCLINKMP
The module will be called synclinkmp. If you want to do that, say M
here.
+config SYNCLINK_GT
+ tristate "SyncLink GT/AC support"
+ depends on SERIAL_NONSTANDARD
+ help
+ Support for SyncLink GT and SyncLink AC families of
+ synchronous and asynchronous serial adapters
+ manufactured by Microgate Systems, Ltd. (www.microgate.com)
+
config N_HDLC
tristate "HDLC line discipline support"
depends on SERIAL_NONSTANDARD
@@ -282,7 +290,7 @@ config SX
config RIO
tristate "Specialix RIO system support"
- depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+ depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && !64BIT
help
This is a driver for the Specialix RIO, a smart serial card which
drives an outboard box that can support up to 128 ports. Product
@@ -687,7 +695,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
- depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI)
+ depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -735,7 +743,7 @@ config SGI_IP27_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC
+ depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -928,6 +936,15 @@ config SCx200_GPIO
If compiled as a module, it will be called scx200_gpio.
+config CS5535_GPIO
+ tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)"
+ depends on X86_32
+ help
+ Give userspace access to the GPIO pins on the AMD CS5535 and
+ CS5536 Geode companion devices.
+
+ If compiled as a module, it will be called cs5535_gpio.
+
config GPIO_VR41XX
tristate "NEC VR4100 series General-purpose I/O Unit support"
depends on CPU_VR41XX
@@ -985,7 +1002,7 @@ config HPET_MMAP
config HANGCHECK_TIMER
tristate "Hangcheck timer"
- depends on X86 || IA64 || PPC64 || ARCH_S390
+ depends on X86 || IA64 || PPC64 || S390
help
The hangcheck-timer module detects when the system has gone
out to lunch past a certain margin. It can reboot the system
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 4aeae687e88..503dd901d40 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_RISCOM8) += riscom8.o
obj-$(CONFIG_ISI) += isicom.o
obj-$(CONFIG_SYNCLINK) += synclink.o
obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
+obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
@@ -80,6 +81,7 @@ obj-$(CONFIG_PPDEV) += ppdev.o
obj-$(CONFIG_NWBUTTON) += nwbutton.o
obj-$(CONFIG_NWFLASH) += nwflash.o
obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
+obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_TANBAC_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 3f8f7fa6b0f..268f78d926d 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/jiffies.h>
#include <linux/agp_backend.h>
#include "agp.h"
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index a124f8c5d06..869518e4035 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -116,7 +116,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
static struct serial_state rs_table[1];
-#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
+#define NR_PORTS ARRAY_SIZE(rs_table)
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
@@ -265,8 +265,9 @@ static _INLINE_ void receive_chars(struct async_struct *info)
int status;
int serdatr;
struct tty_struct *tty = info->tty;
- unsigned char ch;
+ unsigned char ch, flag;
struct async_icount *icount;
+ int oe = 0;
icount = &info->state->icount;
@@ -282,15 +283,12 @@ static _INLINE_ void receive_chars(struct async_struct *info)
status |= UART_LSR_OE;
ch = serdatr & 0xff;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- goto ignore_char;
- *tty->flip.char_buf_ptr = ch;
icount->rx++;
#ifdef SERIAL_DEBUG_INTR
printk("DR%02x:%02x...", ch, status);
#endif
- *tty->flip.flag_buf_ptr = 0;
+ flag = TTY_NORMAL;
/*
* We don't handle parity or frame errors - but I have left
@@ -319,7 +317,7 @@ static _INLINE_ void receive_chars(struct async_struct *info)
* should be ignored.
*/
if (status & info->ignore_status_mask)
- goto ignore_char;
+ goto out;
status &= info->read_status_mask;
@@ -327,33 +325,28 @@ static _INLINE_ void receive_chars(struct async_struct *info)
#ifdef SERIAL_DEBUG_INTR
printk("handling break....");
#endif
- *tty->flip.flag_buf_ptr = TTY_BREAK;
+ flag = TTY_BREAK;
if (info->flags & ASYNC_SAK)
do_SAK(tty);
} else if (status & UART_LSR_PE)
- *tty->flip.flag_buf_ptr = TTY_PARITY;
+ flag = TTY_PARITY;
else if (status & UART_LSR_FE)
- *tty->flip.flag_buf_ptr = TTY_FRAME;
+ flag = TTY_FRAME;
if (status & UART_LSR_OE) {
/*
* Overrun is special, since it's
* reported immediately, and doesn't
* affect the current character
*/
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- }
+ oe = 1;
}
}
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
- ignore_char:
-
+ tty_insert_flip_char(tty, ch, flag);
+ if (oe == 1)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
tty_flip_buffer_push(tty);
+out:
+ return;
}
static _INLINE_ void transmit_chars(struct async_struct *info)
diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c
new file mode 100644
index 00000000000..5d72f50de1a
--- /dev/null
+++ b/drivers/char/cs5535_gpio.c
@@ -0,0 +1,250 @@
+/*
+ * AMD CS5535/CS5536 GPIO driver.
+ * Allows a user space process to play with the GPIO pins.
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+
+#define NAME "cs5535_gpio"
+
+MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
+MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO Pin Driver");
+MODULE_LICENSE("GPL");
+
+static int major;
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "Major device number");
+
+static ulong mask;
+module_param(mask, ulong, 0);
+MODULE_PARM_DESC(mask, "GPIO channel mask");
+
+#define MSR_LBAR_GPIO 0x5140000C
+
+static u32 gpio_base;
+
+static struct pci_device_id divil_pci[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+ { } /* NULL entry */
+};
+
+static struct cdev cs5535_gpio_cdev;
+
+/* reserve 32 entries even though some aren't usable */
+#define CS5535_GPIO_COUNT 32
+
+/* IO block size */
+#define CS5535_GPIO_SIZE 256
+
+struct gpio_regmap {
+ u32 rd_offset;
+ u32 wr_offset;
+ char on;
+ char off;
+};
+static struct gpio_regmap rm[] =
+{
+ { 0x30, 0x00, '1', '0' }, /* GPIOx_READ_BACK / GPIOx_OUT_VAL */
+ { 0x20, 0x20, 'I', 'i' }, /* GPIOx_IN_EN */
+ { 0x04, 0x04, 'O', 'o' }, /* GPIOx_OUT_EN */
+ { 0x08, 0x08, 't', 'T' }, /* GPIOx_OUT_OD_EN */
+ { 0x18, 0x18, 'P', 'p' }, /* GPIOx_OUT_PU_EN */
+ { 0x1c, 0x1c, 'D', 'd' }, /* GPIOx_OUT_PD_EN */
+};
+
+
+/**
+ * Gets the register offset for the GPIO bank.
+ * Low (0-15) starts at 0x00, high (16-31) starts at 0x80
+ */
+static inline u32 cs5535_lowhigh_base(int reg)
+{
+ return (reg & 0x10) << 3;
+}
+
+static ssize_t cs5535_gpio_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ u32 m = iminor(file->f_dentry->d_inode);
+ int i, j;
+ u32 base = gpio_base + cs5535_lowhigh_base(m);
+ u32 m0, m1;
+ char c;
+
+ /**
+ * Creates the mask for atomic bit programming.
+ * The high 16 bits and the low 16 bits are used to set the mask.
+ * For example, GPIO 15 maps to 31,15: 0,1 => On; 1,0=> Off
+ */
+ m1 = 1 << (m & 0x0F);
+ m0 = m1 << 16;
+
+ for (i = 0; i < len; ++i) {
+ if (get_user(c, data+i))
+ return -EFAULT;
+
+ for (j = 0; j < ARRAY_SIZE(rm); j++) {
+ if (c == rm[j].on) {
+ outl(m1, base + rm[j].wr_offset);
+ break;
+ } else if (c == rm[j].off) {
+ outl(m0, base + rm[j].wr_offset);
+ break;
+ }
+ }
+ }
+ *ppos = 0;
+ return len;
+}
+
+static ssize_t cs5535_gpio_read(struct file *file, char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ u32 m = iminor(file->f_dentry->d_inode);
+ u32 base = gpio_base + cs5535_lowhigh_base(m);
+ int rd_bit = 1 << (m & 0x0f);
+ int i;
+ char ch;
+ ssize_t count = 0;
+
+ if (*ppos >= ARRAY_SIZE(rm))
+ return 0;
+
+ for (i = *ppos; (i < (*ppos + len)) && (i < ARRAY_SIZE(rm)); i++) {
+ ch = (inl(base + rm[i].rd_offset) & rd_bit) ?
+ rm[i].on : rm[i].off;
+
+ if (put_user(ch, buf+count))
+ return -EFAULT;
+
+ count++;
+ }
+
+ /* add a line-feed if there is room */
+ if ((i == ARRAY_SIZE(rm)) && (count < len)) {
+ put_user('\n', buf + count);
+ count++;
+ }
+
+ *ppos += count;
+ return count;
+}
+
+static int cs5535_gpio_open(struct inode *inode, struct file *file)
+{
+ u32 m = iminor(inode);
+
+ /* the mask says which pins are usable by this driver */
+ if ((mask & (1 << m)) == 0)
+ return -EINVAL;
+
+ return nonseekable_open(inode, file);
+}
+
+static struct file_operations cs5535_gpio_fops = {
+ .owner = THIS_MODULE,
+ .write = cs5535_gpio_write,
+ .read = cs5535_gpio_read,
+ .open = cs5535_gpio_open
+};
+
+static int __init cs5535_gpio_init(void)
+{
+ dev_t dev_id;
+ u32 low, hi;
+ int retval;
+
+ if (pci_dev_present(divil_pci) == 0) {
+ printk(KERN_WARNING NAME ": DIVIL not found\n");
+ return -ENODEV;
+ }
+
+ /* Grab the GPIO I/O range */
+ rdmsr(MSR_LBAR_GPIO, low, hi);
+
+ /* Check the mask and whether GPIO is enabled (sanity check) */
+ if (hi != 0x0000f001) {
+ printk(KERN_WARNING NAME ": GPIO not enabled\n");
+ return -ENODEV;
+ }
+
+ /* Mask off the IO base address */
+ gpio_base = low & 0x0000ff00;
+
+ /**
+ * Some GPIO pins
+ * 31-29,23 : reserved (always mask out)
+ * 28 : Power Button
+ * 26 : PME#
+ * 22-16 : LPC
+ * 14,15 : SMBus
+ * 9,8 : UART1
+ * 7 : PCI INTB
+ * 3,4 : UART2/DDC
+ * 2 : IDE_IRQ0
+ * 0 : PCI INTA
+ *
+ * If a mask was not specified, be conservative and only allow:
+ * 1,2,5,6,10-13,24,25,27
+ */
+ if (mask != 0)
+ mask &= 0x1f7fffff;
+ else
+ mask = 0x0b003c66;
+
+ if (request_region(gpio_base, CS5535_GPIO_SIZE, NAME) == 0) {
+ printk(KERN_ERR NAME ": can't allocate I/O for GPIO\n");
+ return -ENODEV;
+ }
+
+ if (major) {
+ dev_id = MKDEV(major, 0);
+ retval = register_chrdev_region(dev_id, CS5535_GPIO_COUNT,
+ NAME);
+ } else {
+ retval = alloc_chrdev_region(&dev_id, 0, CS5535_GPIO_COUNT,
+ NAME);
+ major = MAJOR(dev_id);
+ }
+
+ if (retval) {
+ release_region(gpio_base, CS5535_GPIO_SIZE);
+ return -1;
+ }
+
+ printk(KERN_DEBUG NAME ": base=%#x mask=%#lx major=%d\n",
+ gpio_base, mask, major);
+
+ cdev_init(&cs5535_gpio_cdev, &cs5535_gpio_fops);
+ cdev_add(&cs5535_gpio_cdev, dev_id, CS5535_GPIO_COUNT);
+
+ return 0;
+}
+
+static void __exit cs5535_gpio_cleanup(void)
+{
+ dev_t dev_id = MKDEV(major, 0);
+ unregister_chrdev_region(dev_id, CS5535_GPIO_COUNT);
+ if (gpio_base != 0)
+ release_region(gpio_base, CS5535_GPIO_SIZE);
+}
+
+module_init(cs5535_gpio_init);
+module_exit(cs5535_gpio_cleanup);
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index c7f818cd7b0..39c61a71176 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -641,6 +641,7 @@ static char rcsid[] =
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
+#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/major.h>
#include <linux/string.h>
@@ -723,7 +724,7 @@ static unsigned int cy_isa_addresses[] = {
0xDE000,
0,0,0,0,0,0,0,0
};
-#define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
+#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
#ifdef MODULE
static long maddr[NR_CARDS] = { 0, };
@@ -1086,7 +1087,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
int had_work;
int mdm_change;
int mdm_status;
-
+ int len;
if((cinfo = (struct cyclades_card *)dev_id) == 0){
#ifdef CY_DEBUG_INTERRUPTS
printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
@@ -1163,63 +1164,43 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
info->icount.rx++;
continue;
}
- if (tty->flip.count < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
+ if (tty_buffer_request_room(tty, 1)) {
if (data & info->read_status_mask){
if(data & CyBREAK){
- *tty->flip.flag_buf_ptr++ =
- TTY_BREAK;
- *tty->flip.char_buf_ptr++ =
- cy_readb(base_addr+(CyRDSR<<index));
+ tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_BREAK);
info->icount.rx++;
if (info->flags & ASYNC_SAK){
do_SAK(tty);
}
}else if(data & CyFRAME){
- *tty->flip.flag_buf_ptr++ =
- TTY_FRAME;
- *tty->flip.char_buf_ptr++ =
- cy_readb(base_addr+(CyRDSR<<index));
+ tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME);
info->icount.rx++;
info->idle_stats.frame_errs++;
}else if(data & CyPARITY){
- *tty->flip.flag_buf_ptr++ =
- TTY_PARITY;
- *tty->flip.char_buf_ptr++ =
- cy_readb(base_addr+(CyRDSR<<index));
+ /* Pieces of seven... */
+ tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_PARITY);
info->icount.rx++;
info->idle_stats.parity_errs++;
}else if(data & CyOVERRUN){
- *tty->flip.flag_buf_ptr++ =
- TTY_OVERRUN;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
info->icount.rx++;
/* If the flip buffer itself is
overflowing, we still lose
the next incoming character.
*/
- if(tty->flip.count
- < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ =
- TTY_NORMAL;
- *tty->flip.char_buf_ptr++ =
- cy_readb(base_addr+(CyRDSR<<index));
- info->icount.rx++;
- }
+ tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME);
+ info->icount.rx++;
info->idle_stats.overruns++;
/* These two conditions may imply */
/* a normal read should be done. */
/* }else if(data & CyTIMEOUT){ */
/* }else if(data & CySPECHAR){ */
- }else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
- info->icount.rx++;
+ }else {
+ tty_insert_flip_char(tty, 0, TTY_NORMAL);
+ info->icount.rx++;
}
}else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_NORMAL);
info->icount.rx++;
}
}else{
@@ -1240,14 +1221,10 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
info->mon.char_max = char_count;
info->mon.char_last = char_count;
#endif
- while(char_count--){
- if (tty->flip.count >= TTY_FLIPBUF_SIZE){
- break;
- }
- tty->flip.count++;
+ len = tty_buffer_request_room(tty, char_count);
+ while(len--){
data = cy_readb(base_addr+(CyRDSR<<index));
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
info->idle_stats.recv_bytes++;
info->icount.rx++;
#ifdef CY_16Y_HACK
@@ -1256,7 +1233,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
info->idle_stats.recv_idle = jiffies;
}
- schedule_delayed_work(&tty->flip.work, 1);
+ schedule_delayed_work(&tty->buf.work, 1);
}
/* end of service */
cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f));
@@ -1551,6 +1528,7 @@ cyz_handle_rx(struct cyclades_port *info,
struct cyclades_card *cinfo = &cy_card[info->card];
struct tty_struct *tty = info->tty;
volatile int char_count;
+ int len;
#ifdef BLOCKMOVE
int small_count;
#else
@@ -1606,18 +1584,11 @@ cyz_handle_rx(struct cyclades_port *info,
tty->flip.count += small_count;
}
#else
- while(char_count--){
- if (tty->flip.count >= N_TTY_BUF_SIZE - tty->read_cnt)
- break;
-
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- break;
-
+ len = tty_buffer_request_room(tty, char_count);
+ while(len--){
data = cy_readb(cinfo->base_addr + rx_bufaddr + new_rx_get);
new_rx_get = (new_rx_get + 1) & (rx_bufsize - 1);
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
info->idle_stats.recv_bytes++;
info->icount.rx++;
}
@@ -1635,7 +1606,7 @@ cyz_handle_rx(struct cyclades_port *info,
}
#endif
info->idle_stats.recv_idle = jiffies;
- schedule_delayed_work(&tty->flip.work, 1);
+ schedule_delayed_work(&tty->buf.work, 1);
}
/* Update rx_get */
cy_writel(&buf_ctrl->rx_get, new_rx_get);
@@ -1763,23 +1734,17 @@ cyz_handle_cmd(struct cyclades_card *cinfo)
switch(cmd) {
case C_CM_PR_ERROR:
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_PARITY);
info->icount.rx++;
special_count++;
break;
case C_CM_FR_ERROR:
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_FRAME);
info->icount.rx++;
special_count++;
break;
case C_CM_RXBRK:
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
info->icount.rx++;
special_count++;
break;
@@ -1844,7 +1809,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo)
if(delta_count)
cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
if(special_count)
- schedule_delayed_work(&tty->flip.work, 1);
+ schedule_delayed_work(&tty->buf.work, 1);
}
}
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
index dd91ff6b474..e9e2db18952 100644
--- a/drivers/char/drm/drm_ioc32.c
+++ b/drivers/char/drm/drm_ioc32.c
@@ -28,7 +28,6 @@
* IN THE SOFTWARE.
*/
#include <linux/compat.h>
-#include <linux/ioctl32.h>
#include "drmP.h"
#include "drm_core.h"
diff --git a/drivers/char/drm/i915_ioc32.c b/drivers/char/drm/i915_ioc32.c
index 2218a946ec8..296248cdc76 100644
--- a/drivers/char/drm/i915_ioc32.c
+++ b/drivers/char/drm/i915_ioc32.c
@@ -30,7 +30,6 @@
* IN THE SOFTWARE.
*/
#include <linux/compat.h>
-#include <linux/ioctl32.h>
#include "drmP.h"
#include "drm.h"
diff --git a/drivers/char/drm/mga_ioc32.c b/drivers/char/drm/mga_ioc32.c
index 24a9d4e86af..54a18eb2fc0 100644
--- a/drivers/char/drm/mga_ioc32.c
+++ b/drivers/char/drm/mga_ioc32.c
@@ -31,7 +31,6 @@
* IN THE SOFTWARE.
*/
#include <linux/compat.h>
-#include <linux/ioctl32.h>
#include "drmP.h"
#include "drm.h"
diff --git a/drivers/char/drm/r128_ioc32.c b/drivers/char/drm/r128_ioc32.c
index 1e2e367b8b8..9dd6d4116e4 100644
--- a/drivers/char/drm/r128_ioc32.c
+++ b/drivers/char/drm/r128_ioc32.c
@@ -30,7 +30,6 @@
* IN THE SOFTWARE.
*/
#include <linux/compat.h>
-#include <linux/ioctl32.h>
#include "drmP.h"
#include "drm.h"
diff --git a/drivers/char/drm/radeon_ioc32.c b/drivers/char/drm/radeon_ioc32.c
index fef4a2b84c1..0ccfd3618ff 100644
--- a/drivers/char/drm/radeon_ioc32.c
+++ b/drivers/char/drm/radeon_ioc32.c
@@ -28,7 +28,6 @@
* IN THE SOFTWARE.
*/
#include <linux/compat.h>
-#include <linux/ioctl32.h>
#include "drmP.h"
#include "drm.h"
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 407708a001e..765c5c108bf 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -1786,9 +1786,7 @@ static void doevent(int crd)
if (tty) { /* Begin if valid tty */
if (event & BREAK_IND) { /* Begin if BREAK_IND */
/* A break has been indicated */
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
tty_schedule_flip(tty);
} else if (event & LOWTX_IND) { /* Begin LOWTX_IND */
if (ch->statusflags & LOWWAIT)
@@ -2124,7 +2122,6 @@ static void receive_data(struct channel *ch)
int dataToRead, wrapgap, bytesAvailable;
unsigned int tail, head;
unsigned int wrapmask;
- int rc;
/* ---------------------------------------------------------------
This routine is called by doint when a receive data event
@@ -2162,16 +2159,15 @@ static void receive_data(struct channel *ch)
return;
}
- if (tty->flip.count == TTY_FLIPBUF_SIZE)
+ if (tty_buffer_request_room(tty, bytesAvailable + 1) == 0)
return;
if (readb(&bc->orun)) {
writeb(0, &bc->orun);
printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name);
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
rxwinon(ch);
- rptr = tty->flip.char_buf_ptr;
- rc = tty->flip.count;
while (bytesAvailable > 0) { /* Begin while there is data on the card */
wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
/* ---------------------------------------------------------------
@@ -2183,8 +2179,7 @@ static void receive_data(struct channel *ch)
/* --------------------------------------------------------------
Make sure we don't overflow the buffer
----------------------------------------------------------------- */
- if ((rc + dataToRead) > TTY_FLIPBUF_SIZE)
- dataToRead = TTY_FLIPBUF_SIZE - rc;
+ dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
if (dataToRead == 0)
break;
/* ---------------------------------------------------------------
@@ -2192,13 +2187,9 @@ static void receive_data(struct channel *ch)
for translation if necessary.
------------------------------------------------------------------ */
memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
- rc += dataToRead;
- rptr += dataToRead;
tail = (tail + dataToRead) & wrapmask;
bytesAvailable -= dataToRead;
} /* End while there is data on the card */
- tty->flip.count = rc;
- tty->flip.char_buf_ptr = rptr;
globalwinon(ch);
writew(tail, &bc->rout);
/* Must be called with global data */
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 9f53d2fcc36..e469f641c72 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -345,26 +345,22 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
for (i = 0; i < num_bytes; i++) {
if (!(err_buf->data[i] & status_mask)) {
- *(tty->flip.char_buf_ptr++) = pio_buf->data[i];
+ int flag = 0;
if (err_buf->data[i] & 0x04) {
- *(tty->flip.flag_buf_ptr++) = TTY_BREAK;
-
+ flag = TTY_BREAK;
if (info->flags & ASYNC_SAK)
do_SAK(tty);
}
else if (err_buf->data[i] & 0x02)
- *(tty->flip.flag_buf_ptr++) = TTY_FRAME;
+ flag = TTY_FRAME;
else if (err_buf->data[i] & 0x01)
- *(tty->flip.flag_buf_ptr++) = TTY_PARITY;
- else
- *(tty->flip.flag_buf_ptr++) = 0;
-
- tty->flip.count++;
+ flag = TTY_PARITY;
+ tty_insert_flip_char(tty, pio_buf->data[i], flag);
}
}
- schedule_delayed_work(&tty->flip.work, 1);
+ schedule_delayed_work(&tty->buf.work, 1);
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
release_pio_buffer(pio_buf);
@@ -397,7 +393,6 @@ static inline void receive_chars_dma_done(struct esp_struct *info,
int num_bytes;
unsigned long flags;
-
flags=claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
@@ -408,38 +403,31 @@ static inline void receive_chars_dma_done(struct esp_struct *info,
info->icount.rx += num_bytes;
- memcpy(tty->flip.char_buf_ptr, dma_buffer, num_bytes);
- tty->flip.char_buf_ptr += num_bytes;
- tty->flip.count += num_bytes;
- memset(tty->flip.flag_buf_ptr, 0, num_bytes);
- tty->flip.flag_buf_ptr += num_bytes;
-
if (num_bytes > 0) {
- tty->flip.flag_buf_ptr--;
+ tty_insert_flip_string(tty, dma_buffer, num_bytes - 1);
status &= (0x1c & info->read_status_mask);
+
+ /* Is the status significant or do we throw the last byte ? */
+ if (!(status & info->ignore_status_mask)) {
+ int statflag = 0;
- if (status & info->ignore_status_mask) {
- tty->flip.count--;
- tty->flip.char_buf_ptr--;
- tty->flip.flag_buf_ptr--;
- } else if (status & 0x10) {
- *tty->flip.flag_buf_ptr = TTY_BREAK;
- (info->icount.brk)++;
- if (info->flags & ASYNC_SAK)
- do_SAK(tty);
- } else if (status & 0x08) {
- *tty->flip.flag_buf_ptr = TTY_FRAME;
- (info->icount.frame)++;
- }
- else if (status & 0x04) {
- *tty->flip.flag_buf_ptr = TTY_PARITY;
- (info->icount.parity)++;
+ if (status & 0x10) {
+ statflag = TTY_BREAK;
+ (info->icount.brk)++;
+ if (info->flags & ASYNC_SAK)
+ do_SAK(tty);
+ } else if (status & 0x08) {
+ statflag = TTY_FRAME;
+ (info->icount.frame)++;
+ }
+ else if (status & 0x04) {
+ statflag = TTY_PARITY;
+ (info->icount.parity)++;
+ }
+ tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag);
}
-
- tty->flip.flag_buf_ptr++;
-
- schedule_delayed_work(&tty->flip.work, 1);
+ schedule_delayed_work(&tty->buf.work, 1);
}
if (dma_bytes != num_bytes) {
@@ -693,8 +681,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id,
num_bytes = serial_in(info, UART_ESI_STAT1) << 8;
num_bytes |= serial_in(info, UART_ESI_STAT2);
- if (num_bytes > (TTY_FLIPBUF_SIZE - info->tty->flip.count))
- num_bytes = TTY_FLIPBUF_SIZE - info->tty->flip.count;
+ num_bytes = tty_buffer_request_room(info->tty, num_bytes);
if (num_bytes) {
if (dma_bytes ||
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index 66e53dd450f..40a67c86420 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -120,7 +120,7 @@ __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks);
#if defined(CONFIG_X86)
# define HAVE_MONOTONIC
# define TIMER_FREQ 1000000000ULL
-#elif defined(CONFIG_ARCH_S390)
+#elif defined(CONFIG_S390)
/* FA240000 is 1 Second in the IBM time universe (Page 4-38 Principles of Op for zSeries */
# define TIMER_FREQ 0xFA240000ULL
#elif defined(CONFIG_IA64)
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index f9217763467..1994a92d473 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -597,9 +597,7 @@ static int hvc_poll(struct hvc_struct *hp)
/* Read data if any */
for (;;) {
- int count = N_INBUF;
- if (count > (TTY_FLIPBUF_SIZE - tty->flip.count))
- count = TTY_FLIPBUF_SIZE - tty->flip.count;
+ int count = tty_buffer_request_room(tty, N_INBUF);
/* If flip is full, just reschedule a later read */
if (count == 0) {
@@ -635,7 +633,7 @@ static int hvc_poll(struct hvc_struct *hp)
tty_insert_flip_char(tty, buf[i], 0);
}
- if (tty->flip.count)
+ if (count)
tty_schedule_flip(tty);
/*
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 53dc77c760f..831eb4e8d9d 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -456,12 +456,11 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
/* remove the read masks */
hvcsd->todo_mask &= ~(HVCS_READ_MASK);
- if ((tty->flip.count + HVCS_BUFF_LEN) < TTY_FLIPBUF_SIZE) {
+ if (tty_buffer_request_room(tty, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) {
got = hvc_get_chars(unit_address,
&buf[0],
HVCS_BUFF_LEN);
- for (i=0;got && i<got;i++)
- tty_insert_flip_char(tty, buf[i], TTY_NORMAL);
+ tty_insert_flip_string(tty, buf, got);
}
/* Give the TTY time to process the data we just sent. */
@@ -469,10 +468,9 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
hvcsd->todo_mask |= HVCS_QUICK_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);
- if (tty->flip.count) {
- /* This is synch because tty->low_latency == 1 */
+ /* This is synch because tty->low_latency == 1 */
+ if(got)
tty_flip_buffer_push(tty);
- }
if (!got) {
/* Do this _after_ the flip_buffer_push */
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index a22aa940e01..a9522189fc9 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -197,7 +197,7 @@ static inline void print_state(struct hvsi_struct *hp)
};
const char *name = state_names[hp->state];
- if (hp->state > (sizeof(state_names)/sizeof(char*)))
+ if (hp->state > ARRAY_SIZE(state_names))
name = "UNKNOWN";
pr_debug("hvsi%i: state = %s\n", hp->index, name);
diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c
index 6f673d2de0b..b3bc2e37e61 100644
--- a/drivers/char/hw_random.c
+++ b/drivers/char/hw_random.c
@@ -1,4 +1,9 @@
/*
+ Added support for the AMD Geode LX RNG
+ (c) Copyright 2004-2005 Advanced Micro Devices, Inc.
+
+ derived from
+
Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
(c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
@@ -95,6 +100,11 @@ static unsigned int via_data_present (void);
static u32 via_data_read (void);
#endif
+static int __init geode_init(struct pci_dev *dev);
+static void geode_cleanup(void);
+static unsigned int geode_data_present (void);
+static u32 geode_data_read (void);
+
struct rng_operations {
int (*init) (struct pci_dev *dev);
void (*cleanup) (void);
@@ -122,6 +132,7 @@ enum {
rng_hw_intel,
rng_hw_amd,
rng_hw_via,
+ rng_hw_geode,
};
static struct rng_operations rng_vendor_ops[] = {
@@ -139,6 +150,9 @@ static struct rng_operations rng_vendor_ops[] = {
/* rng_hw_via */
{ via_init, via_cleanup, via_data_present, via_data_read, 1 },
#endif
+
+ /* rng_hw_geode */
+ { geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 }
};
/*
@@ -155,10 +169,14 @@ static struct pci_device_id rng_pci_tbl[] = {
{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+ { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
{ 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
{ 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
{ 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_geode },
+
{ 0, }, /* terminate list */
};
MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
@@ -460,6 +478,57 @@ static void via_cleanup(void)
}
#endif
+/***********************************************************************
+ *
+ * AMD Geode RNG operations
+ *
+ */
+
+static void __iomem *geode_rng_base = NULL;
+
+#define GEODE_RNG_DATA_REG 0x50
+#define GEODE_RNG_STATUS_REG 0x54
+
+static u32 geode_data_read(void)
+{
+ u32 val;
+
+ assert(geode_rng_base != NULL);
+ val = readl(geode_rng_base + GEODE_RNG_DATA_REG);
+ return val;
+}
+
+static unsigned int geode_data_present(void)
+{
+ u32 val;
+
+ assert(geode_rng_base != NULL);
+ val = readl(geode_rng_base + GEODE_RNG_STATUS_REG);
+ return val;
+}
+
+static void geode_cleanup(void)
+{
+ iounmap(geode_rng_base);
+ geode_rng_base = NULL;
+}
+
+static int geode_init(struct pci_dev *dev)
+{
+ unsigned long rng_base = pci_resource_start(dev, 0);
+
+ if (rng_base == 0)
+ return 1;
+
+ geode_rng_base = ioremap(rng_base, 0x58);
+
+ if (geode_rng_base == NULL) {
+ printk(KERN_ERR PFX "Cannot ioremap RNG memory\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
/***********************************************************************
*
@@ -574,7 +643,7 @@ static int __init rng_init (void)
DPRINTK ("ENTER\n");
- /* Probe for Intel, AMD RNGs */
+ /* Probe for Intel, AMD, Geode RNGs */
for_each_pci_dev(pdev) {
ent = pci_match_id(rng_pci_tbl, pdev);
if (ent) {
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index ba85eb1b6ec..fc944d375be 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -854,7 +854,7 @@ i2Input(i2ChanStrPtr pCh)
count += IBUF_SIZE;
}
// Don't give more than can be taken by the line discipline
- amountToMove = pCh->pTTY->ldisc.receive_room( pCh->pTTY );
+ amountToMove = pCh->pTTY->receive_room;
if (count > amountToMove) {
count = amountToMove;
}
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index d815d197dc3..56e93a5a1e2 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -172,7 +172,7 @@ static int Fip_firmware_size;
/* Private (static) functions */
static int ip2_open(PTTY, struct file *);
static void ip2_close(PTTY, struct file *);
-static int ip2_write(PTTY, int, const unsigned char *, int);
+static int ip2_write(PTTY, const unsigned char *, int);
static void ip2_putchar(PTTY, unsigned char);
static void ip2_flush_chars(PTTY);
static int ip2_write_room(PTTY);
@@ -1713,7 +1713,7 @@ ip2_hangup ( PTTY tty )
/* */
/******************************************************************************/
static int
-ip2_write( PTTY tty, int user, const unsigned char *pData, int count)
+ip2_write( PTTY tty, const unsigned char *pData, int count)
{
i2ChanStrPtr pCh = tty->driver_data;
int bytesSent = 0;
@@ -1726,7 +1726,7 @@ ip2_write( PTTY tty, int user, const unsigned char *pData, int count)
/* This is the actual move bit. Make sure it does what we need!!!!! */
WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
- bytesSent = i2Output( pCh, pData, count, user );
+ bytesSent = i2Output( pCh, pData, count, 0 );
WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
@@ -2001,7 +2001,9 @@ ip2_stop ( PTTY tty )
static int ip2_tiocmget(struct tty_struct *tty, struct file *file)
{
i2ChanStrPtr pCh = DevTable[tty->index];
+#ifdef ENABLE_DSSNOW
wait_queue_t wait;
+#endif
if (pCh == NULL)
return -ENODEV;
@@ -2089,15 +2091,17 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
{
wait_queue_t wait;
i2ChanStrPtr pCh = DevTable[tty->index];
+ i2eBordStrPtr pB;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser;
int rc = 0;
unsigned long flags;
void __user *argp = (void __user *)arg;
- if ( pCh == NULL ) {
+ if ( pCh == NULL )
return -ENODEV;
- }
+
+ pB = pCh->pMyBord;
ip2trace (CHANN, ITRC_IOCTL, ITRC_ENTER, 2, cmd, arg );
@@ -2206,9 +2210,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
* for masking). Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- save_flags(flags);cli();
+ WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
cprev = pCh->icount; /* note the counters on entry */
- restore_flags(flags);
+ WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
init_waitqueue_entry(&wait, current);
@@ -2228,9 +2232,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
rc = -ERESTARTSYS;
break;
}
- save_flags(flags);cli();
+ WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
cnow = pCh->icount; /* atomic copy */
- restore_flags(flags);
+ WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
rc = -EIO; /* no change => rc */
@@ -2268,9 +2272,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
case TIOCGICOUNT:
ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
- save_flags(flags);cli();
+ WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
cnow = pCh->icount;
- restore_flags(flags);
+ WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
p_cuser = argp;
rc = put_user(cnow.cts, &p_cuser->cts);
rc = put_user(cnow.dsr, &p_cuser->dsr);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 1f56b4cf0f5..0097f06fa67 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -57,6 +57,7 @@ static int initialized = 0;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_ipmi_root = NULL;
+EXPORT_SYMBOL(proc_ipmi_root);
#endif /* CONFIG_PROC_FS */
#define MAX_EVENTS_IN_QUEUE 25
@@ -787,7 +788,6 @@ int ipmi_destroy_user(ipmi_user_t user)
int i;
unsigned long flags;
struct cmd_rcvr *rcvr;
- struct list_head *entry1, *entry2;
struct cmd_rcvr *rcvrs = NULL;
user->valid = 1;
@@ -812,8 +812,7 @@ int ipmi_destroy_user(ipmi_user_t user)
* synchronize_rcu()) then free everything in that list.
*/
down(&intf->cmd_rcvrs_lock);
- list_for_each_safe_rcu(entry1, entry2, &intf->cmd_rcvrs) {
- rcvr = list_entry(entry1, struct cmd_rcvr, link);
+ list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
if (rcvr->user == user) {
list_del_rcu(&rcvr->link);
rcvr->next = rcvrs;
@@ -3297,6 +3296,5 @@ EXPORT_SYMBOL(ipmi_get_my_address);
EXPORT_SYMBOL(ipmi_set_my_LUN);
EXPORT_SYMBOL(ipmi_get_my_LUN);
EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
-EXPORT_SYMBOL(proc_ipmi_root);
EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
EXPORT_SYMBOL(ipmi_free_recv_msg);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index e053eade036..49c09ae004b 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -612,11 +612,14 @@ static int ipmi_poweroff_init (void)
#endif
rv = ipmi_smi_watcher_register(&smi_watcher);
+
+#ifdef CONFIG_PROC_FS
if (rv) {
unregister_sysctl_table(ipmi_table_header);
printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
goto out_err;
}
+#endif
out_err:
return rv;
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 1bbf507adda..e9ebabaf8cb 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -20,7 +20,7 @@
* 3/9/99 sameer Added support for ISI4616 cards.
*
* 16/9/99 sameer We do not force RTS low anymore.
- * This is to prevent the firmware
+ * This is to prevent the firmware
* from getting confused.
*
* 26/10/99 sameer Cosmetic changes:The driver now
@@ -31,28 +31,28 @@
*
* 10/5/00 sameer Fixed isicom_shutdown_board()
* to not lower DTR on all the ports
- * when the last port on the card is
+ * when the last port on the card is
* closed.
*
* 10/5/00 sameer Signal mask setup command added
- * to isicom_setup_port and
+ * to isicom_setup_port and
* isicom_shutdown_port.
*
* 24/5/00 sameer The driver is now SMP aware.
- *
- *
+ *
+ *
* 27/11/00 Vinayak P Risbud Fixed the Driver Crash Problem
- *
- *
+ *
+ *
* 03/01/01 anil .s Added support for resetting the
* internal modems on ISI cards.
*
* 08/02/01 anil .s Upgraded the driver for kernel
* 2.4.x
*
- * 11/04/01 Kevin Fixed firmware load problem with
+ * 11/04/01 Kevin Fixed firmware load problem with
* ISIHP-4X card
- *
+ *
* 30/04/01 anil .s Fixed the remote login through
* ISI port problem. Now the link
* does not go down before password
@@ -62,9 +62,9 @@
* among ISI-PCI cards.
*
* 03/05/01 anil .s Added support to display the version
- * info during insmod as well as module
+ * info during insmod as well as module
* listing by lsmod.
- *
+ *
* 10/05/01 anil .s Done the modifications to the source
* file and Install script so that the
* same installation can be used for
@@ -73,19 +73,19 @@
* 06/06/01 anil .s Now we drop both dtr and rts during
* shutdown_port as well as raise them
* during isicom_config_port.
- *
+ *
* 09/06/01 acme@conectiva.com.br use capable, not suser, do
* restore_flags on failure in
* isicom_send_break, verify put_user
* result
*
- * 11/02/03 ranjeeth Added support for 230 Kbps and 460 Kbps
- * Baud index extended to 21
- *
- * 20/03/03 ranjeeth Made to work for Linux Advanced server.
- * Taken care of license warning.
- *
- * 10/12/03 Ravindra Made to work for Fedora Core 1 of
+ * 11/02/03 ranjeeth Added support for 230 Kbps and 460 Kbps
+ * Baud index extended to 21
+ *
+ * 20/03/03 ranjeeth Made to work for Linux Advanced server.
+ * Taken care of license warning.
+ *
+ * 10/12/03 Ravindra Made to work for Fedora Core 1 of
* Red Hat Distribution
*
* 06/01/05 Alan Cox Merged the ISI and base kernel strands
@@ -93,10 +93,10 @@
*
* ***********************************************************
*
- * To use this driver you also need the support package. You
+ * To use this driver you also need the support package. You
* can find this in RPM format on
* ftp://ftp.linux.org.uk/pub/linux/alan
- *
+ *
* You can find the original tools for this direct from Multitech
* ftp://ftp.multitech.com/ISI-Cards/
*
@@ -107,20 +107,20 @@
* Omit those entries for boards you don't have installed.
*
* TODO
- * Hotplug
* Merge testing
* 64-bit verification
*/
#include <linux/module.h>
+#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/tty.h>
+#include <linux/tty_flip.h>
#include <linux/termios.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/mm.h>
-#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/delay.h>
@@ -134,50 +134,62 @@
#include <linux/isicom.h>
+#define InterruptTheCard(base) outw(0, (base) + 0xc)
+#define ClearInterrupt(base) inw((base) + 0x0a)
+
+#ifdef DEBUG
+#define pr_dbg(str...) printk(KERN_DEBUG "ISICOM: " str)
+#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
+#else
+#define pr_dbg(str...) do { } while (0)
+#define isicom_paranoia_check(a, b, c) 0
+#endif
+
+static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit isicom_remove(struct pci_dev *);
+
static struct pci_device_id isicom_pci_tbl[] = {
- { VENDOR_ID, 0x2028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { VENDOR_ID, 0x2051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { VENDOR_ID, 0x2052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { VENDOR_ID, 0x2053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { VENDOR_ID, 0x2054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { VENDOR_ID, 0x2055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { VENDOR_ID, 0x2056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { VENDOR_ID, 0x2057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { VENDOR_ID, 0x2058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_DEVICE(VENDOR_ID, 0x2028) },
+ { PCI_DEVICE(VENDOR_ID, 0x2051) },
+ { PCI_DEVICE(VENDOR_ID, 0x2052) },
+ { PCI_DEVICE(VENDOR_ID, 0x2053) },
+ { PCI_DEVICE(VENDOR_ID, 0x2054) },
+ { PCI_DEVICE(VENDOR_ID, 0x2055) },
+ { PCI_DEVICE(VENDOR_ID, 0x2056) },
+ { PCI_DEVICE(VENDOR_ID, 0x2057) },
+ { PCI_DEVICE(VENDOR_ID, 0x2058) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, isicom_pci_tbl);
+static struct pci_driver isicom_driver = {
+ .name = "isicom",
+ .id_table = isicom_pci_tbl,
+ .probe = isicom_probe,
+ .remove = __devexit_p(isicom_remove)
+};
+
static int prev_card = 3; /* start servicing isi_card[0] */
static struct tty_driver *isicom_normal;
static struct timer_list tx;
static char re_schedule = 1;
-#ifdef ISICOM_DEBUG
-static unsigned long tx_count = 0;
-#endif
-
-static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
static void isicom_tx(unsigned long _data);
-static void isicom_start(struct tty_struct * tty);
-
-static unsigned char * tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
+static void isicom_start(struct tty_struct *tty);
/* baud index mappings from linux defns to isi */
static signed char linuxb_to_isib[] = {
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17,
- 18, 19
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19
};
struct isi_board {
- unsigned short base;
+ unsigned long base;
unsigned char irq;
unsigned char port_count;
unsigned short status;
- unsigned short port_status; /* each bit represents a single port */
+ unsigned short port_status; /* each bit for each port */
unsigned short shift_count;
struct isi_port * ports;
signed char count;
@@ -192,9 +204,9 @@ struct isi_port {
int count;
int blocked_open;
int close_delay;
- unsigned short channel;
- unsigned short status;
- unsigned short closing_wait;
+ u16 channel;
+ u16 status;
+ u16 closing_wait;
struct isi_board * card;
struct tty_struct * tty;
wait_queue_head_t close_wait;
@@ -215,35 +227,37 @@ static struct isi_port isi_ports[PORT_COUNT];
* the kernel lock for the card and have the card in a position that
* it wants to talk.
*/
-
+
static int lock_card(struct isi_board *card)
{
char retries;
- unsigned short base = card->base;
+ unsigned long base = card->base;
for (retries = 0; retries < 100; retries++) {
spin_lock_irqsave(&card->card_lock, card->flags);
if (inw(base + 0xe) & 0x1) {
- return 1;
+ return 1;
} else {
spin_unlock_irqrestore(&card->card_lock, card->flags);
udelay(1000); /* 1ms */
}
}
- printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%x)\n", card->base);
+ printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n",
+ card->base);
+
return 0; /* Failed to aquire the card! */
}
static int lock_card_at_interrupt(struct isi_board *card)
{
unsigned char retries;
- unsigned short base = card->base;
+ unsigned long base = card->base;
for (retries = 0; retries < 200; retries++) {
spin_lock_irqsave(&card->card_lock, card->flags);
if (inw(base + 0xe) & 0x1)
- return 1;
+ return 1;
else
spin_unlock_irqrestore(&card->card_lock, card->flags);
}
@@ -259,373 +273,141 @@ static void unlock_card(struct isi_board *card)
/*
* ISI Card specific ops ...
*/
-
-static void raise_dtr(struct isi_port * port)
+
+static void raise_dtr(struct isi_port *port)
{
- struct isi_board * card = port->card;
- unsigned short base = card->base;
- unsigned char channel = port->channel;
+ struct isi_board *card = port->card;
+ unsigned long base = card->base;
+ u16 channel = port->channel;
if (!lock_card(card))
return;
- outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0504, base);
InterruptTheCard(base);
port->status |= ISI_DTR;
unlock_card(card);
}
-static inline void drop_dtr(struct isi_port * port)
-{
- struct isi_board * card = port->card;
- unsigned short base = card->base;
- unsigned char channel = port->channel;
+static inline void drop_dtr(struct isi_port *port)
+{
+ struct isi_board *card = port->card;
+ unsigned long base = card->base;
+ u16 channel = port->channel;
if (!lock_card(card))
return;
- outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0404, base);
- InterruptTheCard(base);
+ InterruptTheCard(base);
port->status &= ~ISI_DTR;
unlock_card(card);
}
-static inline void raise_rts(struct isi_port * port)
+static inline void raise_rts(struct isi_port *port)
{
- struct isi_board * card = port->card;
- unsigned short base = card->base;
- unsigned char channel = port->channel;
+ struct isi_board *card = port->card;
+ unsigned long base = card->base;
+ u16 channel = port->channel;
if (!lock_card(card))
return;
- outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0a04, base);
- InterruptTheCard(base);
+ InterruptTheCard(base);
port->status |= ISI_RTS;
unlock_card(card);
}
-static inline void drop_rts(struct isi_port * port)
+static inline void drop_rts(struct isi_port *port)
{
- struct isi_board * card = port->card;
- unsigned short base = card->base;
- unsigned char channel = port->channel;
+ struct isi_board *card = port->card;
+ unsigned long base = card->base;
+ u16 channel = port->channel;
if (!lock_card(card))
return;
- outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0804, base);
- InterruptTheCard(base);
+ InterruptTheCard(base);
port->status &= ~ISI_RTS;
unlock_card(card);
}
-static inline void raise_dtr_rts(struct isi_port * port)
+static inline void raise_dtr_rts(struct isi_port *port)
{
- struct isi_board * card = port->card;
- unsigned short base = card->base;
- unsigned char channel = port->channel;
+ struct isi_board *card = port->card;
+ unsigned long base = card->base;
+ u16 channel = port->channel;
if (!lock_card(card))
return;
- outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0f04, base);
InterruptTheCard(base);
port->status |= (ISI_DTR | ISI_RTS);
unlock_card(card);
}
-static void drop_dtr_rts(struct isi_port * port)
+static void drop_dtr_rts(struct isi_port *port)
{
- struct isi_board * card = port->card;
- unsigned short base = card->base;
- unsigned char channel = port->channel;
+ struct isi_board *card = port->card;
+ unsigned long base = card->base;
+ u16 channel = port->channel;
if (!lock_card(card))
return;
- outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0c04, base);
- InterruptTheCard(base);
+ InterruptTheCard(base);
port->status &= ~(ISI_RTS | ISI_DTR);
unlock_card(card);
}
-static inline void kill_queue(struct isi_port * port, short queue)
+static inline void kill_queue(struct isi_port *port, short queue)
{
- struct isi_board * card = port->card;
- unsigned short base = card->base;
- unsigned char channel = port->channel;
+ struct isi_board *card = port->card;
+ unsigned long base = card->base;
+ u16 channel = port->channel;
if (!lock_card(card))
return;
- outw(0x8000 | (channel << card->shift_count) | 0x02 , base);
+ outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw((queue << 8) | 0x06, base);
- InterruptTheCard(base);
+ InterruptTheCard(base);
unlock_card(card);
}
-
-/*
- * Firmware loader driver specific routines. This needs to mostly die
- * and be replaced with request_firmware.
- */
-
-static struct file_operations ISILoad_fops = {
- .owner = THIS_MODULE,
- .ioctl = ISILoad_ioctl,
-};
-
-static struct miscdevice isiloader_device = {
- ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops
-};
-
-
-static inline int WaitTillCardIsFree(unsigned short base)
-{
- unsigned long count=0;
- while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000));
- if (inw(base+0xe)&0x1)
- return 0;
- else
- return 1;
-}
-
-static int ISILoad_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- unsigned int card, i, j, signature, status, portcount = 0;
- unsigned long t;
- unsigned short word_count, base;
- bin_frame frame;
- void __user *argp = (void __user *)arg;
- /* exec_record exec_rec; */
-
- if(get_user(card, (int __user *)argp))
- return -EFAULT;
-
- if(card < 0 || card >= BOARD_COUNT)
- return -ENXIO;
-
- base=isi_card[card].base;
-
- if(base==0)
- return -ENXIO; /* disabled or not used */
-
- switch(cmd) {
- case MIOCTL_RESET_CARD:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%x ",card+1,base);
-
- inw(base+0x8);
-
- for(t=jiffies+HZ/100;time_before(jiffies, t););
-
- outw(0,base+0x8); /* Reset */
-
- for(j=1;j<=3;j++) {
- for(t=jiffies+HZ;time_before(jiffies, t););
- printk(".");
- }
- signature=(inw(base+0x4)) & 0xff;
- if (isi_card[card].isa) {
-
- if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
-#ifdef ISICOM_DEBUG
- printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
-#endif
- printk("\nISILoad:ISA Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
- return -EIO;
- }
- }
- else {
- portcount = inw(base+0x2);
- if (!(inw(base+0xe) & 0x1) || ((portcount!=0) && (portcount!=4) && (portcount!=8))) {
-#ifdef ISICOM_DEBUG
- printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
-#endif
- printk("\nISILoad:PCI Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
- return -EIO;
- }
- }
- switch(signature) {
- case 0xa5:
- case 0xbb:
- case 0xdd:
- if (isi_card[card].isa)
- isi_card[card].port_count = 8;
- else {
- if (portcount == 4)
- isi_card[card].port_count = 4;
- else
- isi_card[card].port_count = 8;
- }
- isi_card[card].shift_count = 12;
- break;
-
- case 0xcc: isi_card[card].port_count = 16;
- isi_card[card].shift_count = 11;
- break;
-
- default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
-#ifdef ISICOM_DEBUG
- printk("Sig=0x%x\n",signature);
-#endif
- return -EIO;
- }
- printk("-Done\n");
- return put_user(signature,(unsigned __user *)argp);
-
- case MIOCTL_LOAD_FIRMWARE:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if(copy_from_user(&frame, argp, sizeof(bin_frame)))
- return -EFAULT;
-
- if (WaitTillCardIsFree(base))
- return -EIO;
-
- outw(0xf0,base); /* start upload sequence */
- outw(0x00,base);
- outw((frame.addr), base);/* lsb of adderess */
-
- word_count=(frame.count >> 1) + frame.count % 2;
- outw(word_count, base);
- InterruptTheCard(base);
-
- for(i=0;i<=0x2f;i++); /* a wee bit of delay */
-
- if (WaitTillCardIsFree(base))
- return -EIO;
-
- if ((status=inw(base+0x4))!=0) {
- printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
- card+1, frame.addr, frame.count, status);
- return -EIO;
- }
- outsw(base, (void *) frame.bin_data, word_count);
-
- InterruptTheCard(base);
-
- for(i=0;i<=0x0f;i++); /* another wee bit of delay */
-
- if (WaitTillCardIsFree(base))
- return -EIO;
-
- if ((status=inw(base+0x4))!=0) {
- printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status);
- return -EIO;
- }
- return 0;
-
- case MIOCTL_READ_FIRMWARE:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if(copy_from_user(&frame, argp, sizeof(bin_header)))
- return -EFAULT;
-
- if (WaitTillCardIsFree(base))
- return -EIO;
-
- outw(0xf1,base); /* start download sequence */
- outw(0x00,base);
- outw((frame.addr), base);/* lsb of adderess */
-
- word_count=(frame.count >> 1) + frame.count % 2;
- outw(word_count+1, base);
- InterruptTheCard(base);
-
- for(i=0;i<=0xf;i++); /* a wee bit of delay */
-
- if (WaitTillCardIsFree(base))
- return -EIO;
-
- if ((status=inw(base+0x4))!=0) {
- printk(KERN_WARNING "ISILoad:Card%d rejected verify header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
- card+1, frame.addr, frame.count, status);
- return -EIO;
- }
-
- inw(base);
- insw(base, frame.bin_data, word_count);
- InterruptTheCard(base);
-
- for(i=0;i<=0x0f;i++); /* another wee bit of delay */
-
- if (WaitTillCardIsFree(base))
- return -EIO;
-
- if ((status=inw(base+0x4))!=0) {
- printk(KERN_ERR "ISILoad:Card%d verify got out of sync.Card Status:0x%x\n",card+1, status);
- return -EIO;
- }
-
- if(copy_to_user(argp, &frame, sizeof(bin_frame)))
- return -EFAULT;
- return 0;
-
- case MIOCTL_XFER_CTRL:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (WaitTillCardIsFree(base))
- return -EIO;
-
- outw(0xf2, base);
- outw(0x800, base);
- outw(0x0, base);
- outw(0x0, base);
- InterruptTheCard(base);
- outw(0x0, base+0x4); /* for ISI4608 cards */
-
- isi_card[card].status |= FIRMWARE_LOADED;
- return 0;
-
- default:
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISILoad: Received Ioctl cmd 0x%x.\n", cmd);
-#endif
- return -ENOIOCTLCMD;
-
- }
-
-}
-
-
/*
* ISICOM Driver specific routines ...
*
*/
-
-static inline int isicom_paranoia_check(struct isi_port const * port, char *name,
- const char * routine)
+
+static inline int __isicom_paranoia_check(struct isi_port const *port,
+ char *name, const char *routine)
{
-#ifdef ISICOM_DEBUG
- static const char * badmagic =
- KERN_WARNING "ISICOM: Warning: bad isicom magic for dev %s in %s.\n";
- static const char * badport =
- KERN_WARNING "ISICOM: Warning: NULL isicom port for dev %s in %s.\n";
if (!port) {
- printk(badport, name, routine);
+ printk(KERN_WARNING "ISICOM: Warning: bad isicom magic for "
+ "dev %s in %s.\n", name, routine);
return 1;
}
if (port->magic != ISICOM_MAGIC) {
- printk(badmagic, name, routine);
+ printk(KERN_WARNING "ISICOM: Warning: NULL isicom port for "
+ "dev %s in %s.\n", name, routine);
return 1;
- }
-#endif
+ }
+
return 0;
}
-
+
/*
- * Transmitter.
+ * Transmitter.
*
* We shovel data into the card buffers on a regular basis. The card
* will do the rest of the work for us.
@@ -635,25 +417,21 @@ static void isicom_tx(unsigned long _data)
{
short count = (BOARD_COUNT-1), card, base;
short txcount, wrd, residue, word_count, cnt;
- struct isi_port * port;
- struct tty_struct * tty;
-
-#ifdef ISICOM_DEBUG
- ++tx_count;
-#endif
-
+ struct isi_port *port;
+ struct tty_struct *tty;
+
/* find next active board */
card = (prev_card + 1) & 0x0003;
while(count-- > 0) {
- if (isi_card[card].status & BOARD_ACTIVE)
+ if (isi_card[card].status & BOARD_ACTIVE)
break;
- card = (card + 1) & 0x0003;
+ card = (card + 1) & 0x0003;
}
if (!(isi_card[card].status & BOARD_ACTIVE))
goto sched_again;
-
+
prev_card = card;
-
+
count = isi_card[card].port_count;
port = isi_card[card].ports;
base = isi_card[card].base;
@@ -662,18 +440,18 @@ static void isicom_tx(unsigned long _data)
continue;
/* port not active or tx disabled to force flow control */
if (!(port->flags & ASYNC_INITIALIZED) ||
- !(port->status & ISI_TXOK))
+ !(port->status & ISI_TXOK))
unlock_card(&isi_card[card]);
continue;
-
+
tty = port->tty;
-
-
- if(tty == NULL) {
+
+
+ if (tty == NULL) {
unlock_card(&isi_card[card]);
continue;
}
-
+
txcount = min_t(short, TX_SIZE, port->xmit_cnt);
if (txcount <= 0 || tty->stopped || tty->hw_stopped) {
unlock_card(&isi_card[card]);
@@ -681,44 +459,45 @@ static void isicom_tx(unsigned long _data)
}
if (!(inw(base + 0x02) & (1 << port->channel))) {
unlock_card(&isi_card[card]);
- continue;
+ continue;
}
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: txing %d bytes, port%d.\n",
- txcount, port->channel+1);
-#endif
- outw((port->channel << isi_card[card].shift_count) | txcount
- , base);
+ pr_dbg("txing %d bytes, port%d.\n", txcount,
+ port->channel + 1);
+ outw((port->channel << isi_card[card].shift_count) | txcount,
+ base);
residue = NO;
- wrd = 0;
+ wrd = 0;
while (1) {
- cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE - port->xmit_tail));
+ cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
+ - port->xmit_tail));
if (residue == YES) {
residue = NO;
if (cnt > 0) {
- wrd |= (port->xmit_buf[port->xmit_tail] << 8);
- port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+ wrd |= (port->xmit_buf[port->xmit_tail]
+ << 8);
+ port->xmit_tail = (port->xmit_tail + 1)
+ & (SERIAL_XMIT_SIZE - 1);
port->xmit_cnt--;
txcount--;
cnt--;
- outw(wrd, base);
- }
- else {
+ outw(wrd, base);
+ } else {
outw(wrd, base);
break;
}
- }
+ }
if (cnt <= 0) break;
word_count = cnt >> 1;
- outsw(base, port->xmit_buf+port->xmit_tail, word_count);
- port->xmit_tail = (port->xmit_tail + (word_count << 1)) &
- (SERIAL_XMIT_SIZE - 1);
+ outsw(base, port->xmit_buf+port->xmit_tail,word_count);
+ port->xmit_tail = (port->xmit_tail
+ + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
txcount -= (word_count << 1);
port->xmit_cnt -= (word_count << 1);
if (cnt & 0x0001) {
residue = YES;
wrd = port->xmit_buf[port->xmit_tail];
- port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+ port->xmit_tail = (port->xmit_tail + 1)
+ & (SERIAL_XMIT_SIZE - 1);
port->xmit_cnt--;
txcount--;
}
@@ -730,81 +509,82 @@ static void isicom_tx(unsigned long _data)
if (port->xmit_cnt <= WAKEUP_CHARS)
schedule_work(&port->bh_tqueue);
unlock_card(&isi_card[card]);
- }
+ }
+
+ /* schedule another tx for hopefully in about 10ms */
+sched_again:
+ if (!re_schedule) {
+ re_schedule = 2;
+ return;
+ }
- /* schedule another tx for hopefully in about 10ms */
-sched_again:
- if (!re_schedule)
- return;
init_timer(&tx);
tx.expires = jiffies + HZ/100;
tx.data = 0;
tx.function = isicom_tx;
add_timer(&tx);
-
- return;
-}
-
+
+ return;
+}
+
/* Interrupt handlers */
-
-static void isicom_bottomhalf(void * data)
+
+static void isicom_bottomhalf(void *data)
{
- struct isi_port * port = (struct isi_port *) data;
- struct tty_struct * tty = port->tty;
-
+ struct isi_port *port = (struct isi_port *) data;
+ struct tty_struct *tty = port->tty;
+
if (!tty)
return;
- tty_wakeup(tty);
+ tty_wakeup(tty);
wake_up_interruptible(&tty->write_wait);
-}
-
+}
+
/*
- * Main interrupt handler routine
+ * Main interrupt handler routine
*/
-
-static irqreturn_t isicom_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+
+static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct isi_board * card;
- struct isi_port * port;
- struct tty_struct * tty;
- unsigned short base, header, word_count, count;
- unsigned char channel;
+ struct isi_board *card = dev_id;
+ struct isi_port *port;
+ struct tty_struct *tty;
+ unsigned long base;
+ u16 header, word_count, count, channel;
short byte_count;
-
- card = (struct isi_board *) dev_id;
+ unsigned char *rp;
if (!card || !(card->status & FIRMWARE_LOADED))
return IRQ_NONE;
-
+
base = card->base;
spin_lock(&card->card_lock);
-
+
if (card->isa == NO) {
/*
- * disable any interrupts from the PCI card and lower the
- * interrupt line
+ * disable any interrupts from the PCI card and lower the
+ * interrupt line
*/
outw(0x8000, base+0x04);
ClearInterrupt(base);
}
-
+
inw(base); /* get the dummy word out */
header = inw(base);
channel = (header & 0x7800) >> card->shift_count;
byte_count = header & 0xff;
if (channel + 1 > card->port_count) {
- printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n",
- base, channel+1);
+ printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): "
+ "%d(channel) > port_count.\n", base, channel+1);
if (card->isa)
ClearInterrupt(base);
else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
spin_unlock(&card->card_lock);
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
}
port = card->ports + channel;
if (!(port->flags & ASYNC_INITIALIZED)) {
@@ -813,8 +593,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id,
else
outw(0x0000, base+0x04); /* enable interrupts */
return IRQ_HANDLED;
- }
-
+ }
+
tty = port->tty;
if (tty == NULL) {
word_count = byte_count >> 1;
@@ -831,224 +611,204 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id,
spin_unlock(&card->card_lock);
return IRQ_HANDLED;
}
-
+
if (header & 0x8000) { /* Status Packet */
header = inw(base);
switch(header & 0xff) {
- case 0: /* Change in EIA signals */
-
- if (port->flags & ASYNC_CHECK_CD) {
- if (port->status & ISI_DCD) {
- if (!(header & ISI_DCD)) {
- /* Carrier has been lost */
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: interrupt: DCD->low.\n");
-#endif
- port->status &= ~ISI_DCD;
- schedule_work(&port->hangup_tq);
- }
- }
- else {
- if (header & ISI_DCD) {
- /* Carrier has been detected */
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: interrupt: DCD->high.\n");
-#endif
- port->status |= ISI_DCD;
- wake_up_interruptible(&port->open_wait);
- }
- }
- }
- else {
- if (header & ISI_DCD)
- port->status |= ISI_DCD;
- else
+ case 0: /* Change in EIA signals */
+ if (port->flags & ASYNC_CHECK_CD) {
+ if (port->status & ISI_DCD) {
+ if (!(header & ISI_DCD)) {
+ /* Carrier has been lost */
+ pr_dbg("interrupt: DCD->low.\n"
+ );
port->status &= ~ISI_DCD;
- }
-
- if (port->flags & ASYNC_CTS_FLOW) {
- if (port->tty->hw_stopped) {
- if (header & ISI_CTS) {
- port->tty->hw_stopped = 0;
- /* start tx ing */
- port->status |= (ISI_TXOK | ISI_CTS);
- schedule_work(&port->bh_tqueue);
- }
- }
- else {
- if (!(header & ISI_CTS)) {
- port->tty->hw_stopped = 1;
- /* stop tx ing */
- port->status &= ~(ISI_TXOK | ISI_CTS);
- }
+ schedule_work(&port->hangup_tq);
}
+ } else if (header & ISI_DCD) {
+ /* Carrier has been detected */
+ pr_dbg("interrupt: DCD->high.\n");
+ port->status |= ISI_DCD;
+ wake_up_interruptible(&port->open_wait);
}
- else {
- if (header & ISI_CTS)
- port->status |= ISI_CTS;
- else
- port->status &= ~ISI_CTS;
- }
-
- if (header & ISI_DSR)
- port->status |= ISI_DSR;
+ } else {
+ if (header & ISI_DCD)
+ port->status |= ISI_DCD;
else
- port->status &= ~ISI_DSR;
-
- if (header & ISI_RI)
- port->status |= ISI_RI;
+ port->status &= ~ISI_DCD;
+ }
+
+ if (port->flags & ASYNC_CTS_FLOW) {
+ if (port->tty->hw_stopped) {
+ if (header & ISI_CTS) {
+ port->tty->hw_stopped = 0;
+ /* start tx ing */
+ port->status |= (ISI_TXOK
+ | ISI_CTS);
+ schedule_work(&port->bh_tqueue);
+ }
+ } else if (!(header & ISI_CTS)) {
+ port->tty->hw_stopped = 1;
+ /* stop tx ing */
+ port->status &= ~(ISI_TXOK | ISI_CTS);
+ }
+ } else {
+ if (header & ISI_CTS)
+ port->status |= ISI_CTS;
else
- port->status &= ~ISI_RI;
-
- break;
-
- case 1: /* Received Break !!! */
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- break;
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- *tty->flip.char_buf_ptr++ = 0;
- tty->flip.count++;
- if (port->flags & ASYNC_SAK)
- do_SAK(tty);
- schedule_delayed_work(&tty->flip.work, 1);
- break;
-
- case 2: /* Statistics */
- printk(KERN_DEBUG "ISICOM: isicom_interrupt: stats!!!.\n");
- break;
-
- default:
- printk(KERN_WARNING "ISICOM: Intr: Unknown code in status packet.\n");
- break;
- }
- }
- else { /* Data Packet */
- count = min_t(unsigned short, byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count));
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: Intr: Can rx %d of %d bytes.\n",
- count, byte_count);
-#endif
+ port->status &= ~ISI_CTS;
+ }
+
+ if (header & ISI_DSR)
+ port->status |= ISI_DSR;
+ else
+ port->status &= ~ISI_DSR;
+
+ if (header & ISI_RI)
+ port->status |= ISI_RI;
+ else
+ port->status &= ~ISI_RI;
+
+ break;
+
+ case 1: /* Received Break !!! */
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
+ if (port->flags & ASYNC_SAK)
+ do_SAK(tty);
+ tty_flip_buffer_push(tty);
+ break;
+
+ case 2: /* Statistics */
+ pr_dbg("isicom_interrupt: stats!!!.\n");
+ break;
+
+ default:
+ pr_dbg("Intr: Unknown code in status packet.\n");
+ break;
+ }
+ } else { /* Data Packet */
+
+ count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
+ pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count);
word_count = count >> 1;
- insw(base, tty->flip.char_buf_ptr, word_count);
- tty->flip.char_buf_ptr += (word_count << 1);
+ insw(base, rp, word_count);
byte_count -= (word_count << 1);
if (count & 0x0001) {
- *tty->flip.char_buf_ptr++ = (char)(inw(base) & 0xff);
+ tty_insert_flip_char(tty, inw(base) & 0xff,
+ TTY_NORMAL);
byte_count -= 2;
- }
- memset(tty->flip.flag_buf_ptr, 0, count);
- tty->flip.flag_buf_ptr += count;
- tty->flip.count += count;
-
+ }
if (byte_count > 0) {
- printk(KERN_DEBUG "ISICOM: Intr(0x%x:%d): Flip buffer overflow! dropping bytes...\n",
- base, channel+1);
+ pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
+ "bytes...\n", base, channel + 1);
while(byte_count > 0) { /* drain out unread xtra data */
inw(base);
byte_count -= 2;
}
}
- schedule_delayed_work(&tty->flip.work, 1);
+ tty_flip_buffer_push(tty);
}
if (card->isa == YES)
ClearInterrupt(base);
else
- outw(0x0000, base+0x04); /* enable interrupts */
+ outw(0x0000, base+0x04); /* enable interrupts */
+
return IRQ_HANDLED;
-}
+}
-static void isicom_config_port(struct isi_port * port)
+static void isicom_config_port(struct isi_port *port)
{
- struct isi_board * card = port->card;
- struct tty_struct * tty;
+ struct isi_board *card = port->card;
+ struct tty_struct *tty;
unsigned long baud;
- unsigned short channel_setup, base = card->base;
- unsigned short channel = port->channel, shift_count = card->shift_count;
+ unsigned long base = card->base;
+ u16 channel_setup, channel = port->channel,
+ shift_count = card->shift_count;
unsigned char flow_ctrl;
-
+
if (!(tty = port->tty) || !tty->termios)
return;
baud = C_BAUD(tty);
if (baud & CBAUDEX) {
baud &= ~CBAUDEX;
-
+
/* if CBAUDEX bit is on and the baud is set to either 50 or 75
* then the card is programmed for 57.6Kbps or 115Kbps
* respectively.
- */
-
+ */
+
if (baud < 1 || baud > 2)
port->tty->termios->c_cflag &= ~CBAUDEX;
else
baud += 15;
- }
+ }
if (baud == 15) {
-
- /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
+
+ /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
* by the set_serial_info ioctl ... this is done by
* the 'setserial' utility.
- */
-
+ */
+
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- baud++; /* 57.6 Kbps */
+ baud++; /* 57.6 Kbps */
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- baud +=2; /* 115 Kbps */
+ baud +=2; /* 115 Kbps */
}
if (linuxb_to_isib[baud] == -1) {
/* hang up */
- drop_dtr(port);
- return;
- }
- else
+ drop_dtr(port);
+ return;
+ }
+ else
raise_dtr(port);
-
+
if (lock_card(card)) {
outw(0x8000 | (channel << shift_count) |0x03, base);
outw(linuxb_to_isib[baud] << 8 | 0x03, base);
channel_setup = 0;
switch(C_CSIZE(tty)) {
- case CS5:
- channel_setup |= ISICOM_CS5;
- break;
- case CS6:
- channel_setup |= ISICOM_CS6;
- break;
- case CS7:
- channel_setup |= ISICOM_CS7;
- break;
- case CS8:
- channel_setup |= ISICOM_CS8;
- break;
+ case CS5:
+ channel_setup |= ISICOM_CS5;
+ break;
+ case CS6:
+ channel_setup |= ISICOM_CS6;
+ break;
+ case CS7:
+ channel_setup |= ISICOM_CS7;
+ break;
+ case CS8:
+ channel_setup |= ISICOM_CS8;
+ break;
}
-
+
if (C_CSTOPB(tty))
channel_setup |= ISICOM_2SB;
if (C_PARENB(tty)) {
channel_setup |= ISICOM_EVPAR;
if (C_PARODD(tty))
- channel_setup |= ISICOM_ODPAR;
+ channel_setup |= ISICOM_ODPAR;
}
- outw(channel_setup, base);
+ outw(channel_setup, base);
InterruptTheCard(base);
- unlock_card(card);
- }
+ unlock_card(card);
+ }
if (C_CLOCAL(tty))
port->flags &= ~ASYNC_CHECK_CD;
else
- port->flags |= ASYNC_CHECK_CD;
-
+ port->flags |= ASYNC_CHECK_CD;
+
/* flow control settings ...*/
flow_ctrl = 0;
port->flags &= ~ASYNC_CTS_FLOW;
if (C_CRTSCTS(tty)) {
port->flags |= ASYNC_CTS_FLOW;
flow_ctrl |= ISICOM_CTSRTS;
- }
- if (I_IXON(tty))
+ }
+ if (I_IXON(tty))
flow_ctrl |= ISICOM_RESPOND_XONXOFF;
if (I_IXOFF(tty))
- flow_ctrl |= ISICOM_INITIATE_XONXOFF;
-
+ flow_ctrl |= ISICOM_INITIATE_XONXOFF;
+
if (lock_card(card)) {
outw(0x8000 | (channel << shift_count) |0x04, base);
outw(flow_ctrl << 8 | 0x05, base);
@@ -1056,22 +816,22 @@ static void isicom_config_port(struct isi_port * port)
InterruptTheCard(base);
unlock_card(card);
}
-
+
/* rx enabled -> enable port for rx on the card */
if (C_CREAD(tty)) {
card->port_status |= (1 << channel);
outw(card->port_status, base + 0x02);
}
}
-
-/* open et all */
-static inline void isicom_setup_board(struct isi_board * bp)
+/* open et all */
+
+static inline void isicom_setup_board(struct isi_board *bp)
{
int channel;
- struct isi_port * port;
+ struct isi_port *port;
unsigned long flags;
-
+
spin_lock_irqsave(&bp->card_lock, flags);
if (bp->status & BOARD_ACTIVE) {
spin_unlock_irqrestore(&bp->card_lock, flags);
@@ -1080,53 +840,54 @@ static inline void isicom_setup_board(struct isi_board * bp)
port = bp->ports;
bp->status |= BOARD_ACTIVE;
spin_unlock_irqrestore(&bp->card_lock, flags);
- for(channel = 0; channel < bp->port_count; channel++, port++)
+ for (channel = 0; channel < bp->port_count; channel++, port++)
drop_dtr_rts(port);
return;
}
-
-static int isicom_setup_port(struct isi_port * port)
+
+static int isicom_setup_port(struct isi_port *port)
{
- struct isi_board * card = port->card;
+ struct isi_board *card = port->card;
unsigned long flags;
-
+
if (port->flags & ASYNC_INITIALIZED) {
return 0;
}
if (!port->xmit_buf) {
unsigned long page;
-
+
if (!(page = get_zeroed_page(GFP_KERNEL)))
return -ENOMEM;
-
+
if (port->xmit_buf) {
free_page(page);
return -ERESTARTSYS;
}
- port->xmit_buf = (unsigned char *) page;
- }
+ port->xmit_buf = (unsigned char *) page;
+ }
spin_lock_irqsave(&card->card_lock, flags);
if (port->tty)
clear_bit(TTY_IO_ERROR, &port->tty->flags);
if (port->count == 1)
card->count++;
-
+
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-
+
/* discard any residual data */
kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX);
-
+
isicom_config_port(port);
port->flags |= ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
-
- return 0;
-}
-
-static int block_til_ready(struct tty_struct * tty, struct file * filp, struct isi_port * port)
+
+ return 0;
+}
+
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct isi_port *port)
{
- struct isi_board * card = port->card;
+ struct isi_board *card = port->card;
int do_clocal = 0, retval;
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
@@ -1134,30 +895,27 @@ static int block_til_ready(struct tty_struct * tty, struct file * filp, struct i
/* block if port is in the process of being closed */
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: block_til_ready: close in progress.\n");
-#endif
+ pr_dbg("block_til_ready: close in progress.\n");
interruptible_sleep_on(&port->close_wait);
if (port->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
else
return -ERESTARTSYS;
}
-
+
/* if non-blocking mode is set ... */
-
- if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: block_til_ready: non-block mode.\n");
-#endif
+
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ pr_dbg("block_til_ready: non-block mode.\n");
port->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
+ return 0;
+ }
+
if (C_CLOCAL(tty))
do_clocal = 1;
-
- /* block waiting for DCD to be asserted, and while
+
+ /* block waiting for DCD to be asserted, and while
callout dev is busy */
retval = 0;
add_wait_queue(&port->open_wait, &wait);
@@ -1167,27 +925,27 @@ static int block_til_ready(struct tty_struct * tty, struct file * filp, struct i
port->count--;
port->blocked_open++;
spin_unlock_irqrestore(&card->card_lock, flags);
-
+
while (1) {
raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+ if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
break;
- }
+ }
if (!(port->flags & ASYNC_CLOSING) &&
- (do_clocal || (port->status & ISI_DCD))) {
+ (do_clocal || (port->status & ISI_DCD))) {
break;
- }
+ }
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
- schedule();
+ schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
@@ -1201,11 +959,11 @@ static int block_til_ready(struct tty_struct * tty, struct file * filp, struct i
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
-
-static int isicom_open(struct tty_struct * tty, struct file * filp)
+
+static int isicom_open(struct tty_struct *tty, struct file *filp)
{
- struct isi_port * port;
- struct isi_board * card;
+ struct isi_port *port;
+ struct isi_board *card;
unsigned int line, board;
int error;
@@ -1214,20 +972,20 @@ static int isicom_open(struct tty_struct * tty, struct file * filp)
return -ENODEV;
board = BOARD(line);
card = &isi_card[board];
-
+
if (!(card->status & FIRMWARE_LOADED))
return -ENODEV;
-
+
/* open on a port greater than the port count for the card !!! */
if (line > ((board * 16) + card->port_count - 1))
return -ENODEV;
- port = &isi_ports[line];
+ port = &isi_ports[line];
if (isicom_paranoia_check(port, tty->name, "isicom_open"))
return -ENODEV;
-
- isicom_setup_board(card);
-
+
+ isicom_setup_board(card);
+
port->count++;
tty->driver_data = port;
port->tty = tty;
@@ -1236,12 +994,12 @@ static int isicom_open(struct tty_struct * tty, struct file * filp)
if ((error = block_til_ready(tty, filp, port))!=0)
return error;
- return 0;
+ return 0;
}
-
+
/* close et all */
-static inline void isicom_shutdown_board(struct isi_board * bp)
+static inline void isicom_shutdown_board(struct isi_board *bp)
{
unsigned long flags;
@@ -1252,15 +1010,15 @@ static inline void isicom_shutdown_board(struct isi_board * bp)
spin_unlock_irqrestore(&bp->card_lock, flags);
}
-static void isicom_shutdown_port(struct isi_port * port)
+static void isicom_shutdown_port(struct isi_port *port)
{
- struct isi_board * card = port->card;
- struct tty_struct * tty;
+ struct isi_board *card = port->card;
+ struct tty_struct *tty;
unsigned long flags;
-
+
tty = port->tty;
- spin_lock_irqsave(&card->card_lock, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
if (!(port->flags & ASYNC_INITIALIZED)) {
spin_unlock_irqrestore(&card->card_lock, flags);
return;
@@ -1268,93 +1026,91 @@ static void isicom_shutdown_port(struct isi_port * port)
if (port->xmit_buf) {
free_page((unsigned long) port->xmit_buf);
port->xmit_buf = NULL;
- }
+ }
port->flags &= ~ASYNC_INITIALIZED;
/* 3rd October 2000 : Vinayak P Risbud */
port->tty = NULL;
spin_unlock_irqrestore(&card->card_lock, flags);
-
+
/*Fix done by Anil .S on 30-04-2001
remote login through isi port has dtr toggle problem
due to which the carrier drops before the password prompt
- appears on the remote end. Now we drop the dtr only if the
+ appears on the remote end. Now we drop the dtr only if the
HUPCL(Hangup on close) flag is set for the tty*/
-
- if (C_HUPCL(tty))
+
+ if (C_HUPCL(tty))
/* drop dtr on this port */
drop_dtr(port);
-
- /* any other port uninits */
+
+ /* any other port uninits */
if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
-
+
if (--card->count < 0) {
- printk(KERN_DEBUG "ISICOM: isicom_shutdown_port: bad board(0x%x) count %d.\n",
+ pr_dbg("isicom_shutdown_port: bad board(0x%lx) count %d.\n",
card->base, card->count);
- card->count = 0;
+ card->count = 0;
}
-
- /* last port was closed , shutdown that boad too */
- if(C_HUPCL(tty)) {
+
+ /* last port was closed, shutdown that boad too */
+ if (C_HUPCL(tty)) {
if (!card->count)
isicom_shutdown_board(card);
}
}
-static void isicom_close(struct tty_struct * tty, struct file * filp)
+static void isicom_close(struct tty_struct *tty, struct file *filp)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
- struct isi_board * card = port->card;
+ struct isi_port *port = tty->driver_data;
+ struct isi_board *card = port->card;
unsigned long flags;
-
+
if (!port)
return;
if (isicom_paranoia_check(port, tty->name, "isicom_close"))
return;
-
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: Close start!!!.\n");
-#endif
-
+
+ pr_dbg("Close start!!!.\n");
+
spin_lock_irqsave(&card->card_lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&card->card_lock, flags);
return;
}
-
+
if (tty->count == 1 && port->count != 1) {
- printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count"
- "tty->count = 1 port count = %d.\n",
+ printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
+ "count tty->count = 1 port count = %d.\n",
card->base, port->count);
port->count = 1;
}
if (--port->count < 0) {
- printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count for"
- "channel%d = %d", card->base, port->channel,
+ printk(KERN_WARNING "ISICOM:(0x%lx) isicom_close: bad port "
+ "count for channel%d = %d", card->base, port->channel,
port->count);
- port->count = 0;
+ port->count = 0;
}
-
+
if (port->count) {
spin_unlock_irqrestore(&card->card_lock, flags);
return;
- }
+ }
port->flags |= ASYNC_CLOSING;
tty->closing = 1;
spin_unlock_irqrestore(&card->card_lock, flags);
-
+
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait);
- /* indicate to the card that no more data can be received
+ /* indicate to the card that no more data can be received
on this port */
spin_lock_irqsave(&card->card_lock, flags);
- if (port->flags & ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED) {
card->port_status &= ~(1 << port->channel);
outw(card->port_status, card->base + 0x02);
- }
+ }
isicom_shutdown_port(port);
spin_unlock_irqrestore(&card->card_lock, flags);
-
+
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
@@ -1365,65 +1121,65 @@ static void isicom_close(struct tty_struct * tty, struct file * filp)
if (port->blocked_open) {
spin_unlock_irqrestore(&card->card_lock, flags);
if (port->close_delay) {
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: scheduling until time out.\n");
-#endif
- msleep_interruptible(jiffies_to_msecs(port->close_delay));
+ pr_dbg("scheduling until time out.\n");
+ msleep_interruptible(
+ jiffies_to_msecs(port->close_delay));
}
spin_lock_irqsave(&card->card_lock, flags);
wake_up_interruptible(&port->open_wait);
- }
+ }
port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
wake_up_interruptible(&port->close_wait);
spin_unlock_irqrestore(&card->card_lock, flags);
}
/* write et all */
-static int isicom_write(struct tty_struct * tty,
- const unsigned char * buf, int count)
+static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
+ int count)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
- struct isi_board * card = port->card;
+ struct isi_port *port = tty->driver_data;
+ struct isi_board *card = port->card;
unsigned long flags;
int cnt, total = 0;
if (isicom_paranoia_check(port, tty->name, "isicom_write"))
return 0;
-
- if (!tty || !port->xmit_buf || !tmp_buf)
+
+ if (!tty || !port->xmit_buf)
return 0;
-
+
spin_lock_irqsave(&card->card_lock, flags);
-
- while(1) {
- cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - port->xmit_head));
- if (cnt <= 0)
+
+ while(1) {
+ cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
+ - 1, SERIAL_XMIT_SIZE - port->xmit_head));
+ if (cnt <= 0)
break;
-
+
memcpy(port->xmit_buf + port->xmit_head, buf, cnt);
- port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1);
+ port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE
+ - 1);
port->xmit_cnt += cnt;
buf += cnt;
count -= cnt;
total += cnt;
- }
+ }
if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
port->status |= ISI_TXOK;
spin_unlock_irqrestore(&card->card_lock, flags);
- return total;
+ return total;
}
/* put_char et all */
-static void isicom_put_char(struct tty_struct * tty, unsigned char ch)
+static void isicom_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
- struct isi_board * card = port->card;
+ struct isi_port *port = tty->driver_data;
+ struct isi_board *card = port->card;
unsigned long flags;
-
+
if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
return;
-
+
if (!tty || !port->xmit_buf)
return;
@@ -1432,7 +1188,7 @@ static void isicom_put_char(struct tty_struct * tty, unsigned char ch)
spin_unlock_irqrestore(&card->card_lock, flags);
return;
}
-
+
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
port->xmit_cnt++;
@@ -1440,30 +1196,31 @@ static void isicom_put_char(struct tty_struct * tty, unsigned char ch)
}
/* flush_chars et all */
-static void isicom_flush_chars(struct tty_struct * tty)
+static void isicom_flush_chars(struct tty_struct *tty)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
-
+ struct isi_port *port = tty->driver_data;
+
if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars"))
return;
-
- if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !port->xmit_buf)
+
+ if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !port->xmit_buf)
return;
-
+
/* this tells the transmitter to consider this port for
data output to the card ... that's the best we can do. */
- port->status |= ISI_TXOK;
+ port->status |= ISI_TXOK;
}
/* write_room et all */
-static int isicom_write_room(struct tty_struct * tty)
+static int isicom_write_room(struct tty_struct *tty)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
+ struct isi_port *port = tty->driver_data;
int free;
if (isicom_paranoia_check(port, tty->name, "isicom_write_room"))
return 0;
-
+
free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
if (free < 0)
free = 0;
@@ -1471,23 +1228,24 @@ static int isicom_write_room(struct tty_struct * tty)
}
/* chars_in_buffer et all */
-static int isicom_chars_in_buffer(struct tty_struct * tty)
+static int isicom_chars_in_buffer(struct tty_struct *tty)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
+ struct isi_port *port = tty->driver_data;
if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer"))
return 0;
return port->xmit_cnt;
}
/* ioctl et all */
-static inline void isicom_send_break(struct isi_port * port, unsigned long length)
+static inline void isicom_send_break(struct isi_port *port,
+ unsigned long length)
{
- struct isi_board * card = port->card;
- unsigned short base = card->base;
-
- if(!lock_card(card))
+ struct isi_board *card = port->card;
+ unsigned long base = card->base;
+
+ if (!lock_card(card))
return;
-
+
outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
outw((length & 0xff) << 8 | 0x00, base);
outw((length & 0xff00), base);
@@ -1498,13 +1256,13 @@ static inline void isicom_send_break(struct isi_port * port, unsigned long lengt
static int isicom_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
+ struct isi_port *port = tty->driver_data;
/* just send the port status */
- unsigned short status = port->status;
+ u16 status = port->status;
if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
return -ENODEV;
-
+
return ((status & ISI_RTS) ? TIOCM_RTS : 0) |
((status & ISI_DTR) ? TIOCM_DTR : 0) |
((status & ISI_DCD) ? TIOCM_CAR : 0) |
@@ -1514,13 +1272,13 @@ static int isicom_tiocmget(struct tty_struct *tty, struct file *file)
}
static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
+ unsigned int set, unsigned int clear)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
-
+ struct isi_port *port = tty->driver_data;
+
if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
return -ENODEV;
-
+
if (set & TIOCM_RTS)
raise_rts(port);
if (set & TIOCM_DTR)
@@ -1532,46 +1290,46 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file,
drop_dtr(port);
return 0;
-}
+}
-static int isicom_set_serial_info(struct isi_port * port,
- struct serial_struct __user *info)
+static int isicom_set_serial_info(struct isi_port *port,
+ struct serial_struct __user *info)
{
struct serial_struct newinfo;
int reconfig_port;
- if(copy_from_user(&newinfo, info, sizeof(newinfo)))
+ if (copy_from_user(&newinfo, info, sizeof(newinfo)))
return -EFAULT;
-
- reconfig_port = ((port->flags & ASYNC_SPD_MASK) !=
- (newinfo.flags & ASYNC_SPD_MASK));
-
+
+ reconfig_port = ((port->flags & ASYNC_SPD_MASK) !=
+ (newinfo.flags & ASYNC_SPD_MASK));
+
if (!capable(CAP_SYS_ADMIN)) {
if ((newinfo.close_delay != port->close_delay) ||
- (newinfo.closing_wait != port->closing_wait) ||
- ((newinfo.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
+ (newinfo.closing_wait != port->closing_wait) ||
+ ((newinfo.flags & ~ASYNC_USR_MASK) !=
+ (port->flags & ~ASYNC_USR_MASK)))
return -EPERM;
port->flags = ((port->flags & ~ ASYNC_USR_MASK) |
(newinfo.flags & ASYNC_USR_MASK));
- }
+ }
else {
port->close_delay = newinfo.close_delay;
- port->closing_wait = newinfo.closing_wait;
- port->flags = ((port->flags & ~ASYNC_FLAGS) |
+ port->closing_wait = newinfo.closing_wait;
+ port->flags = ((port->flags & ~ASYNC_FLAGS) |
(newinfo.flags & ASYNC_FLAGS));
}
if (reconfig_port) {
isicom_config_port(port);
}
- return 0;
-}
+ return 0;
+}
-static int isicom_get_serial_info(struct isi_port * port,
- struct serial_struct __user *info)
+static int isicom_get_serial_info(struct isi_port *port,
+ struct serial_struct __user *info)
{
struct serial_struct out_info;
-
+
memset(&out_info, 0, sizeof(out_info));
/* out_info.type = ? */
out_info.line = port - isi_ports;
@@ -1581,15 +1339,15 @@ static int isicom_get_serial_info(struct isi_port * port,
/* out_info.baud_base = ? */
out_info.close_delay = port->close_delay;
out_info.closing_wait = port->closing_wait;
- if(copy_to_user(info, &out_info, sizeof(out_info)))
+ if (copy_to_user(info, &out_info, sizeof(out_info)))
return -EFAULT;
return 0;
-}
+}
-static int isicom_ioctl(struct tty_struct * tty, struct file * filp,
- unsigned int cmd, unsigned long arg)
+static int isicom_ioctl(struct tty_struct *tty, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
+ struct isi_port *port = tty->driver_data;
void __user *argp = (void __user *)arg;
int retval;
@@ -1597,139 +1355,141 @@ static int isicom_ioctl(struct tty_struct * tty, struct file * filp,
return -ENODEV;
switch(cmd) {
- case TCSBRK:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- isicom_send_break(port, HZ/4);
- return 0;
-
- case TCSBRKP:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);
- return 0;
-
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
-
- case TIOCSSOFTCAR:
- if(get_user(arg, (unsigned long __user *) argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
-
- case TIOCGSERIAL:
- return isicom_get_serial_info(port, argp);
-
- case TIOCSSERIAL:
- return isicom_set_serial_info(port, argp);
-
- default:
- return -ENOIOCTLCMD;
+ case TCSBRK:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ isicom_send_break(port, HZ/4);
+ return 0;
+
+ case TCSBRKP:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);
+ return 0;
+
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long __user *)argp);
+
+ case TIOCSSOFTCAR:
+ if (get_user(arg, (unsigned long __user *) argp))
+ return -EFAULT;
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ return 0;
+
+ case TIOCGSERIAL:
+ return isicom_get_serial_info(port, argp);
+
+ case TIOCSSERIAL:
+ return isicom_set_serial_info(port, argp);
+
+ default:
+ return -ENOIOCTLCMD;
}
return 0;
}
/* set_termios et all */
-static void isicom_set_termios(struct tty_struct * tty, struct termios * old_termios)
+static void isicom_set_termios(struct tty_struct *tty,
+ struct termios *old_termios)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
-
+ struct isi_port *port = tty->driver_data;
+
if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
return;
-
+
if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
+ tty->termios->c_iflag == old_termios->c_iflag)
return;
-
+
isicom_config_port(port);
-
+
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios->c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
- isicom_start(tty);
- }
+ isicom_start(tty);
+ }
}
/* throttle et all */
-static void isicom_throttle(struct tty_struct * tty)
+static void isicom_throttle(struct tty_struct *tty)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
- struct isi_board * card = port->card;
-
+ struct isi_port *port = tty->driver_data;
+ struct isi_board *card = port->card;
+
if (isicom_paranoia_check(port, tty->name, "isicom_throttle"))
return;
-
+
/* tell the card that this port cannot handle any more data for now */
card->port_status &= ~(1 << port->channel);
outw(card->port_status, card->base + 0x02);
}
/* unthrottle et all */
-static void isicom_unthrottle(struct tty_struct * tty)
+static void isicom_unthrottle(struct tty_struct *tty)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
- struct isi_board * card = port->card;
-
+ struct isi_port *port = tty->driver_data;
+ struct isi_board *card = port->card;
+
if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle"))
return;
-
+
/* tell the card that this port is ready to accept more data */
card->port_status |= (1 << port->channel);
outw(card->port_status, card->base + 0x02);
}
/* stop et all */
-static void isicom_stop(struct tty_struct * tty)
+static void isicom_stop(struct tty_struct *tty)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
+ struct isi_port *port = tty->driver_data;
if (isicom_paranoia_check(port, tty->name, "isicom_stop"))
return;
-
+
/* this tells the transmitter not to consider this port for
data output to the card. */
port->status &= ~ISI_TXOK;
}
/* start et all */
-static void isicom_start(struct tty_struct * tty)
+static void isicom_start(struct tty_struct *tty)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
-
+ struct isi_port *port = tty->driver_data;
+
if (isicom_paranoia_check(port, tty->name, "isicom_start"))
return;
-
+
/* this tells the transmitter to consider this port for
data output to the card. */
port->status |= ISI_TXOK;
}
/* hangup et all */
-static void do_isicom_hangup(void * data)
+static void do_isicom_hangup(void *data)
{
- struct isi_port * port = (struct isi_port *) data;
- struct tty_struct * tty;
-
+ struct isi_port *port = data;
+ struct tty_struct *tty;
+
tty = port->tty;
if (tty)
tty_hangup(tty);
}
-static void isicom_hangup(struct tty_struct * tty)
+static void isicom_hangup(struct tty_struct *tty)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
-
+ struct isi_port *port = tty->driver_data;
+
if (isicom_paranoia_check(port, tty->name, "isicom_hangup"))
return;
-
+
isicom_shutdown_port(port);
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
@@ -1738,342 +1498,540 @@ static void isicom_hangup(struct tty_struct * tty)
}
/* flush_buffer et all */
-static void isicom_flush_buffer(struct tty_struct * tty)
+static void isicom_flush_buffer(struct tty_struct *tty)
{
- struct isi_port * port = (struct isi_port *) tty->driver_data;
- struct isi_board * card = port->card;
+ struct isi_port *port = tty->driver_data;
+ struct isi_board *card = port->card;
unsigned long flags;
-
+
if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
return;
-
+
spin_lock_irqsave(&card->card_lock, flags);
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
spin_unlock_irqrestore(&card->card_lock, flags);
-
+
wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
}
+/*
+ * Driver init and deinit functions
+ */
-static int __devinit register_ioregion(void)
+static int __devinit isicom_register_ioregion(struct pci_dev *pdev,
+ const unsigned int index)
{
- int count, done=0;
- for (count=0; count < BOARD_COUNT; count++ ) {
- if (isi_card[count].base)
- if (!request_region(isi_card[count].base,16,ISICOM_NAME)) {
- printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x is busy. Card%d will be disabled.\n",
- isi_card[count].base,isi_card[count].base+15,count+1);
- isi_card[count].base=0;
- done++;
- }
- }
- return done;
+ struct isi_board *board = pci_get_drvdata(pdev);
+
+ if (!board->base)
+ return -EINVAL;
+
+ if (!request_region(board->base, 16, ISICOM_NAME)) {
+ dev_dbg(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d "
+ "will be disabled.\n", board->base, board->base + 15,
+ index + 1);
+ return -EBUSY;
+ }
+
+ return 0;
}
-static void unregister_ioregion(void)
+static void isicom_unregister_ioregion(struct pci_dev *pdev)
{
- int count;
- for (count=0; count < BOARD_COUNT; count++ )
- if (isi_card[count].base) {
- release_region(isi_card[count].base,16);
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x released for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1);
-#endif
- }
+ struct isi_board *board = pci_get_drvdata(pdev);
+
+ if (!board->base)
+ return;
+
+ release_region(board->base, 16);
+ dev_dbg(&pdev->dev, "I/O Region 0x%lx-0x%lx released.\n",
+ board->base, board->base + 15);
+ board->base = 0;
}
static struct tty_operations isicom_ops = {
- .open = isicom_open,
- .close = isicom_close,
- .write = isicom_write,
- .put_char = isicom_put_char,
- .flush_chars = isicom_flush_chars,
- .write_room = isicom_write_room,
+ .open = isicom_open,
+ .close = isicom_close,
+ .write = isicom_write,
+ .put_char = isicom_put_char,
+ .flush_chars = isicom_flush_chars,
+ .write_room = isicom_write_room,
.chars_in_buffer = isicom_chars_in_buffer,
- .ioctl = isicom_ioctl,
- .set_termios = isicom_set_termios,
- .throttle = isicom_throttle,
- .unthrottle = isicom_unthrottle,
- .stop = isicom_stop,
- .start = isicom_start,
- .hangup = isicom_hangup,
- .flush_buffer = isicom_flush_buffer,
- .tiocmget = isicom_tiocmget,
- .tiocmset = isicom_tiocmset,
+ .ioctl = isicom_ioctl,
+ .set_termios = isicom_set_termios,
+ .throttle = isicom_throttle,
+ .unthrottle = isicom_unthrottle,
+ .stop = isicom_stop,
+ .start = isicom_start,
+ .hangup = isicom_hangup,
+ .flush_buffer = isicom_flush_buffer,
+ .tiocmget = isicom_tiocmget,
+ .tiocmset = isicom_tiocmset,
};
-static int __devinit register_drivers(void)
+static int __devinit isicom_register_tty_driver(void)
{
- int error;
+ int error = -ENOMEM;
/* tty driver structure initialization */
isicom_normal = alloc_tty_driver(PORT_COUNT);
if (!isicom_normal)
- return -ENOMEM;
-
- isicom_normal->owner = THIS_MODULE;
- isicom_normal->name = "ttyM";
- isicom_normal->devfs_name = "isicom/";
- isicom_normal->major = ISICOM_NMAJOR;
- isicom_normal->minor_start = 0;
- isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
- isicom_normal->subtype = SERIAL_TYPE_NORMAL;
- isicom_normal->init_termios = tty_std_termios;
- isicom_normal->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL |CLOCAL;
- isicom_normal->flags = TTY_DRIVER_REAL_RAW;
+ goto end;
+
+ isicom_normal->owner = THIS_MODULE;
+ isicom_normal->name = "ttyM";
+ isicom_normal->devfs_name = "isicom/";
+ isicom_normal->major = ISICOM_NMAJOR;
+ isicom_normal->minor_start = 0;
+ isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
+ isicom_normal->subtype = SERIAL_TYPE_NORMAL;
+ isicom_normal->init_termios = tty_std_termios;
+ isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
+ CLOCAL;
+ isicom_normal->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(isicom_normal, &isicom_ops);
-
- if ((error=tty_register_driver(isicom_normal))!=0) {
- printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n",
+
+ if ((error = tty_register_driver(isicom_normal))) {
+ pr_dbg("Couldn't register the dialin driver, error=%d\n",
error);
put_tty_driver(isicom_normal);
- return error;
}
- return 0;
+end:
+ return error;
}
-static void unregister_drivers(void)
+static void isicom_unregister_tty_driver(void)
{
- int error = tty_unregister_driver(isicom_normal);
- if (error)
- printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error);
+ int error;
+
+ if ((error = tty_unregister_driver(isicom_normal)))
+ pr_dbg("couldn't unregister normal driver, error=%d.\n", error);
+
put_tty_driver(isicom_normal);
}
-static int __devinit register_isr(void)
+static int __devinit isicom_register_isr(struct pci_dev *pdev,
+ const unsigned int index)
{
- int count, done=0;
- unsigned long irqflags;
-
- for (count=0; count < BOARD_COUNT; count++ ) {
- if (isi_card[count].base) {
- irqflags = (isi_card[count].isa == YES) ?
- SA_INTERRUPT :
- (SA_INTERRUPT | SA_SHIRQ);
-
- if (request_irq(isi_card[count].irq,
- isicom_interrupt,
- irqflags,
- ISICOM_NAME, &isi_card[count])) {
-
- printk(KERN_WARNING "ISICOM: Could not"
- " install handler at Irq %d."
- " Card%d will be disabled.\n",
- isi_card[count].irq, count+1);
-
- release_region(isi_card[count].base,16);
- isi_card[count].base=0;
- }
- else
- done++;
- }
- }
- return done;
+ struct isi_board *board = pci_get_drvdata(pdev);
+ unsigned long irqflags = SA_INTERRUPT;
+ int retval = -EINVAL;
+
+ if (!board->base)
+ goto end;
+
+ if (board->isa == NO)
+ irqflags |= SA_SHIRQ;
+
+ retval = request_irq(board->irq, isicom_interrupt, irqflags,
+ ISICOM_NAME, board);
+ if (retval < 0)
+ dev_warn(&pdev->dev, "Could not install handler at Irq %d. "
+ "Card%d will be disabled.\n", board->irq, index + 1);
+ else
+ retval = 0;
+end:
+ return retval;
}
-static void __exit unregister_isr(void)
+static int __devinit reset_card(struct pci_dev *pdev,
+ const unsigned int card, unsigned int *signature)
{
- int count;
+ struct isi_board *board = pci_get_drvdata(pdev);
+ unsigned long base = board->base;
+ unsigned int portcount = 0;
+ int retval = 0;
+
+ dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1,
+ base);
- for (count=0; count < BOARD_COUNT; count++ ) {
- if (isi_card[count].base)
- free_irq(isi_card[count].irq, &isi_card[count]);
+ inw(base + 0x8);
+
+ mdelay(10);
+
+ outw(0, base + 0x8); /* Reset */
+
+ msleep(3000);
+
+ *signature = inw(base + 0x4) & 0xff;
+
+ if (board->isa == YES) {
+ if (!(inw(base + 0xe) & 0x1) || (inw(base + 0x2))) {
+ dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n",
+ inw(base + 0x2), inw(base + 0xe));
+ dev_err(&pdev->dev, "ISILoad:ISA Card%d reset failure "
+ "(Possible bad I/O Port Address 0x%lx).\n",
+ card + 1, base);
+ retval = -EIO;
+ goto end;
+ }
+ } else {
+ portcount = inw(base + 0x2);
+ if (!(inw(base + 0xe) & 0x1) || ((portcount != 0) &&
+ (portcount != 4) && (portcount != 8))) {
+ dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n",
+ inw(base + 0x2), inw(base + 0xe));
+ dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure "
+ "(Possible bad I/O Port Address 0x%lx).\n",
+ card + 1, base);
+ retval = -EIO;
+ goto end;
+ }
}
+
+ switch (*signature) {
+ case 0xa5:
+ case 0xbb:
+ case 0xdd:
+ board->port_count = (board->isa == NO && portcount == 4) ? 4 :
+ 8;
+ board->shift_count = 12;
+ break;
+ case 0xcc:
+ board->port_count = 16;
+ board->shift_count = 11;
+ break;
+ default:
+ dev_warn(&pdev->dev, "ISILoad:Card%d reset failure (Possible "
+ "bad I/O Port Address 0x%lx).\n", card + 1, base);
+ dev_dbg(&pdev->dev, "Sig=0x%lx\n", signature);
+ retval = -EIO;
+ }
+ dev_info(&pdev->dev, "-Done\n");
+
+end:
+ return retval;
}
-static int __devinit isicom_init(void)
+static inline int WaitTillCardIsFree(u16 base)
{
- int card, channel, base;
- struct isi_port * port;
- unsigned long page;
-
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page) {
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n");
-#else
- printk(KERN_ERR "ISICOM: Not enough memory...\n");
-#endif
- return 0;
- }
- tmp_buf = (unsigned char *) page;
- }
-
- if (!register_ioregion())
- {
- printk(KERN_ERR "ISICOM: All required I/O space found busy.\n");
- free_page((unsigned long)tmp_buf);
- return 0;
- }
- if (register_drivers())
- {
- unregister_ioregion();
- free_page((unsigned long)tmp_buf);
- return 0;
- }
- if (!register_isr())
- {
- unregister_drivers();
- /* ioports already uregistered in register_isr */
- free_page((unsigned long)tmp_buf);
- return 0;
+ unsigned long count = 0;
+
+ while (!(inw(base + 0xe) & 0x1) && count++ < 100)
+ msleep(5);
+
+ return !(inw(base + 0xe) & 0x1);
+}
+
+static int __devinit load_firmware(struct pci_dev *pdev,
+ const unsigned int index, const unsigned int signature)
+{
+ struct isi_board *board = pci_get_drvdata(pdev);
+ const struct firmware *fw;
+ unsigned long base = board->base;
+ unsigned int a;
+ u16 word_count, status;
+ int retval = -EIO;
+ char *name;
+ u8 *data;
+
+ struct stframe {
+ u16 addr;
+ u16 count;
+ u8 data[0];
+ } *frame;
+
+ switch (signature) {
+ case 0xa5:
+ name = "isi608.bin";
+ break;
+ case 0xbb:
+ name = "isi608em.bin";
+ break;
+ case 0xcc:
+ name = "isi616em.bin";
+ break;
+ case 0xdd:
+ name = "isi4608.bin";
+ break;
+ case 0xee:
+ name = "isi4616.bin";
+ break;
+ default:
+ dev_err(&pdev->dev, "Unknown signature.\n");
+ goto end;
+ }
+
+ retval = request_firmware(&fw, name, &pdev->dev);
+ if (retval)
+ goto end;
+
+ for (frame = (struct stframe *)fw->data;
+ frame < (struct stframe *)(fw->data + fw->size);
+ frame++) {
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+ outw(0xf0, base); /* start upload sequence */
+ outw(0x00, base);
+ outw(frame->addr, base); /* lsb of address */
+
+ word_count = frame->count / 2 + frame->count % 2;
+ outw(word_count, base);
+ InterruptTheCard(base);
+
+ udelay(100); /* 0x2f */
+
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+ if ((status = inw(base + 0x4)) != 0) {
+ dev_warn(&pdev->dev, "Card%d rejected load header:\n"
+ "Address:0x%x\nCount:0x%x\nStatus:0x%x\n",
+ index + 1, frame->addr, frame->count, status);
+ goto errrelfw;
+ }
+ outsw(base, frame->data, word_count);
+
+ InterruptTheCard(base);
+
+ udelay(50); /* 0x0f */
+
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+ if ((status = inw(base + 0x4)) != 0) {
+ dev_err(&pdev->dev, "Card%d got out of sync.Card "
+ "Status:0x%x\n", index + 1, status);
+ goto errrelfw;
+ }
+ }
+
+ retval = -EIO;
+
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+ outw(0xf2, base);
+ outw(0x800, base);
+ outw(0x0, base);
+ outw(0x0, base);
+ InterruptTheCard(base);
+ outw(0x0, base + 0x4); /* for ISI4608 cards */
+
+/* XXX: should we test it by reading it back and comparing with original like
+ * in load firmware package? */
+ for (frame = (struct stframe*)fw->data;
+ frame < (struct stframe*)(fw->data + fw->size);
+ frame++) {
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+ outw(0xf1, base); /* start download sequence */
+ outw(0x00, base);
+ outw(frame->addr, base); /* lsb of address */
+
+ word_count = (frame->count >> 1) + frame->count % 2;
+ outw(word_count + 1, base);
+ InterruptTheCard(base);
+
+ udelay(50); /* 0xf */
+
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+ if ((status = inw(base + 0x4)) != 0) {
+ dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
+ "Address:0x%x\nCount:0x%x\nStatus: 0x%x\n",
+ index + 1, frame->addr, frame->count, status);
+ goto errrelfw;
+ }
+
+ data = kmalloc(word_count * 2, GFP_KERNEL);
+ inw(base);
+ insw(base, data, word_count);
+ InterruptTheCard(base);
+
+ for (a = 0; a < frame->count; a++)
+ if (data[a] != frame->data[a]) {
+ kfree(data);
+ dev_err(&pdev->dev, "Card%d, firmware upload "
+ "failed\n", index + 1);
+ goto errrelfw;
+ }
+ kfree(data);
+
+ udelay(50); /* 0xf */
+
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+ if ((status = inw(base + 0x4)) != 0) {
+ dev_err(&pdev->dev, "Card%d verify got out of sync. "
+ "Card Status:0x%x\n", index + 1, status);
+ goto errrelfw;
+ }
}
-
- memset(isi_ports, 0, sizeof(isi_ports));
- for (card = 0; card < BOARD_COUNT; card++) {
- port = &isi_ports[card * 16];
- isi_card[card].ports = port;
- spin_lock_init(&isi_card[card].card_lock);
- base = isi_card[card].base;
- for (channel = 0; channel < 16; channel++, port++) {
- port->magic = ISICOM_MAGIC;
- port->card = &isi_card[card];
- port->channel = channel;
- port->close_delay = 50 * HZ/100;
- port->closing_wait = 3000 * HZ/100;
- INIT_WORK(&port->hangup_tq, do_isicom_hangup, port);
- INIT_WORK(&port->bh_tqueue, isicom_bottomhalf, port);
- port->status = 0;
- init_waitqueue_head(&port->open_wait);
- init_waitqueue_head(&port->close_wait);
- /* . . . */
- }
- }
-
- return 1;
+
+ board->status |= FIRMWARE_LOADED;
+ retval = 0;
+
+errrelfw:
+ release_firmware(fw);
+end:
+ return retval;
}
/*
* Insmod can set static symbols so keep these static
*/
-
static int io[4];
static int irq[4];
+static int card;
-MODULE_AUTHOR("MultiTech");
-MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
-MODULE_LICENSE("GPL");
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io, "I/O ports for the cards");
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq, "Interrupts for the cards");
+static int __devinit isicom_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ unsigned int ioaddr, signature, index;
+ int retval = -EPERM;
+ u8 pciirq;
+ struct isi_board *board = NULL;
+
+ if (card >= BOARD_COUNT)
+ goto err;
+
+ ioaddr = pci_resource_start(pdev, 3);
+ /* i.e at offset 0x1c in the PCI configuration register space. */
+ pciirq = pdev->irq;
+ dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
+
+ /* allot the first empty slot in the array */
+ for (index = 0; index < BOARD_COUNT; index++)
+ if (isi_card[index].base == 0) {
+ board = &isi_card[index];
+ break;
+ }
+
+ board->base = ioaddr;
+ board->irq = pciirq;
+ board->isa = NO;
+ card++;
+
+ pci_set_drvdata(pdev, board);
+
+ retval = isicom_register_ioregion(pdev, index);
+ if (retval < 0)
+ goto err;
+
+ retval = isicom_register_isr(pdev, index);
+ if (retval < 0)
+ goto errunrr;
+
+ retval = reset_card(pdev, index, &signature);
+ if (retval < 0)
+ goto errunri;
+
+ retval = load_firmware(pdev, index, signature);
+ if (retval < 0)
+ goto errunri;
+
+ return 0;
+
+errunri:
+ free_irq(board->irq, board);
+errunrr:
+ isicom_unregister_ioregion(pdev);
+err:
+ board->base = 0;
+ return retval;
+}
+
+static void __devexit isicom_remove(struct pci_dev *pdev)
+{
+ struct isi_board *board = pci_get_drvdata(pdev);
+
+ free_irq(board->irq, board);
+ isicom_unregister_ioregion(pdev);
+}
static int __devinit isicom_setup(void)
{
- struct pci_dev *dev = NULL;
- int retval, card, idx, count;
- unsigned char pciirq;
- unsigned int ioaddr;
-
+ int retval, idx, channel;
+ struct isi_port *port;
+
card = 0;
- for(idx=0; idx < BOARD_COUNT; idx++) {
- if (io[idx]) {
- isi_card[idx].base=io[idx];
- isi_card[idx].irq=irq[idx];
- isi_card[idx].isa=YES;
- card++;
- }
- else {
- isi_card[idx].base = 0;
- isi_card[idx].irq = 0;
- }
- }
-
- for (idx=0 ;idx < card; idx++) {
- if (!((isi_card[idx].irq==2)||(isi_card[idx].irq==3)||
- (isi_card[idx].irq==4)||(isi_card[idx].irq==5)||
- (isi_card[idx].irq==7)||(isi_card[idx].irq==10)||
- (isi_card[idx].irq==11)||(isi_card[idx].irq==12)||
- (isi_card[idx].irq==15))) {
-
- if (isi_card[idx].base) {
- printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n",
- isi_card[idx].irq, idx+1);
- isi_card[idx].base=0;
- card--;
- }
- }
- }
-
- if (card < BOARD_COUNT) {
- for (idx=0; idx < DEVID_COUNT; idx++) {
- dev = NULL;
- for (;;){
- if (!(dev = pci_find_device(VENDOR_ID, isicom_pci_tbl[idx].device, dev)))
- break;
- if (card >= BOARD_COUNT)
- break;
-
- if (pci_enable_device(dev))
- break;
+ memset(isi_ports, 0, sizeof(isi_ports));
- /* found a PCI ISI card! */
- ioaddr = pci_resource_start (dev, 3); /* i.e at offset 0x1c in the
- * PCI configuration register
- * space.
- */
- pciirq = dev->irq;
- printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", isicom_pci_tbl[idx].device);
- /*
- * allot the first empty slot in the array
- */
- for (count=0; count < BOARD_COUNT; count++) {
- if (isi_card[count].base == 0) {
- isi_card[count].base = ioaddr;
- isi_card[count].irq = pciirq;
- isi_card[count].isa = NO;
- card++;
- break;
- }
- }
- }
- if (card >= BOARD_COUNT) break;
- }
+ for(idx = 0; idx < BOARD_COUNT; idx++) {
+ port = &isi_ports[idx * 16];
+ isi_card[idx].ports = port;
+ spin_lock_init(&isi_card[idx].card_lock);
+ for (channel = 0; channel < 16; channel++, port++) {
+ port->magic = ISICOM_MAGIC;
+ port->card = &isi_card[idx];
+ port->channel = channel;
+ port->close_delay = 50 * HZ/100;
+ port->closing_wait = 3000 * HZ/100;
+ INIT_WORK(&port->hangup_tq, do_isicom_hangup, port);
+ INIT_WORK(&port->bh_tqueue, isicom_bottomhalf, port);
+ port->status = 0;
+ init_waitqueue_head(&port->open_wait);
+ init_waitqueue_head(&port->close_wait);
+ /* . . . */
+ }
+ isi_card[idx].base = 0;
+ isi_card[idx].irq = 0;
+
+ if (!io[idx])
+ continue;
+
+ if (irq[idx] == 2 || irq[idx] == 3 || irq[idx] == 4 ||
+ irq[idx] == 5 || irq[idx] == 7 ||
+ irq[idx] == 10 || irq[idx] == 11 ||
+ irq[idx] == 12 || irq[idx] == 15) {
+ printk(KERN_ERR "ISICOM: ISA not supported yet.\n");
+ retval = -EINVAL;
+ goto error;
+ } else
+ printk(KERN_ERR "ISICOM: Irq %d unsupported. "
+ "Disabling Card%d...\n", irq[idx], idx + 1);
}
-
- if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) {
- printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n");
- return -EIO;
- }
- retval = misc_register(&isiloader_device);
+ retval = isicom_register_tty_driver();
+ if (retval < 0)
+ goto error;
+
+ retval = pci_register_driver(&isicom_driver);
if (retval < 0) {
- printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n");
- return retval;
- }
-
- if (!isicom_init()) {
- if (misc_deregister(&isiloader_device))
- printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");
- return -EIO;
+ printk(KERN_ERR "ISICOM: Unable to register pci driver.\n");
+ goto errtty;
}
-
+
init_timer(&tx);
tx.expires = jiffies + 1;
tx.data = 0;
tx.function = isicom_tx;
re_schedule = 1;
add_timer(&tx);
-
+
return 0;
+errtty:
+ isicom_unregister_tty_driver();
+error:
+ return retval;
}
static void __exit isicom_exit(void)
{
+ unsigned int index = 0;
+
re_schedule = 0;
- /* FIXME */
- msleep(1000);
- unregister_isr();
- unregister_drivers();
- unregister_ioregion();
- if(tmp_buf)
- free_page((unsigned long)tmp_buf);
- if (misc_deregister(&isiloader_device))
- printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");
+
+ while (re_schedule != 2 && index++ < 100)
+ msleep(10);
+
+ pci_unregister_driver(&isicom_driver);
+ isicom_unregister_tty_driver();
}
module_init(isicom_setup);
module_exit(isicom_exit);
+
+MODULE_AUTHOR("MultiTech");
+MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
+MODULE_LICENSE("GPL");
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io, "I/O ports for the cards");
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(irq, "Interrupts for the cards");
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index ce3bc0d45f1..28c5a3193b8 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -135,7 +135,7 @@ static stlconf_t stli_brdconf[] = {
/*{ BRD_ECP, 0x2a0, 0, 0xcc000, 0, 0 },*/
};
-static int stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
+static int stli_nrbrds = ARRAY_SIZE(stli_brdconf);
/*
* There is some experimental EISA board detection code in this driver.
@@ -406,7 +406,7 @@ static unsigned long stli_eisamemprobeaddrs[] = {
0xff000000, 0xff010000, 0xff020000, 0xff030000,
};
-static int stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long);
+static int stli_eisamempsize = ARRAY_SIZE(stli_eisamemprobeaddrs);
/*
* Define the Stallion PCI vendor and device IDs.
@@ -899,15 +899,13 @@ static void stli_argbrds(void)
{
stlconf_t conf;
stlibrd_t *brdp;
- int nrargs, i;
+ int i;
#ifdef DEBUG
printk("stli_argbrds()\n");
#endif
- nrargs = sizeof(stli_brdsp) / sizeof(char **);
-
- for (i = stli_nrbrds; (i < nrargs); i++) {
+ for (i = stli_nrbrds; i < ARRAY_SIZE(stli_brdsp); i++) {
memset(&conf, 0, sizeof(conf));
if (stli_parsebrd(&conf, stli_brdsp[i]) == 0)
continue;
@@ -967,7 +965,7 @@ static unsigned long stli_atol(char *str)
static int stli_parsebrd(stlconf_t *confp, char **argp)
{
char *sp;
- int nrbrdnames, i;
+ int i;
#ifdef DEBUG
printk("stli_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp);
@@ -979,14 +977,13 @@ static int stli_parsebrd(stlconf_t *confp, char **argp)
for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
*sp = TOLOWER(*sp);
- nrbrdnames = sizeof(stli_brdstr) / sizeof(stlibrdtype_t);
- for (i = 0; (i < nrbrdnames); i++) {
+ for (i = 0; i < ARRAY_SIZE(stli_brdstr); i++) {
if (strcmp(stli_brdstr[i].name, argp[0]) == 0)
break;
}
- if (i >= nrbrdnames) {
+ if (i == ARRAY_SIZE(stli_brdstr)) {
printk("STALLION: unknown board name, %s?\n", argp[0]);
- return(0);
+ return 0;
}
confp->brdtype = stli_brdstr[i].type;
@@ -2714,17 +2711,13 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
stlen = size - tail;
}
- len = MIN(len, (TTY_FLIPBUF_SIZE - tty->flip.count));
+ len = tty_buffer_request_room(tty, len);
+ /* FIXME : iomap ? */
shbuf = (volatile char *) EBRDGETMEMPTR(brdp, portp->rxoffset);
while (len > 0) {
stlen = MIN(len, stlen);
- memcpy(tty->flip.char_buf_ptr, (char *) (shbuf + tail), stlen);
- memset(tty->flip.flag_buf_ptr, 0, stlen);
- tty->flip.char_buf_ptr += stlen;
- tty->flip.flag_buf_ptr += stlen;
- tty->flip.count += stlen;
-
+ tty_insert_flip_string(tty, (char *)(shbuf + tail), stlen);
len -= stlen;
tail += stlen;
if (tail >= size) {
@@ -2909,16 +2902,12 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
if ((nt.data & DT_RXBREAK) && (portp->rxmarkmsk & BRKINT)) {
if (tty != (struct tty_struct *) NULL) {
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- *tty->flip.char_buf_ptr++ = 0;
- if (portp->flags & ASYNC_SAK) {
- do_SAK(tty);
- EBRDENABLE(brdp);
- }
- tty_schedule_flip(tty);
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
+ if (portp->flags & ASYNC_SAK) {
+ do_SAK(tty);
+ EBRDENABLE(brdp);
}
+ tty_schedule_flip(tty);
}
}
@@ -4943,7 +4932,7 @@ static int stli_portcmdstats(stliport_t *portp)
if (portp->tty != (struct tty_struct *) NULL) {
if (portp->tty->driver_data == portp) {
stli_comstats.ttystate = portp->tty->flags;
- stli_comstats.rxbuffered = portp->tty->flip.count;
+ stli_comstats.rxbuffered = -1 /*portp->tty->flip.count*/;
if (portp->tty->termios != (struct termios *) NULL) {
stli_comstats.cflags = portp->tty->termios->c_cflag;
stli_comstats.iflags = portp->tty->termios->c_iflag;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 91dd669273e..704c3c07f0a 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -101,6 +101,11 @@ static inline int valid_phys_addr_range(unsigned long addr, size_t *count)
return 1;
}
+
+static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t *size)
+{
+ return 1;
+}
#endif
/*
@@ -228,26 +233,36 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
return written;
}
+#ifndef __HAVE_PHYS_MEM_ACCESS_PROT
+static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot)
+{
+#ifdef pgprot_noncached
+ unsigned long offset = pfn << PAGE_SHIFT;
+
+ if (uncached_access(file, offset))
+ return pgprot_noncached(vma_prot);
+#endif
+ return vma_prot;
+}
+#endif
+
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
-#if defined(__HAVE_PHYS_MEM_ACCESS_PROT)
+ size_t size = vma->vm_end - vma->vm_start;
+
+ if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, &size))
+ return -EINVAL;
+
vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
+ size,
vma->vm_page_prot);
-#elif defined(pgprot_noncached)
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- int uncached;
-
- uncached = uncached_access(file, offset);
- if (uncached)
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#endif
/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
if (remap_pfn_range(vma,
vma->vm_start,
vma->vm_pgoff,
- vma->vm_end-vma->vm_start,
+ size,
vma->vm_page_prot))
return -EAGAIN;
return 0;
@@ -726,7 +741,7 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
{
loff_t ret;
- down(&file->f_dentry->d_inode->i_sem);
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
switch (orig) {
case 0:
file->f_pos = offset;
@@ -741,7 +756,7 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
default:
ret = -EINVAL;
}
- up(&file->f_dentry->d_inode->i_sem);
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
return ret;
}
@@ -817,7 +832,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
char *tmp;
- int ret;
+ ssize_t ret;
tmp = kmalloc(count + 1, GFP_KERNEL);
if (tmp == NULL)
@@ -826,6 +841,9 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
if (!copy_from_user(tmp, buf, count)) {
tmp[count] = 0;
ret = printk("%s", tmp);
+ if (ret > count)
+ /* printk can add a prefix */
+ ret = count;
}
kfree(tmp);
return ret;
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 78c89a3e782..c92378121b4 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -1,11 +1,11 @@
/*
- * Intel Multimedia Timer device implementation for SGI SN platforms.
+ * Timer device implementation for SGI SN platforms.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (c) 2001-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 2001-2006 Silicon Graphics, Inc. All rights reserved.
*
* This driver exports an API that should be supportable by any HPET or IA-PC
* multimedia timer. The code below is currently specific to the SGI Altix
@@ -45,7 +45,7 @@ MODULE_LICENSE("GPL");
/* name of the device, usually in /dev */
#define MMTIMER_NAME "mmtimer"
#define MMTIMER_DESC "SGI Altix RTC Timer"
-#define MMTIMER_VERSION "2.0"
+#define MMTIMER_VERSION "2.1"
#define RTC_BITS 55 /* 55 bits for this implementation */
@@ -227,10 +227,7 @@ typedef struct mmtimer {
struct tasklet_struct tasklet;
} mmtimer_t;
-/*
- * Total number of comparators is comparators/node * MAX nodes/running kernel
- */
-static mmtimer_t timers[NUM_COMPARATORS*MAX_COMPACT_NODES];
+static mmtimer_t ** timers;
/**
* mmtimer_ioctl - ioctl interface for /dev/mmtimer
@@ -441,29 +438,29 @@ static irqreturn_t
mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
int i;
- mmtimer_t *base = timers + cpu_to_node(smp_processor_id()) *
- NUM_COMPARATORS;
unsigned long expires = 0;
int result = IRQ_NONE;
+ unsigned indx = cpu_to_node(smp_processor_id());
/*
* Do this once for each comparison register
*/
for (i = 0; i < NUM_COMPARATORS; i++) {
+ mmtimer_t *base = timers[indx] + i;
/* Make sure this doesn't get reused before tasklet_sched */
- spin_lock(&base[i].lock);
- if (base[i].cpu == smp_processor_id()) {
- if (base[i].timer)
- expires = base[i].timer->it.mmtimer.expires;
+ spin_lock(&base->lock);
+ if (base->cpu == smp_processor_id()) {
+ if (base->timer)
+ expires = base->timer->it.mmtimer.expires;
/* expires test won't work with shared irqs */
if ((mmtimer_int_pending(i) > 0) ||
(expires && (expires < rtc_time()))) {
mmtimer_clr_int_pending(i);
- tasklet_schedule(&base[i].tasklet);
+ tasklet_schedule(&base->tasklet);
result = IRQ_HANDLED;
}
}
- spin_unlock(&base[i].lock);
+ spin_unlock(&base->lock);
expires = 0;
}
return result;
@@ -523,7 +520,7 @@ static int sgi_timer_del(struct k_itimer *timr)
{
int i = timr->it.mmtimer.clock;
cnodeid_t nodeid = timr->it.mmtimer.node;
- mmtimer_t *t = timers + nodeid * NUM_COMPARATORS +i;
+ mmtimer_t *t = timers[nodeid] + i;
unsigned long irqflags;
if (i != TIMER_OFF) {
@@ -609,11 +606,11 @@ static int sgi_timer_set(struct k_itimer *timr, int flags,
preempt_disable();
nodeid = cpu_to_node(smp_processor_id());
- base = timers + nodeid * NUM_COMPARATORS;
retry:
/* Don't use an allocated timer, or a deleted one that's pending */
for(i = 0; i< NUM_COMPARATORS; i++) {
- if (!base[i].timer && !base[i].tasklet.state) {
+ base = timers[nodeid] + i;
+ if (!base->timer && !base->tasklet.state) {
break;
}
}
@@ -623,14 +620,14 @@ retry:
return -EBUSY;
}
- spin_lock_irqsave(&base[i].lock, irqflags);
+ spin_lock_irqsave(&base->lock, irqflags);
- if (base[i].timer || base[i].tasklet.state != 0) {
- spin_unlock_irqrestore(&base[i].lock, irqflags);
+ if (base->timer || base->tasklet.state != 0) {
+ spin_unlock_irqrestore(&base->lock, irqflags);
goto retry;
}
- base[i].timer = timr;
- base[i].cpu = smp_processor_id();
+ base->timer = timr;
+ base->cpu = smp_processor_id();
timr->it.mmtimer.clock = i;
timr->it.mmtimer.node = nodeid;
@@ -645,11 +642,11 @@ retry:
}
} else {
timr->it.mmtimer.expires -= period;
- if (reschedule_periodic_timer(base+i))
+ if (reschedule_periodic_timer(base))
err = -EINVAL;
}
- spin_unlock_irqrestore(&base[i].lock, irqflags);
+ spin_unlock_irqrestore(&base->lock, irqflags);
preempt_enable();
@@ -675,6 +672,7 @@ static struct k_clock sgi_clock = {
static int __init mmtimer_init(void)
{
unsigned i;
+ cnodeid_t node, maxn = -1;
if (!ia64_platform_is("sn2"))
return -1;
@@ -691,14 +689,6 @@ static int __init mmtimer_init(void)
mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second /
2) / sn_rtc_cycles_per_second;
- for (i=0; i< NUM_COMPARATORS*MAX_COMPACT_NODES; i++) {
- spin_lock_init(&timers[i].lock);
- timers[i].timer = NULL;
- timers[i].cpu = 0;
- timers[i].i = i % NUM_COMPARATORS;
- tasklet_init(&timers[i].tasklet, mmtimer_tasklet, (unsigned long) (timers+i));
- }
-
if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, SA_PERCPU_IRQ, MMTIMER_NAME, NULL)) {
printk(KERN_WARNING "%s: unable to allocate interrupt.",
MMTIMER_NAME);
@@ -712,6 +702,40 @@ static int __init mmtimer_init(void)
return -1;
}
+ /* Get max numbered node, calculate slots needed */
+ for_each_online_node(node) {
+ maxn = node;
+ }
+ maxn++;
+
+ /* Allocate list of node ptrs to mmtimer_t's */
+ timers = kmalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
+ if (timers == NULL) {
+ printk(KERN_ERR "%s: failed to allocate memory for device\n",
+ MMTIMER_NAME);
+ return -1;
+ }
+
+ /* Allocate mmtimer_t's for each online node */
+ for_each_online_node(node) {
+ timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node);
+ if (timers[node] == NULL) {
+ printk(KERN_ERR "%s: failed to allocate memory for device\n",
+ MMTIMER_NAME);
+ return -1;
+ }
+ for (i=0; i< NUM_COMPARATORS; i++) {
+ mmtimer_t * base = timers[node] + i;
+
+ spin_lock_init(&base->lock);
+ base->timer = NULL;
+ base->cpu = 0;
+ base->i = i;
+ tasklet_init(&base->tasklet, mmtimer_tasklet,
+ (unsigned long) (base));
+ }
+ }
+
sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second;
register_posix_clock(CLOCK_SGI_CYCLE, &sgi_clock);
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 79e490ef2cf..5e3ef552219 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -269,7 +269,7 @@ static int MoxaPortDCDChange(int);
static int MoxaPortDCDON(int);
static void MoxaPortFlushData(int, int);
static int MoxaPortWriteData(int, unsigned char *, int);
-static int MoxaPortReadData(int, unsigned char *, int);
+static int MoxaPortReadData(int, struct tty_struct *tty);
static int MoxaPortTxQueue(int);
static int MoxaPortRxQueue(int);
static int MoxaPortTxFree(int);
@@ -301,6 +301,8 @@ static struct tty_operations moxa_ops = {
.tiocmset = moxa_tiocmset,
};
+static spinlock_t moxa_lock = SPIN_LOCK_UNLOCKED;
+
#ifdef CONFIG_PCI
static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board)
{
@@ -448,7 +450,7 @@ static int __init moxa_init(void)
#ifdef CONFIG_PCI
{
struct pci_dev *p = NULL;
- int n = (sizeof(moxa_pcibrds) / sizeof(moxa_pcibrds[0])) - 1;
+ int n = ARRAY_SIZE(moxa_pcibrds) - 1;
i = 0;
while (i < n) {
while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL)
@@ -645,10 +647,10 @@ static int moxa_write(struct tty_struct *tty,
if (ch == NULL)
return (0);
port = ch->port;
- save_flags(flags);
- cli();
+
+ spin_lock_irqsave(&moxa_lock, flags);
len = MoxaPortWriteData(port, (unsigned char *) buf, count);
- restore_flags(flags);
+ spin_unlock_irqrestore(&moxa_lock, flags);
/*********************************************
if ( !(ch->statusflags & LOWWAIT) &&
@@ -723,11 +725,10 @@ static void moxa_put_char(struct tty_struct *tty, unsigned char c)
if (ch == NULL)
return;
port = ch->port;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&moxa_lock, flags);
moxaXmitBuff[0] = c;
MoxaPortWriteData(port, moxaXmitBuff, 1);
- restore_flags(flags);
+ spin_unlock_irqrestore(&moxa_lock, flags);
/************************************************
if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
*************************************************/
@@ -1030,12 +1031,12 @@ static int block_till_ready(struct tty_struct *tty, struct file *filp,
printk("block_til_ready before block: ttys%d, count = %d\n",
ch->line, ch->count);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&moxa_lock, flags);
if (!tty_hung_up_p(filp))
ch->count--;
- restore_flags(flags);
ch->blocked_open++;
+ spin_unlock_irqrestore(&moxa_lock, flags);
+
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
@@ -1062,17 +1063,21 @@ static int block_till_ready(struct tty_struct *tty, struct file *filp,
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&ch->open_wait, &wait);
+
+ spin_lock_irqsave(&moxa_lock, flags);
if (!tty_hung_up_p(filp))
ch->count++;
ch->blocked_open--;
+ spin_unlock_irqrestore(&moxa_lock, flags);
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready after blocking: ttys%d, count = %d\n",
ch->line, ch->count);
#endif
if (retval)
return (retval);
+ /* FIXME: review to see if we need to use set_bit on these */
ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
- return (0);
+ return 0;
}
static void setup_empty_event(struct tty_struct *tty)
@@ -1080,15 +1085,14 @@ static void setup_empty_event(struct tty_struct *tty)
struct moxa_str *ch = tty->driver_data;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&moxa_lock, flags);
ch->statusflags |= EMPTYWAIT;
moxaEmptyTimer_on[ch->port] = 0;
del_timer(&moxaEmptyTimer[ch->port]);
moxaEmptyTimer[ch->port].expires = jiffies + HZ;
moxaEmptyTimer_on[ch->port] = 1;
add_timer(&moxaEmptyTimer[ch->port]);
- restore_flags(flags);
+ spin_unlock_irqrestore(&moxa_lock, flags);
}
static void check_xmit_empty(unsigned long data)
@@ -1135,8 +1139,6 @@ static void receive_data(struct moxa_str *ch)
{
struct tty_struct *tp;
struct termios *ts;
- int i, count, rc, space;
- unsigned char *charptr, *flagptr;
unsigned long flags;
ts = NULL;
@@ -1150,24 +1152,10 @@ static void receive_data(struct moxa_str *ch)
MoxaPortFlushData(ch->port, 0);
return;
}
- space = TTY_FLIPBUF_SIZE - tp->flip.count;
- if (space <= 0)
- return;
- charptr = tp->flip.char_buf_ptr;
- flagptr = tp->flip.flag_buf_ptr;
- rc = tp->flip.count;
- save_flags(flags);
- cli();
- count = MoxaPortReadData(ch->port, charptr, space);
- restore_flags(flags);
- for (i = 0; i < count; i++)
- *flagptr++ = 0;
- charptr += count;
- rc += count;
- tp->flip.count = rc;
- tp->flip.char_buf_ptr = charptr;
- tp->flip.flag_buf_ptr = flagptr;
- tty_schedule_flip(ch->tty);
+ spin_lock_irqsave(&moxa_lock, flags);
+ MoxaPortReadData(ch->port, tp);
+ spin_unlock_irqrestore(&moxa_lock, flags);
+ tty_schedule_flip(tp);
}
#define Magic_code 0x404
@@ -1774,7 +1762,7 @@ int MoxaPortsOfCard(int cardno)
* 14. MoxaPortDCDON(int port); *
* 15. MoxaPortFlushData(int port, int mode); *
* 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
- * 17. MoxaPortReadData(int port, unsigned char * buffer, int length); *
+ * 17. MoxaPortReadData(int port, struct tty_struct *tty); *
* 18. MoxaPortTxBufSize(int port); *
* 19. MoxaPortRxBufSize(int port); *
* 20. MoxaPortTxQueue(int port); *
@@ -2003,10 +1991,9 @@ int MoxaPortsOfCard(int cardno)
*
* Function 21: Read data.
* Syntax:
- * int MoxaPortReadData(int port, unsigned char * buffer, int length);
+ * int MoxaPortReadData(int port, struct tty_struct *tty);
* int port : port number (0 - 127)
- * unsigned char * buffer : pointer to read data buffer.
- * int length : read data buffer length
+ * struct tty_struct *tty : tty for data
*
* return: 0 - length : real read data length
*
@@ -2504,7 +2491,7 @@ int MoxaPortWriteData(int port, unsigned char * buffer, int len)
return (total);
}
-int MoxaPortReadData(int port, unsigned char * buffer, int space)
+int MoxaPortReadData(int port, struct tty_struct *tty)
{
register ushort head, pageofs;
int i, count, cnt, len, total, remain;
@@ -2522,9 +2509,9 @@ int MoxaPortReadData(int port, unsigned char * buffer, int space)
count = (tail >= head) ? (tail - head)
: (tail - head + rx_mask + 1);
if (count == 0)
- return (0);
+ return 0;
- total = (space > count) ? count : space;
+ total = count;
remain = count - total;
moxaLog.rxcnt[port] += total;
count = total;
@@ -2539,7 +2526,7 @@ int MoxaPortReadData(int port, unsigned char * buffer, int space)
len = (count > len) ? len : count;
ofs = baseAddr + DynPage_addr + bufhead + head;
for (i = 0; i < len; i++)
- *buffer++ = readb(ofs + i);
+ tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
head = (head + len) & rx_mask;
count -= len;
}
@@ -2556,7 +2543,7 @@ int MoxaPortReadData(int port, unsigned char * buffer, int space)
writew(pageno, baseAddr + Control_reg);
ofs = baseAddr + DynPage_addr + pageofs;
for (i = 0; i < cnt; i++)
- *buffer++ = readb(ofs + i);
+ tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
if (count == 0) {
writew((head + len) & rx_mask, ofsAddr + RXrptr);
break;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 26448f17680..ea725a9964e 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -813,7 +813,7 @@ static int mxser_init(void)
/* start finding PCI board here */
#ifdef CONFIG_PCI
- n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1;
+ n = ARRAY_SIZE(mxser_pcibrds) - 1;
index = 0;
b = 0;
while (b < n) {
@@ -1982,7 +1982,7 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
spin_lock_irqsave(&info->slock, flags);
- recv_room = tty->ldisc.receive_room(tty);
+ recv_room = tty->receive_room;
if ((recv_room == 0) && (!info->ldisc_stop_rx)) {
//mxser_throttle(tty);
mxser_stoprx(tty);
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index a133a62f3d5..9f54733f162 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -191,7 +191,6 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
poll_table *wait);
static int n_hdlc_tty_open(struct tty_struct *tty);
static void n_hdlc_tty_close(struct tty_struct *tty);
-static int n_hdlc_tty_room(struct tty_struct *tty);
static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
char *fp, int count);
static void n_hdlc_tty_wakeup(struct tty_struct *tty);
@@ -212,7 +211,6 @@ static struct tty_ldisc n_hdlc_ldisc = {
.ioctl = n_hdlc_tty_ioctl,
.poll = n_hdlc_tty_poll,
.receive_buf = n_hdlc_tty_receive,
- .receive_room = n_hdlc_tty_room,
.write_wakeup = n_hdlc_tty_wakeup,
};
@@ -337,6 +335,7 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
tty->disc_data = n_hdlc;
n_hdlc->tty = tty;
+ tty->receive_room = 65536;
#if defined(TTY_NO_WRITE_SPLIT)
/* change tty_io write() to not split large writes into 8K chunks */
@@ -478,22 +477,6 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
} /* end of n_hdlc_tty_wakeup() */
/**
- * n_hdlc_tty_room - Return the amount of space left in the receiver's buffer
- * @tty - pointer to associated tty instance data
- *
- * Callback function from tty driver. Return the amount of space left in the
- * receiver's buffer to decide if remote transmitter is to be throttled.
- */
-static int n_hdlc_tty_room(struct tty_struct *tty)
-{
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_room() called\n",__FILE__,__LINE__);
- /* always return a larger number to prevent */
- /* throttling of remote transmitter. */
- return 65536;
-} /* end of n_hdlc_tty_root() */
-
-/**
* n_hdlc_tty_receive - Called by tty driver when receive data is available
* @tty - pointer to tty instance data
* @data - pointer to received data
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 853c98cee64..c48de09d68f 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -147,7 +147,6 @@ static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
struct poll_table_struct *wait);
static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count);
-static int r3964_receive_room(struct tty_struct *tty);
static struct tty_ldisc tty_ldisc_N_R3964 = {
.owner = THIS_MODULE,
@@ -161,7 +160,6 @@ static struct tty_ldisc tty_ldisc_N_R3964 = {
.set_termios = r3964_set_termios,
.poll = r3964_poll,
.receive_buf = r3964_receive_buf,
- .receive_room = r3964_receive_room,
};
@@ -1119,6 +1117,7 @@ static int r3964_open(struct tty_struct *tty)
pInfo->nRetry = 0;
tty->disc_data = pInfo;
+ tty->receive_room = 65536;
init_timer(&pInfo->tmr);
pInfo->tmr.data = (unsigned long)pInfo;
@@ -1405,12 +1404,5 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
}
-static int r3964_receive_room(struct tty_struct *tty)
-{
- TRACE_L("receive_room");
- return -1;
-}
-
-
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_R3964);
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index c556f4d3ccd..ccad7ae9454 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -78,7 +78,32 @@ static inline void free_buf(unsigned char *buf)
free_page((unsigned long) buf);
}
-static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
+/**
+ * n_tty_set__room - receive space
+ * @tty: terminal
+ *
+ * Called by the driver to find out how much data it is
+ * permitted to feed to the line discipline without any being lost
+ * and thus to manage flow control. Not serialized. Answers for the
+ * "instant".
+ */
+
+static void n_tty_set_room(struct tty_struct *tty)
+{
+ int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
+ /*
+ * If we are doing input canonicalization, and there are no
+ * pending newlines, let characters through without limit, so
+ * that erase characters will be handled. Other excess
+ * characters will be beeped.
+ */
+ if (left <= 0)
+ left = tty->icanon && !tty->canon_data;
+ tty->receive_room = left;
+}
+
+static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
{
if (tty->read_cnt < N_TTY_BUF_SIZE) {
tty->read_buf[tty->read_head] = c;
@@ -87,7 +112,7 @@ static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
}
}
-static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
+static void put_tty_queue(unsigned char c, struct tty_struct *tty)
{
unsigned long flags;
/*
@@ -136,6 +161,7 @@ static void reset_buffer_flags(struct tty_struct *tty)
spin_unlock_irqrestore(&tty->read_lock, flags);
tty->canon_head = tty->canon_data = tty->erasing = 0;
memset(&tty->read_flags, 0, sizeof tty->read_flags);
+ n_tty_set_room(tty);
check_unthrottle(tty);
}
@@ -838,30 +864,6 @@ send_signal:
put_tty_queue(c, tty);
}
-/**
- * n_tty_receive_room - receive space
- * @tty: terminal
- *
- * Called by the driver to find out how much data it is
- * permitted to feed to the line discipline without any being lost
- * and thus to manage flow control. Not serialized. Answers for the
- * "instant".
- */
-
-static int n_tty_receive_room(struct tty_struct *tty)
-{
- int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-
- /*
- * If we are doing input canonicalization, and there are no
- * pending newlines, let characters through without limit, so
- * that erase characters will be handled. Other excess
- * characters will be beeped.
- */
- if (left <= 0)
- left = tty->icanon && !tty->canon_data;
- return left;
-}
/**
* n_tty_write_wakeup - asynchronous I/O notifier
@@ -953,6 +955,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
tty->driver->flush_chars(tty);
}
+ n_tty_set_room(tty);
+
if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
@@ -964,7 +968,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
- if (n_tty_receive_room(tty) < TTY_THRESHOLD_THROTTLE) {
+ if (tty->receive_room < TTY_THRESHOLD_THROTTLE) {
/* check TTY_THROTTLED first so it indicates our state */
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
tty->driver->throttle)
@@ -999,6 +1003,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
tty->raw = 1;
tty->real_raw = 1;
+ n_tty_set_room(tty);
return;
}
if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
@@ -1051,6 +1056,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
else
tty->real_raw = 0;
}
+ n_tty_set_room(tty);
}
/**
@@ -1130,7 +1136,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
*
*/
-static inline int copy_from_read_buf(struct tty_struct *tty,
+static int copy_from_read_buf(struct tty_struct *tty,
unsigned char __user **b,
size_t *nr)
@@ -1308,6 +1314,7 @@ do_it_again:
retval = -ERESTARTSYS;
break;
}
+ n_tty_set_room(tty);
clear_bit(TTY_DONT_FLIP, &tty->flags);
timeout = schedule_timeout(timeout);
set_bit(TTY_DONT_FLIP, &tty->flags);
@@ -1401,6 +1408,8 @@ do_it_again:
} else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
goto do_it_again;
+ n_tty_set_room(tty);
+
return retval;
}
@@ -1553,7 +1562,6 @@ struct tty_ldisc tty_ldisc_N_TTY = {
normal_poll, /* poll */
NULL, /* hangup */
n_tty_receive_buf, /* receive_buf */
- n_tty_receive_room, /* receive_room */
n_tty_write_wakeup /* write_wakeup */
};
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 1af733d0732..3556ccd7757 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -557,13 +557,13 @@ pc_proc_infos(unsigned char *nvram, char *buffer, int *len,
(nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0);
PRINT_PROC("Floppy 0 type : ");
type = nvram[2] >> 4;
- if (type < sizeof (floppy_types) / sizeof (*floppy_types))
+ if (type < ARRAY_SIZE(floppy_types))
PRINT_PROC("%s\n", floppy_types[type]);
else
PRINT_PROC("%d (unknown)\n", type);
PRINT_PROC("Floppy 1 type : ");
type = nvram[2] & 0x0f;
- if (type < sizeof (floppy_types) / sizeof (*floppy_types))
+ if (type < ARRAY_SIZE(floppy_types))
PRINT_PROC("%s\n", floppy_types[type]);
else
PRINT_PROC("%d (unknown)\n", type);
@@ -843,8 +843,6 @@ static char *colors[] = {
"2", "4", "16", "256", "65536", "??", "??", "??"
};
-#define fieldsize(a) (sizeof(a)/sizeof(*a))
-
static int
atari_proc_infos(unsigned char *nvram, char *buffer, int *len,
off_t *begin, off_t offset, int size)
@@ -856,7 +854,7 @@ atari_proc_infos(unsigned char *nvram, char *buffer, int *len,
PRINT_PROC("Checksum status : %svalid\n", checksum ? "" : "not ");
PRINT_PROC("Boot preference : ");
- for (i = fieldsize(boot_prefs) - 1; i >= 0; --i) {
+ for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i) {
if (nvram[1] == boot_prefs[i].val) {
PRINT_PROC("%s\n", boot_prefs[i].name);
break;
@@ -878,12 +876,12 @@ atari_proc_infos(unsigned char *nvram, char *buffer, int *len,
return 1;
PRINT_PROC("OS language : ");
- if (nvram[6] < fieldsize(languages))
+ if (nvram[6] < ARRAY_SIZE(languages))
PRINT_PROC("%s\n", languages[nvram[6]]);
else
PRINT_PROC("%u (undefined)\n", nvram[6]);
PRINT_PROC("Keyboard language: ");
- if (nvram[7] < fieldsize(languages))
+ if (nvram[7] < ARRAY_SIZE(languages))
PRINT_PROC("%s\n", languages[nvram[7]]);
else
PRINT_PROC("%u (undefined)\n", nvram[7]);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index cf45b100eff..8a8ca32822b 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1007,8 +1007,9 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
static void rx_ready_async(MGSLPC_INFO *info, int tcd)
{
- unsigned char data, status;
+ unsigned char data, status, flag;
int fifo_count;
+ int work = 0;
struct tty_struct *tty = info->tty;
struct mgsl_icount *icount = &info->icount;
@@ -1023,20 +1024,16 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
fifo_count = 32;
} else
fifo_count = 32;
-
+
+ tty_buffer_request_room(tty, fifo_count);
/* Flush received async data to receive data buffer. */
while (fifo_count) {
data = read_reg(info, CHA + RXFIFO);
status = read_reg(info, CHA + RXFIFO);
fifo_count -= 2;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- break;
-
- *tty->flip.char_buf_ptr = data;
icount->rx++;
-
- *tty->flip.flag_buf_ptr = 0;
+ flag = TTY_NORMAL;
// if no frameing/crc error then save data
// BIT7:parity error
@@ -1055,26 +1052,23 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
status &= info->read_status_mask;
if (status & BIT7)
- *tty->flip.flag_buf_ptr = TTY_PARITY;
+ flag = TTY_PARITY;
else if (status & BIT6)
- *tty->flip.flag_buf_ptr = TTY_FRAME;
+ flag = TTY_FRAME;
}
-
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ work += tty_insert_flip_char(tty, data, flag);
}
issue_command(info, CHA, CMD_RXFIFO);
if (debug_level >= DEBUG_LEVEL_ISR) {
- printk("%s(%d):rx_ready_async count=%d\n",
- __FILE__,__LINE__,tty->flip.count);
+ printk("%s(%d):rx_ready_async",
+ __FILE__,__LINE__);
printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n",
__FILE__,__LINE__,icount->rx,icount->brk,
icount->parity,icount->frame,icount->overrun);
}
- if (tty->flip.count)
+ if (work)
tty_flip_buffer_push(tty);
}
@@ -4005,7 +3999,7 @@ BOOLEAN register_test(MGSLPC_INFO *info)
{
static unsigned char patterns[] =
{ 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f };
- static unsigned int count = sizeof(patterns) / sizeof(patterns[0]);
+ static unsigned int count = ARRAY_SIZE(patterns);
unsigned int i;
BOOLEAN rc = TRUE;
unsigned long flags;
@@ -4016,7 +4010,7 @@ BOOLEAN register_test(MGSLPC_INFO *info)
for (i = 0; i < count; i++) {
write_reg(info, XAD1, patterns[i]);
write_reg(info, XAD2, patterns[(i + 1) % count]);
- if ((read_reg(info, XAD1) != patterns[i]) ||
+ if ((read_reg(info, XAD1) != patterns[i]) ||
(read_reg(info, XAD2) != patterns[(i + 1) % count])) {
rc = FALSE;
break;
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 49f3997fd25..9b5a2c0e700 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -111,7 +111,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun
if (!to || tty->stopped)
return 0;
- c = to->ldisc.receive_room(to);
+ c = to->receive_room;
if (c > count)
c = count;
to->ldisc.receive_buf(to, buf, NULL, c);
@@ -126,7 +126,7 @@ static int pty_write_room(struct tty_struct *tty)
if (!to || tty->stopped)
return 0;
- return to->ldisc.receive_room(to);
+ return to->receive_room;
}
/*
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index d7d484024e2..7085a38532b 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -56,10 +56,6 @@
#include <linux/generic_serial.h>
#include <asm/uaccess.h>
-#if BITS_PER_LONG != 32
-# error FIXME: this driver only works on 32-bit platforms
-#endif
-
#include "linux_compat.h"
#include "typdef.h"
#include "pkt.h"
@@ -215,7 +211,7 @@ static int rio_poll = 1;
or less.... */
static int rio_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000};
-#define NR_RIO_ADDRS (sizeof(rio_probe_addrs)/sizeof (int))
+#define NR_RIO_ADDRS ARRAY_SIZE(rio_probe_addrs)
/* Set the mask to all-ones. This alas, only supports 32 interrupts.
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
index e42e7b50bf6..ddda9c14e05 100644
--- a/drivers/char/rio/riointr.c
+++ b/drivers/char/rio/riointr.c
@@ -38,6 +38,7 @@ static char *_riointr_c_sccs_ = "@(#)riointr.c 1.2";
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/tty.h>
+#include <linux/tty_flip.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/string.h>
@@ -560,6 +561,7 @@ struct Port * PortP;
struct PKT *PacketP;
register uint DataCnt;
uchar * ptr;
+ unsigned char *buf;
int copied =0;
static int intCount, RxIntCnt;
@@ -657,8 +659,7 @@ struct Port * PortP;
** and available space.
*/
- transCount = min_t(unsigned int, PacketP->len & PKT_LEN_MASK,
- TTY_FLIPBUF_SIZE - TtyP->flip.count);
+ transCount = tty_buffer_request_room(TtyP, PacketP->len & PKT_LEN_MASK);
rio_dprintk (RIO_DEBUG_REC, "port %d: Copy %d bytes\n",
PortP->PortNum, transCount);
/*
@@ -678,9 +679,8 @@ struct Port * PortP;
#endif
ptr = (uchar *) PacketP->data + PortP->RxDataStart;
- rio_memcpy_fromio (TtyP->flip.char_buf_ptr, ptr, transCount);
- memset(TtyP->flip.flag_buf_ptr, TTY_NORMAL, transCount);
-
+ tty_prepare_flip_string(TtyP, &buf, transCount);
+ rio_memcpy_fromio (buf, ptr, transCount);
#ifdef STATS
/*
** keep a count for statistical purposes
@@ -690,9 +690,6 @@ struct Port * PortP;
PortP->RxDataStart += transCount;
PacketP->len -= transCount;
copied += transCount;
- TtyP->flip.count += transCount;
- TtyP->flip.char_buf_ptr += transCount;
- TtyP->flip.flag_buf_ptr += transCount;
#ifdef ___DEBUG_IT___
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 55a3a0188ed..050e70ee592 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -46,6 +46,7 @@
#include <linux/major.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/tty_flip.h>
#include <asm/uaccess.h>
@@ -107,15 +108,15 @@ static struct riscom_port rc_port[RC_NBOARD * RC_NPORT];
/* RISCom/8 I/O ports addresses (without address translation) */
static unsigned short rc_ioport[] = {
-#if 1
+#if 1
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c,
-#else
+#else
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0c, 0x10,
0x11, 0x12, 0x18, 0x28, 0x31, 0x32, 0x39, 0x3a, 0x40, 0x41, 0x61, 0x62,
0x63, 0x64, 0x6b, 0x70, 0x71, 0x78, 0x7a, 0x7b, 0x7f, 0x100, 0x101
-#endif
+#endif
};
-#define RC_NIOPORT (sizeof(rc_ioport) / sizeof(rc_ioport[0]))
+#define RC_NIOPORT ARRAY_SIZE(rc_ioport)
static inline int rc_paranoia_check(struct riscom_port const * port,
@@ -354,28 +355,17 @@ static inline void rc_receive_exc(struct riscom_board const * bp)
struct riscom_port *port;
struct tty_struct *tty;
unsigned char status;
- unsigned char ch;
+ unsigned char ch, flag;
if (!(port = rc_get_port(bp, "Receive")))
return;
tty = port->tty;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- printk(KERN_WARNING "rc%d: port %d: Working around flip "
- "buffer overflow.\n",
- board_No(bp), port_No(port));
- return;
- }
#ifdef RC_REPORT_OVERRUN
status = rc_in(bp, CD180_RCSR);
- if (status & RCSR_OE) {
+ if (status & RCSR_OE)
port->overrun++;
-#if 0
- printk(KERN_ERR "rc%d: port %d: Overrun. Total %ld overruns\n",
- board_No(bp), port_No(port), port->overrun);
-#endif
- }
status &= port->mark_mask;
#else
status = rc_in(bp, CD180_RCSR) & port->mark_mask;
@@ -393,25 +383,24 @@ static inline void rc_receive_exc(struct riscom_board const * bp)
} else if (status & RCSR_BREAK) {
printk(KERN_INFO "rc%d: port %d: Handling break...\n",
board_No(bp), port_No(port));
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+ flag = TTY_BREAK;
if (port->flags & ASYNC_SAK)
do_SAK(tty);
} else if (status & RCSR_PE)
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+ flag = TTY_PARITY;
else if (status & RCSR_FE)
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+ flag = TTY_FRAME;
else if (status & RCSR_OE)
- *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ flag = TTY_OVERRUN;
else
- *tty->flip.flag_buf_ptr++ = 0;
+ flag = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = ch;
- tty->flip.count++;
- schedule_delayed_work(&tty->flip.work, 1);
+ tty_insert_flip_char(tty, ch, flag);
+ tty_flip_buffer_push(tty);
}
static inline void rc_receive(struct riscom_board const * bp)
@@ -432,17 +421,15 @@ static inline void rc_receive(struct riscom_board const * bp)
#endif
while (count--) {
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ if (tty_buffer_request_room(tty, 1) == 0) {
printk(KERN_WARNING "rc%d: port %d: Working around "
"flip buffer overflow.\n",
board_No(bp), port_No(port));
break;
}
- *tty->flip.char_buf_ptr++ = rc_in(bp, CD180_RDR);
- *tty->flip.flag_buf_ptr++ = 0;
- tty->flip.count++;
+ tty_insert_flip_char(tty, rc_in(bp, CD180_RDR), TTY_NORMAL);
}
- schedule_delayed_work(&tty->flip.work, 1);
+ tty_flip_buffer_push(tty);
}
static inline void rc_transmit(struct riscom_board const * bp)
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index d3bc731fbb2..0949dcef069 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -325,19 +325,16 @@ static void rp_do_receive(struct r_port *info,
{
unsigned int CharNStat;
int ToRecv, wRecv, space = 0, count;
- unsigned char *cbuf;
- char *fbuf;
+ unsigned char *cbuf, *chead;
+ char *fbuf, *fhead;
struct tty_ldisc *ld;
ld = tty_ldisc_ref(tty);
ToRecv = sGetRxCnt(cp);
- if (ld)
- space = ld->receive_room(tty);
+ space = tty->receive_room;
if (space > 2 * TTY_FLIPBUF_SIZE)
space = 2 * TTY_FLIPBUF_SIZE;
- cbuf = tty->flip.char_buf;
- fbuf = tty->flip.flag_buf;
count = 0;
#ifdef ROCKET_DEBUG_INTR
printk(KERN_INFO "rp_do_receive(%d, %d)...", ToRecv, space);
@@ -350,9 +347,13 @@ static void rp_do_receive(struct r_port *info,
if (ToRecv > space)
ToRecv = space;
+ ToRecv = tty_prepare_flip_string_flags(tty, &chead, &fhead, ToRecv);
if (ToRecv <= 0)
goto done;
+ cbuf = chead;
+ fbuf = fhead;
+
/*
* if status indicates there are errored characters in the
* FIFO, then enter status mode (a word in FIFO holds
@@ -399,7 +400,7 @@ static void rp_do_receive(struct r_port *info,
else if (CharNStat & STMRCVROVRH)
*fbuf++ = TTY_OVERRUN;
else
- *fbuf++ = 0;
+ *fbuf++ = TTY_NORMAL;
*cbuf++ = CharNStat & 0xff;
count++;
ToRecv--;
@@ -426,13 +427,13 @@ static void rp_do_receive(struct r_port *info,
sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
if (ToRecv & 1)
cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
- memset(fbuf, 0, ToRecv);
+ memset(fbuf, TTY_NORMAL, ToRecv);
cbuf += ToRecv;
fbuf += ToRecv;
count += ToRecv;
}
/* Push the data up to the tty layer */
- ld->receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count);
+ ld->receive_buf(tty, cbuf, fbuf, count);
done:
tty_ldisc_deref(ld);
}
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
index 3df7a574267..2e308657f6f 100644
--- a/drivers/char/s3c2410-rtc.c
+++ b/drivers/char/s3c2410-rtc.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
+#include <linux/clk.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
@@ -33,7 +34,6 @@
#include <asm/mach/time.h>
-#include <asm/hardware/clock.h>
#include <asm/arch/regs-rtc.h>
/* need this for the RTC_AF definitions */
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index 5b187c895c1..71093a9fc46 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -275,7 +275,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
int paste_selection(struct tty_struct *tty)
{
struct vc_data *vc = (struct vc_data *)tty->driver_data;
- int pasted = 0, count;
+ int pasted = 0;
+ unsigned int count;
struct tty_ldisc *ld;
DECLARE_WAITQUEUE(wait, current);
@@ -293,7 +294,7 @@ int paste_selection(struct tty_struct *tty)
continue;
}
count = sel_buffer_lth - pasted;
- count = min(count, tty->ldisc.receive_room(tty));
+ count = min(count, tty->receive_room);
tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count);
pasted += count;
}
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index dda30e42ec7..80a5b840e22 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -194,11 +194,6 @@ static inline void a2232_receive_char(struct a2232_port *port, int ch, int err)
*/
struct tty_struct *tty = port->gs.tty;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- return;
-
- tty->flip.count++;
-
#if 0
switch(err) {
case TTY_BREAK:
@@ -212,8 +207,7 @@ static inline void a2232_receive_char(struct a2232_port *port, int ch, int err)
}
#endif
- *tty->flip.flag_buf_ptr++ = err;
- *tty->flip.char_buf_ptr++ = ch;
+ tty_insert_flip_char(tty, ch, err);
tty_flip_buffer_push(tty);
}
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index c2deac968bd..f36342ae8e7 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -117,7 +117,7 @@ struct cyclades_port cy_port[] = {
{-1 }, /* ttyS2 */
{-1 }, /* ttyS3 */
};
-#define NR_PORTS (sizeof(cy_port)/sizeof(struct cyclades_port))
+#define NR_PORTS ARRAY_SIZE(cy_port)
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
@@ -422,45 +422,35 @@ cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp)
base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
return IRQ_HANDLED;
}
- if (tty->flip.count < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
+ if (tty_buffer_request_room(tty, 1) != 0){
if (err & info->read_status_mask){
if(err & CyBREAK){
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_BREAK);
if (info->flags & ASYNC_SAK){
do_SAK(tty);
}
}else if(err & CyFRAME){
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_FRAME);
}else if(err & CyPARITY){
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_PARITY);
}else if(err & CyOVERRUN){
- *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
/*
If the flip buffer itself is
overflowing, we still loose
the next incoming character.
*/
- if(tty->flip.count < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
- }
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ }
/* These two conditions may imply */
/* a normal read should be done. */
/* else if(data & CyTIMEOUT) */
/* else if(data & CySPECHAR) */
}else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_NORMAL);
}
}else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
}
}else{
/* there was a software buffer overrun
@@ -692,12 +682,7 @@ cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
#endif
while(char_count--){
data = base_addr[CyRDR];
- if (tty->flip.count >= TTY_FLIPBUF_SIZE){
- continue;
- }
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
#ifdef CYCLOM_16Y_HACK
udelay(10L);
#endif
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 51a07370e63..f8dd8527c6a 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -471,7 +471,6 @@ struct sonypi_keypress {
static struct sonypi_device {
struct pci_dev *dev;
- struct platform_device *pdev;
u16 irq;
u16 bits;
u16 ioport1;
@@ -511,6 +510,11 @@ static struct sonypi_device {
#define SONYPI_ACPI_ACTIVE 0
#endif /* CONFIG_ACPI */
+#ifdef CONFIG_ACPI
+static struct acpi_device *sonypi_acpi_device;
+static int acpi_enabled;
+#endif
+
static int sonypi_ec_write(u8 addr, u8 value)
{
#ifdef CONFIG_ACPI_EC
@@ -864,6 +868,11 @@ found:
if (useinput)
sonypi_report_input_event(event);
+#ifdef CONFIG_ACPI
+ if (acpi_enabled)
+ acpi_bus_generate_event(sonypi_acpi_device, 1, event);
+#endif
+
kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
wake_up_interruptible(&sonypi_device.fifo_proc_list);
@@ -1165,45 +1174,38 @@ static int sonypi_disable(void)
return 0;
}
-#ifdef CONFIG_PM
-static int old_camera_power;
-
-static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_ACPI
+static int sonypi_acpi_add(struct acpi_device *device)
{
- old_camera_power = sonypi_device.camera_power;
- sonypi_disable();
-
+ sonypi_acpi_device = device;
+ strcpy(acpi_device_name(device), "Sony laptop hotkeys");
+ strcpy(acpi_device_class(device), "sony/hotkey");
return 0;
}
-static int sonypi_resume(struct platform_device *dev)
+static int sonypi_acpi_remove(struct acpi_device *device, int type)
{
- sonypi_enable(old_camera_power);
+ sonypi_acpi_device = NULL;
return 0;
}
-#endif
-
-static void sonypi_shutdown(struct platform_device *dev)
-{
- sonypi_disable();
-}
-static struct platform_driver sonypi_driver = {
-#ifdef CONFIG_PM
- .suspend = sonypi_suspend,
- .resume = sonypi_resume,
-#endif
- .shutdown = sonypi_shutdown,
- .driver = {
- .name = "sonypi",
+static struct acpi_driver sonypi_acpi_driver = {
+ .name = "sonypi",
+ .class = "hkey",
+ .ids = "SNY6001",
+ .ops = {
+ .add = sonypi_acpi_add,
+ .remove = sonypi_acpi_remove,
},
};
+#endif
static int __devinit sonypi_create_input_devices(void)
{
struct input_dev *jog_dev;
struct input_dev *key_dev;
int i;
+ int error;
sonypi_device.input_jog_dev = jog_dev = input_allocate_device();
if (!jog_dev)
@@ -1219,9 +1221,8 @@ static int __devinit sonypi_create_input_devices(void)
sonypi_device.input_key_dev = key_dev = input_allocate_device();
if (!key_dev) {
- input_free_device(jog_dev);
- sonypi_device.input_jog_dev = NULL;
- return -ENOMEM;
+ error = -ENOMEM;
+ goto err_free_jogdev;
}
key_dev->name = "Sony Vaio Keys";
@@ -1234,56 +1235,122 @@ static int __devinit sonypi_create_input_devices(void)
if (sonypi_inputkeys[i].inputev)
set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit);
- input_register_device(jog_dev);
- input_register_device(key_dev);
+ error = input_register_device(jog_dev);
+ if (error)
+ goto err_free_keydev;
+
+ error = input_register_device(key_dev);
+ if (error)
+ goto err_unregister_jogdev;
return 0;
+
+ err_unregister_jogdev:
+ input_unregister_device(jog_dev);
+ /* Set to NULL so we don't free it again below */
+ jog_dev = NULL;
+ err_free_keydev:
+ input_free_device(key_dev);
+ sonypi_device.input_key_dev = NULL;
+ err_free_jogdev:
+ input_free_device(jog_dev);
+ sonypi_device.input_jog_dev = NULL;
+
+ return error;
}
-static int __devinit sonypi_probe(void)
+static int __devinit sonypi_setup_ioports(struct sonypi_device *dev,
+ const struct sonypi_ioport_list *ioport_list)
{
- int i, ret;
- struct sonypi_ioport_list *ioport_list;
- struct sonypi_irq_list *irq_list;
- struct pci_dev *pcidev;
+ while (ioport_list->port1) {
- if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
- sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
- else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
- sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
- else
- sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
+ if (request_region(ioport_list->port1,
+ sonypi_device.region_size,
+ "Sony Programable I/O Device")) {
+ dev->ioport1 = ioport_list->port1;
+ dev->ioport2 = ioport_list->port2;
+ return 0;
+ }
+ ioport_list++;
+ }
- sonypi_device.dev = pcidev;
+ return -EBUSY;
+}
+
+static int __devinit sonypi_setup_irq(struct sonypi_device *dev,
+ const struct sonypi_irq_list *irq_list)
+{
+ while (irq_list->irq) {
+
+ if (!request_irq(irq_list->irq, sonypi_irq,
+ SA_SHIRQ, "sonypi", sonypi_irq)) {
+ dev->irq = irq_list->irq;
+ dev->bits = irq_list->bits;
+ return 0;
+ }
+ irq_list++;
+ }
+
+ return -EBUSY;
+}
+
+static void __devinit sonypi_display_info(void)
+{
+ printk(KERN_INFO "sonypi: detected type%d model, "
+ "verbose = %d, fnkeyinit = %s, camera = %s, "
+ "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
+ sonypi_device.model,
+ verbose,
+ fnkeyinit ? "on" : "off",
+ camera ? "on" : "off",
+ compat ? "on" : "off",
+ mask,
+ useinput ? "on" : "off",
+ SONYPI_ACPI_ACTIVE ? "on" : "off");
+ printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
+ sonypi_device.irq,
+ sonypi_device.ioport1, sonypi_device.ioport2);
+
+ if (minor == -1)
+ printk(KERN_INFO "sonypi: device allocated minor is %d\n",
+ sonypi_misc_device.minor);
+}
+
+static int __devinit sonypi_probe(struct platform_device *dev)
+{
+ const struct sonypi_ioport_list *ioport_list;
+ const struct sonypi_irq_list *irq_list;
+ struct pci_dev *pcidev;
+ int error;
spin_lock_init(&sonypi_device.fifo_lock);
sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
&sonypi_device.fifo_lock);
if (IS_ERR(sonypi_device.fifo)) {
printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
- ret = PTR_ERR(sonypi_device.fifo);
- goto out_fifo;
+ return PTR_ERR(sonypi_device.fifo);
}
init_waitqueue_head(&sonypi_device.fifo_proc_list);
init_MUTEX(&sonypi_device.lock);
sonypi_device.bluetooth_power = -1;
+ if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
+ else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
+ else
+ sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
+
if (pcidev && pci_enable_device(pcidev)) {
printk(KERN_ERR "sonypi: pci_enable_device failed\n");
- ret = -EIO;
- goto out_pcienable;
- }
-
- if (minor != -1)
- sonypi_misc_device.minor = minor;
- if ((ret = misc_register(&sonypi_misc_device))) {
- printk(KERN_ERR "sonypi: misc_register failed\n");
- goto out_miscreg;
+ error = -EIO;
+ goto err_put_pcidev;
}
+ sonypi_device.dev = pcidev;
if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) {
ioport_list = sonypi_type1_ioport_list;
@@ -1302,43 +1369,36 @@ static int __devinit sonypi_probe(void)
irq_list = sonypi_type3_irq_list;
}
- for (i = 0; ioport_list[i].port1; i++) {
- if (request_region(ioport_list[i].port1,
- sonypi_device.region_size,
- "Sony Programable I/O Device")) {
- /* get the ioport */
- sonypi_device.ioport1 = ioport_list[i].port1;
- sonypi_device.ioport2 = ioport_list[i].port2;
- break;
- }
- }
- if (!sonypi_device.ioport1) {
- printk(KERN_ERR "sonypi: request_region failed\n");
- ret = -ENODEV;
- goto out_reqreg;
+ error = sonypi_setup_ioports(&sonypi_device, ioport_list);
+ if (error) {
+ printk(KERN_ERR "sonypi: failed to request ioports\n");
+ goto err_disable_pcidev;
}
- for (i = 0; irq_list[i].irq; i++) {
-
- sonypi_device.irq = irq_list[i].irq;
- sonypi_device.bits = irq_list[i].bits;
-
- if (!request_irq(sonypi_device.irq, sonypi_irq,
- SA_SHIRQ, "sonypi", sonypi_irq))
- break;
+ error = sonypi_setup_irq(&sonypi_device, irq_list);
+ if (error) {
+ printk(KERN_ERR "sonypi: request_irq failed\n");
+ goto err_free_ioports;
}
- if (!irq_list[i].irq) {
- printk(KERN_ERR "sonypi: request_irq failed\n");
- ret = -ENODEV;
- goto out_reqirq;
+ if (minor != -1)
+ sonypi_misc_device.minor = minor;
+ error = misc_register(&sonypi_misc_device);
+ if (error) {
+ printk(KERN_ERR "sonypi: misc_register failed\n");
+ goto err_free_irq;
}
+ sonypi_display_info();
+
if (useinput) {
- ret = sonypi_create_input_devices();
- if (ret)
- goto out_inputdevices;
+ error = sonypi_create_input_devices();
+ if (error) {
+ printk(KERN_ERR
+ "sonypi: failed to create input devices\n");
+ goto err_miscdev_unregister;
+ }
spin_lock_init(&sonypi_device.input_fifo_lock);
sonypi_device.input_fifo =
@@ -1346,91 +1406,104 @@ static int __devinit sonypi_probe(void)
&sonypi_device.input_fifo_lock);
if (IS_ERR(sonypi_device.input_fifo)) {
printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
- ret = PTR_ERR(sonypi_device.input_fifo);
- goto out_infifo;
+ error = PTR_ERR(sonypi_device.input_fifo);
+ goto err_inpdev_unregister;
}
INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL);
}
- sonypi_device.pdev = platform_device_register_simple("sonypi", -1,
- NULL, 0);
- if (IS_ERR(sonypi_device.pdev)) {
- ret = PTR_ERR(sonypi_device.pdev);
- goto out_platformdev;
- }
-
sonypi_enable(0);
- printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver"
- "v%s.\n", SONYPI_DRIVER_VERSION);
- printk(KERN_INFO "sonypi: detected type%d model, "
- "verbose = %d, fnkeyinit = %s, camera = %s, "
- "compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
- sonypi_device.model,
- verbose,
- fnkeyinit ? "on" : "off",
- camera ? "on" : "off",
- compat ? "on" : "off",
- mask,
- useinput ? "on" : "off",
- SONYPI_ACPI_ACTIVE ? "on" : "off");
- printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
- sonypi_device.irq,
- sonypi_device.ioport1, sonypi_device.ioport2);
-
- if (minor == -1)
- printk(KERN_INFO "sonypi: device allocated minor is %d\n",
- sonypi_misc_device.minor);
-
return 0;
-out_platformdev:
- kfifo_free(sonypi_device.input_fifo);
-out_infifo:
+ err_inpdev_unregister:
input_unregister_device(sonypi_device.input_key_dev);
input_unregister_device(sonypi_device.input_jog_dev);
-out_inputdevices:
+ err_miscdev_unregister:
+ misc_deregister(&sonypi_misc_device);
+ err_free_irq:
free_irq(sonypi_device.irq, sonypi_irq);
-out_reqirq:
+ err_free_ioports:
release_region(sonypi_device.ioport1, sonypi_device.region_size);
-out_reqreg:
- misc_deregister(&sonypi_misc_device);
-out_miscreg:
+ err_disable_pcidev:
if (pcidev)
pci_disable_device(pcidev);
-out_pcienable:
+ err_put_pcidev:
+ pci_dev_put(pcidev);
kfifo_free(sonypi_device.fifo);
-out_fifo:
- pci_dev_put(sonypi_device.dev);
- return ret;
+
+ return error;
}
-static void __devexit sonypi_remove(void)
+static int __devexit sonypi_remove(struct platform_device *dev)
{
sonypi_disable();
synchronize_sched(); /* Allow sonypi interrupt to complete. */
flush_scheduled_work();
- platform_device_unregister(sonypi_device.pdev);
-
if (useinput) {
input_unregister_device(sonypi_device.input_key_dev);
input_unregister_device(sonypi_device.input_jog_dev);
kfifo_free(sonypi_device.input_fifo);
}
+ misc_deregister(&sonypi_misc_device);
+
free_irq(sonypi_device.irq, sonypi_irq);
release_region(sonypi_device.ioport1, sonypi_device.region_size);
- misc_deregister(&sonypi_misc_device);
- if (sonypi_device.dev)
+
+ if (sonypi_device.dev) {
pci_disable_device(sonypi_device.dev);
+ pci_dev_put(sonypi_device.dev);
+ }
+
kfifo_free(sonypi_device.fifo);
- pci_dev_put(sonypi_device.dev);
- printk(KERN_INFO "sonypi: removed.\n");
+
+ return 0;
}
+#ifdef CONFIG_PM
+static int old_camera_power;
+
+static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
+{
+ old_camera_power = sonypi_device.camera_power;
+ sonypi_disable();
+
+ return 0;
+}
+
+static int sonypi_resume(struct platform_device *dev)
+{
+ sonypi_enable(old_camera_power);
+ return 0;
+}
+#else
+#define sonypi_suspend NULL
+#define sonypi_resume NULL
+#endif
+
+static void sonypi_shutdown(struct platform_device *dev)
+{
+ sonypi_disable();
+}
+
+static struct platform_driver sonypi_driver = {
+ .driver = {
+ .name = "sonypi",
+ .owner = THIS_MODULE,
+ },
+ .probe = sonypi_probe,
+ .remove = __devexit_p(sonypi_remove),
+ .shutdown = sonypi_shutdown,
+ .suspend = sonypi_suspend,
+ .resume = sonypi_resume,
+};
+
+static struct platform_device *sonypi_platform_device;
+
static struct dmi_system_id __initdata sonypi_dmi_table[] = {
{
.ident = "Sony Vaio",
@@ -1451,26 +1524,52 @@ static struct dmi_system_id __initdata sonypi_dmi_table[] = {
static int __init sonypi_init(void)
{
- int ret;
+ int error;
+
+ printk(KERN_INFO
+ "sonypi: Sony Programmable I/O Controller Driver v%s.\n",
+ SONYPI_DRIVER_VERSION);
if (!dmi_check_system(sonypi_dmi_table))
return -ENODEV;
- ret = platform_driver_register(&sonypi_driver);
- if (ret)
- return ret;
+ error = platform_driver_register(&sonypi_driver);
+ if (error)
+ return error;
- ret = sonypi_probe();
- if (ret)
- platform_driver_unregister(&sonypi_driver);
+ sonypi_platform_device = platform_device_alloc("sonypi", -1);
+ if (!sonypi_platform_device) {
+ error = -ENOMEM;
+ goto err_driver_unregister;
+ }
- return ret;
+ error = platform_device_add(sonypi_platform_device);
+ if (error)
+ goto err_free_device;
+
+#ifdef CONFIG_ACPI
+ if (acpi_bus_register_driver(&sonypi_acpi_driver) > 0)
+ acpi_enabled = 1;
+#endif
+
+ return 0;
+
+ err_free_device:
+ platform_device_put(sonypi_platform_device);
+ err_driver_unregister:
+ platform_driver_unregister(&sonypi_driver);
+ return error;
}
static void __exit sonypi_exit(void)
{
+#ifdef CONFIG_ACPI
+ if (acpi_enabled)
+ acpi_bus_unregister_driver(&sonypi_acpi_driver);
+#endif
+ platform_device_unregister(sonypi_platform_device);
platform_driver_unregister(&sonypi_driver);
- sonypi_remove();
+ printk(KERN_INFO "sonypi: removed.\n");
}
module_init(sonypi_init);
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 0bbfce43031..0a574bdbce3 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -85,6 +85,7 @@
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/tty.h>
+#include <linux/tty_flip.h>
#include <linux/mm.h>
#include <linux/serial.h>
#include <linux/fcntl.h>
@@ -665,7 +666,7 @@ static inline void sx_receive_exc(struct specialix_board * bp)
struct specialix_port *port;
struct tty_struct *tty;
unsigned char status;
- unsigned char ch;
+ unsigned char ch, flag;
func_enter();
@@ -676,8 +677,6 @@ static inline void sx_receive_exc(struct specialix_board * bp)
return;
}
tty = port->tty;
- dprintk (SX_DEBUG_RX, "port: %p count: %d BUFF_SIZE: %d\n",
- port, tty->flip.count, TTY_FLIPBUF_SIZE);
status = sx_in(bp, CD186x_RCSR);
@@ -691,7 +690,7 @@ static inline void sx_receive_exc(struct specialix_board * bp)
/* This flip buffer check needs to be below the reading of the
status register to reset the chip's IRQ.... */
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ if (tty_buffer_request_room(tty, 1) == 0) {
dprintk(SX_DEBUG_FIFO, "sx%d: port %d: Working around flip buffer overflow.\n",
board_No(bp), port_No(port));
func_exit();
@@ -712,26 +711,24 @@ static inline void sx_receive_exc(struct specialix_board * bp)
} else if (status & RCSR_BREAK) {
dprintk(SX_DEBUG_RX, "sx%d: port %d: Handling break...\n",
board_No(bp), port_No(port));
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+ flag = TTY_BREAK;
if (port->flags & ASYNC_SAK)
do_SAK(tty);
} else if (status & RCSR_PE)
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+ flag = TTY_PARITY;
else if (status & RCSR_FE)
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+ flag = TTY_FRAME;
else if (status & RCSR_OE)
- *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ flag = TTY_OVERRUN;
else
- *tty->flip.flag_buf_ptr++ = 0;
-
- *tty->flip.char_buf_ptr++ = ch;
- tty->flip.count++;
- schedule_delayed_work(&tty->flip.work, 1);
+ flag = TTY_NORMAL;
+ if(tty_insert_flip_char(tty, ch, flag))
+ tty_flip_buffer_push(tty);
func_exit();
}
@@ -755,18 +752,11 @@ static inline void sx_receive(struct specialix_board * bp)
dprintk (SX_DEBUG_RX, "port: %p: count: %d\n", port, count);
port->hits[count > 8 ? 9 : count]++;
- while (count--) {
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n",
- board_No(bp), port_No(port));
- break;
- }
- *tty->flip.char_buf_ptr++ = sx_in(bp, CD186x_RDR);
- *tty->flip.flag_buf_ptr++ = 0;
- tty->flip.count++;
- }
- schedule_delayed_work(&tty->flip.work, 1);
+ tty_buffer_request_room(tty, count);
+ while (count--)
+ tty_insert_flip_char(tty, sx_in(bp, CD186x_RDR), TTY_NORMAL);
+ tty_flip_buffer_push(tty);
func_exit();
}
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 95af2a94159..0e20780d4a2 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -103,7 +103,7 @@ static stlconf_t stl_brdconf[] = {
/*{ BRD_EASYIO, 0x2a0, 0, 0, 10, 0 },*/
};
-static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
+static int stl_nrbrds = ARRAY_SIZE(stl_brdconf);
/*****************************************************************************/
@@ -424,7 +424,7 @@ static stlpcibrd_t stl_pcibrds[] = {
{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, BRD_ECHPCI },
};
-static int stl_nrpcibrds = sizeof(stl_pcibrds) / sizeof(stlpcibrd_t);
+static int stl_nrpcibrds = ARRAY_SIZE(stl_pcibrds);
#endif
@@ -704,7 +704,7 @@ static unsigned int sc26198_baudtable[] = {
230400, 460800, 921600
};
-#define SC26198_NRBAUDS (sizeof(sc26198_baudtable) / sizeof(unsigned int))
+#define SC26198_NRBAUDS ARRAY_SIZE(sc26198_baudtable)
/*****************************************************************************/
@@ -901,7 +901,7 @@ static unsigned long stl_atol(char *str)
static int stl_parsebrd(stlconf_t *confp, char **argp)
{
char *sp;
- int nrbrdnames, i;
+ int i;
#ifdef DEBUG
printk("stl_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp);
@@ -913,14 +913,13 @@ static int stl_parsebrd(stlconf_t *confp, char **argp)
for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
*sp = TOLOWER(*sp);
- nrbrdnames = sizeof(stl_brdstr) / sizeof(stlbrdtype_t);
- for (i = 0; (i < nrbrdnames); i++) {
+ for (i = 0; i < ARRAY_SIZE(stl_brdstr); i++) {
if (strcmp(stl_brdstr[i].name, argp[0]) == 0)
break;
}
- if (i >= nrbrdnames) {
+ if (i == ARRAY_SIZE(stl_brdstr)) {
printk("STALLION: unknown board name, %s?\n", argp[0]);
- return(0);
+ return 0;
}
confp->brdtype = stl_brdstr[i].type;
@@ -2902,7 +2901,8 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
if (portp->tty != (struct tty_struct *) NULL) {
if (portp->tty->driver_data == portp) {
portp->stats.ttystate = portp->tty->flags;
- portp->stats.rxbuffered = portp->tty->flip.count;
+ /* No longer available as a statistic */
+ portp->stats.rxbuffered = 1; /*portp->tty->flip.count; */
if (portp->tty->termios != (struct termios *) NULL) {
portp->stats.cflags = portp->tty->termios->c_cflag;
portp->stats.iflags = portp->tty->termios->c_iflag;
@@ -4046,9 +4046,7 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) {
outb((RDCR + portp->uartaddr), ioaddr);
len = inb(ioaddr + EREG_DATA);
- if ((tty == (struct tty_struct *) NULL) ||
- (tty->flip.char_buf_ptr == (char *) NULL) ||
- ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+ if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
len = MIN(len, sizeof(stl_unwanted));
outb((RDSR + portp->uartaddr), ioaddr);
insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
@@ -4057,12 +4055,10 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
} else {
len = MIN(len, buflen);
if (len > 0) {
+ unsigned char *ptr;
outb((RDSR + portp->uartaddr), ioaddr);
- insb((ioaddr + EREG_DATA), tty->flip.char_buf_ptr, len);
- memset(tty->flip.flag_buf_ptr, 0, len);
- tty->flip.flag_buf_ptr += len;
- tty->flip.char_buf_ptr += len;
- tty->flip.count += len;
+ tty_prepare_flip_string(tty, &ptr, len);
+ insb((ioaddr + EREG_DATA), ptr, len);
tty_schedule_flip(tty);
portp->stats.rxtotal += len;
}
@@ -4086,8 +4082,7 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
portp->stats.txxoff++;
goto stl_rxalldone;
}
- if ((tty != (struct tty_struct *) NULL) &&
- ((portp->rxignoremsk & status) == 0)) {
+ if (tty != NULL && (portp->rxignoremsk & status) == 0) {
if (portp->rxmarkmsk & status) {
if (status & ST_BREAK) {
status = TTY_BREAK;
@@ -4107,14 +4102,8 @@ static void stl_cd1400rxisr(stlpanel_t *panelp, int ioaddr)
} else {
status = 0;
}
- if (tty->flip.char_buf_ptr != (char *) NULL) {
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- *tty->flip.flag_buf_ptr++ = status;
- *tty->flip.char_buf_ptr++ = ch;
- tty->flip.count++;
- }
- tty_schedule_flip(tty);
- }
+ tty_insert_flip_char(tty, ch, status);
+ tty_schedule_flip(tty);
}
} else {
printk("STALLION: bad RX interrupt ack value=%x\n", ioack);
@@ -5013,9 +5002,7 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
len = inb(ioaddr + XP_DATA) + 1;
if ((iack & IVR_TYPEMASK) == IVR_RXDATA) {
- if ((tty == (struct tty_struct *) NULL) ||
- (tty->flip.char_buf_ptr == (char *) NULL) ||
- ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+ if (tty == NULL || (buflen = tty_buffer_request_room(tty, len)) == 0) {
len = MIN(len, sizeof(stl_unwanted));
outb(GRXFIFO, (ioaddr + XP_ADDR));
insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
@@ -5024,12 +5011,10 @@ static void stl_sc26198rxisr(stlport_t *portp, unsigned int iack)
} else {
len = MIN(len, buflen);
if (len > 0) {
+ unsigned char *ptr;
outb(GRXFIFO, (ioaddr + XP_ADDR));
- insb((ioaddr + XP_DATA), tty->flip.char_buf_ptr, len);
- memset(tty->flip.flag_buf_ptr, 0, len);
- tty->flip.flag_buf_ptr += len;
- tty->flip.char_buf_ptr += len;
- tty->flip.count += len;
+ tty_prepare_flip_string(tty, &ptr, len);
+ insb((ioaddr + XP_DATA), ptr, len);
tty_schedule_flip(tty);
portp->stats.rxtotal += len;
}
@@ -5097,14 +5082,8 @@ static inline void stl_sc26198rxbadch(stlport_t *portp, unsigned char status, ch
status = 0;
}
- if (tty->flip.char_buf_ptr != (char *) NULL) {
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- *tty->flip.flag_buf_ptr++ = status;
- *tty->flip.char_buf_ptr++ = ch;
- tty->flip.count++;
- }
- tty_schedule_flip(tty);
- }
+ tty_insert_flip_char(tty, ch, status);
+ tty_schedule_flip(tty);
if (status == 0)
portp->stats.rxtotal++;
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 3ad758a9a1d..64bf89cb574 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -345,9 +345,9 @@ static int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
0xc8000, 0xd8000, 0xe8000, 0xa0000};
static int si1_probe_addrs[]= { 0xd0000};
-#define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int))
-#define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int))
-#define NR_SI1_ADDRS (sizeof(si1_probe_addrs)/sizeof (int))
+#define NR_SX_ADDRS ARRAY_SIZE(sx_probe_addrs)
+#define NR_SI_ADDRS ARRAY_SIZE(si_probe_addrs)
+#define NR_SI1_ADDRS ARRAY_SIZE(si1_probe_addrs)
/* Set the mask to all-ones. This alas, only supports 32 interrupts.
@@ -1085,6 +1085,7 @@ static inline void sx_receive_chars (struct sx_port *port)
int rx_op;
struct tty_struct *tty;
int copied=0;
+ unsigned char *rp;
func_enter2 ();
tty = port->gs.tty;
@@ -1095,8 +1096,8 @@ static inline void sx_receive_chars (struct sx_port *port)
sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c);
/* Don't copy more bytes than there is room for in the buffer */
- if (tty->flip.count + c > TTY_FLIPBUF_SIZE)
- c = TTY_FLIPBUF_SIZE - tty->flip.count;
+
+ c = tty_prepare_flip_string(tty, &rp, c);
sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
@@ -1111,14 +1112,8 @@ static inline void sx_receive_chars (struct sx_port *port)
sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c,
read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op),
CHAN_OFFSET(port, hi_rxbuf));
- memcpy_fromio (tty->flip.char_buf_ptr,
+ memcpy_fromio (rp,
port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c);
- memset(tty->flip.flag_buf_ptr, TTY_NORMAL, c);
-
- /* Update the kernel buffer end */
- tty->flip.count += c;
- tty->flip.char_buf_ptr += c;
- tty->flip.flag_buf_ptr += c;
/* This one last. ( Not essential.)
It allows the card to start putting more data into the buffer!
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 62aa0e534a6..9f1b466c4f8 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1467,6 +1467,7 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info )
{
int Fifocount;
u16 status;
+ int work = 0;
unsigned char DataByte;
struct tty_struct *tty = info->tty;
struct mgsl_icount *icount = &info->icount;
@@ -1487,6 +1488,8 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info )
/* flush the receive FIFO */
while( (Fifocount = (usc_InReg(info,RICR) >> 8)) ) {
+ int flag;
+
/* read one byte from RxFIFO */
outw( (inw(info->io_base + CCAR) & 0x0780) | (RDR+LSBONLY),
info->io_base + CCAR );
@@ -1498,13 +1501,9 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info )
RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) )
usc_UnlatchRxstatusBits(info,RXSTATUS_ALL);
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- continue;
-
- *tty->flip.char_buf_ptr = DataByte;
icount->rx++;
- *tty->flip.flag_buf_ptr = 0;
+ flag = 0;
if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR +
RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) {
printk("rxerr=%04X\n",status);
@@ -1530,41 +1529,31 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info )
status &= info->read_status_mask;
if (status & RXSTATUS_BREAK_RECEIVED) {
- *tty->flip.flag_buf_ptr = TTY_BREAK;
+ flag = TTY_BREAK;
if (info->flags & ASYNC_SAK)
do_SAK(tty);
} else if (status & RXSTATUS_PARITY_ERROR)
- *tty->flip.flag_buf_ptr = TTY_PARITY;
+ flag = TTY_PARITY;
else if (status & RXSTATUS_FRAMING_ERROR)
- *tty->flip.flag_buf_ptr = TTY_FRAME;
- if (status & RXSTATUS_OVERRUN) {
- /* Overrun is special, since it's
- * reported immediately, and doesn't
- * affect the current character
- */
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- }
- }
+ flag = TTY_FRAME;
} /* end of if (error) */
-
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ tty_insert_flip_char(tty, DataByte, flag);
+ if (status & RXSTATUS_OVERRUN) {
+ /* Overrun is special, since it's
+ * reported immediately, and doesn't
+ * affect the current character
+ */
+ work += tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
}
if ( debug_level >= DEBUG_LEVEL_ISR ) {
- printk("%s(%d):mgsl_isr_receive_data flip count=%d\n",
- __FILE__,__LINE__,tty->flip.count);
printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n",
__FILE__,__LINE__,icount->rx,icount->brk,
icount->parity,icount->frame,icount->overrun);
}
- if ( tty->flip.count )
+ if(work)
tty_flip_buffer_push(tty);
}
@@ -7058,7 +7047,7 @@ static BOOLEAN mgsl_register_test( struct mgsl_struct *info )
{
static unsigned short BitPatterns[] =
{ 0x0000, 0xffff, 0xaaaa, 0x5555, 0x1234, 0x6969, 0x9696, 0x0f0f };
- static unsigned int Patterncount = sizeof(BitPatterns)/sizeof(unsigned short);
+ static unsigned int Patterncount = ARRAY_SIZE(BitPatterns);
unsigned int i;
BOOLEAN rc = TRUE;
unsigned long flags;
@@ -7501,9 +7490,9 @@ static int mgsl_adapter_test( struct mgsl_struct *info )
*/
static BOOLEAN mgsl_memory_test( struct mgsl_struct *info )
{
- static unsigned long BitPatterns[] = { 0x0, 0x55555555, 0xaaaaaaaa,
- 0x66666666, 0x99999999, 0xffffffff, 0x12345678 };
- unsigned long Patterncount = sizeof(BitPatterns)/sizeof(unsigned long);
+ static unsigned long BitPatterns[] =
+ { 0x0, 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999, 0xffffffff, 0x12345678 };
+ unsigned long Patterncount = ARRAY_SIZE(BitPatterns);
unsigned long i;
unsigned long TestLimit = SHARED_MEM_ADDRESS_SIZE/sizeof(unsigned long);
unsigned long * TestAddr;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
new file mode 100644
index 00000000000..79c81def410
--- /dev/null
+++ b/drivers/char/synclink_gt.c
@@ -0,0 +1,4499 @@
+/*
+ * $Id: synclink_gt.c,v 4.20 2005/11/08 19:51:55 paulkf Exp $
+ *
+ * Device driver for Microgate SyncLink GT serial adapters.
+ *
+ * written by Paul Fulghum for Microgate Corporation
+ * paulkf@microgate.com
+ *
+ * Microgate and SyncLink are trademarks of Microgate Corporation
+ *
+ * This code is released under the GNU General Public License (GPL)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * DEBUG OUTPUT DEFINITIONS
+ *
+ * uncomment lines below to enable specific types of debug output
+ *
+ * DBGINFO information - most verbose output
+ * DBGERR serious errors
+ * DBGBH bottom half service routine debugging
+ * DBGISR interrupt service routine debugging
+ * DBGDATA output receive and transmit data
+ * DBGTBUF output transmit DMA buffers and registers
+ * DBGRBUF output receive DMA buffers and registers
+ */
+
+#define DBGINFO(fmt) if (debug_level >= DEBUG_LEVEL_INFO) printk fmt
+#define DBGERR(fmt) if (debug_level >= DEBUG_LEVEL_ERROR) printk fmt
+#define DBGBH(fmt) if (debug_level >= DEBUG_LEVEL_BH) printk fmt
+#define DBGISR(fmt) if (debug_level >= DEBUG_LEVEL_ISR) printk fmt
+#define DBGDATA(info, buf, size, label) if (debug_level >= DEBUG_LEVEL_DATA) trace_block((info), (buf), (size), (label))
+//#define DBGTBUF(info) dump_tbufs(info)
+//#define DBGRBUF(info) dump_rbufs(info)
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioctl.h>
+#include <linux/termios.h>
+#include <linux/bitops.h>
+#include <linux/workqueue.h>
+#include <linux/hdlc.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+
+#include "linux/synclink.h"
+
+#ifdef CONFIG_HDLC_MODULE
+#define CONFIG_HDLC 1
+#endif
+
+/*
+ * module identification
+ */
+static char *driver_name = "SyncLink GT";
+static char *driver_version = "$Revision: 4.20 $";
+static char *tty_driver_name = "synclink_gt";
+static char *tty_dev_prefix = "ttySLG";
+MODULE_LICENSE("GPL");
+#define MGSL_MAGIC 0x5401
+#define MAX_DEVICES 12
+
+static struct pci_device_id pci_table[] = {
+ {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {0,}, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, pci_table);
+
+static int init_one(struct pci_dev *dev,const struct pci_device_id *ent);
+static void remove_one(struct pci_dev *dev);
+static struct pci_driver pci_driver = {
+ .name = "synclink_gt",
+ .id_table = pci_table,
+ .probe = init_one,
+ .remove = __devexit_p(remove_one),
+};
+
+static int pci_registered;
+
+/*
+ * module configuration and status
+ */
+static struct slgt_info *slgt_device_list;
+static int slgt_device_count;
+
+static int ttymajor;
+static int debug_level;
+static int maxframe[MAX_DEVICES];
+static int dosyncppp[MAX_DEVICES];
+
+module_param(ttymajor, int, 0);
+module_param(debug_level, int, 0);
+module_param_array(maxframe, int, NULL, 0);
+module_param_array(dosyncppp, int, NULL, 0);
+
+MODULE_PARM_DESC(ttymajor, "TTY major device number override: 0=auto assigned");
+MODULE_PARM_DESC(debug_level, "Debug syslog output: 0=disabled, 1 to 5=increasing detail");
+MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)");
+MODULE_PARM_DESC(dosyncppp, "Enable synchronous net device, 0=disable 1=enable");
+
+/*
+ * tty support and callbacks
+ */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+static struct tty_driver *serial_driver;
+
+static int open(struct tty_struct *tty, struct file * filp);
+static void close(struct tty_struct *tty, struct file * filp);
+static void hangup(struct tty_struct *tty);
+static void set_termios(struct tty_struct *tty, struct termios *old_termios);
+
+static int write(struct tty_struct *tty, const unsigned char *buf, int count);
+static void put_char(struct tty_struct *tty, unsigned char ch);
+static void send_xchar(struct tty_struct *tty, char ch);
+static void wait_until_sent(struct tty_struct *tty, int timeout);
+static int write_room(struct tty_struct *tty);
+static void flush_chars(struct tty_struct *tty);
+static void flush_buffer(struct tty_struct *tty);
+static void tx_hold(struct tty_struct *tty);
+static void tx_release(struct tty_struct *tty);
+
+static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
+static int read_proc(char *page, char **start, off_t off, int count,int *eof, void *data);
+static int chars_in_buffer(struct tty_struct *tty);
+static void throttle(struct tty_struct * tty);
+static void unthrottle(struct tty_struct * tty);
+static void set_break(struct tty_struct *tty, int break_state);
+
+/*
+ * generic HDLC support and callbacks
+ */
+#ifdef CONFIG_HDLC
+#define dev_to_port(D) (dev_to_hdlc(D)->priv)
+static void hdlcdev_tx_done(struct slgt_info *info);
+static void hdlcdev_rx(struct slgt_info *info, char *buf, int size);
+static int hdlcdev_init(struct slgt_info *info);
+static void hdlcdev_exit(struct slgt_info *info);
+#endif
+
+
+/*
+ * device specific structures, macros and functions
+ */
+
+#define SLGT_MAX_PORTS 4
+#define SLGT_REG_SIZE 256
+
+/*
+ * DMA buffer descriptor and access macros
+ */
+struct slgt_desc
+{
+ unsigned short count;
+ unsigned short status;
+ unsigned int pbuf; /* physical address of data buffer */
+ unsigned int next; /* physical address of next descriptor */
+
+ /* driver book keeping */
+ char *buf; /* virtual address of data buffer */
+ unsigned int pdesc; /* physical address of this descriptor */
+ dma_addr_t buf_dma_addr;
+};
+
+#define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b))
+#define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b))
+#define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b))
+#define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0))
+#define desc_count(a) (le16_to_cpu((a).count))
+#define desc_status(a) (le16_to_cpu((a).status))
+#define desc_complete(a) (le16_to_cpu((a).status) & BIT15)
+#define desc_eof(a) (le16_to_cpu((a).status) & BIT2)
+#define desc_crc_error(a) (le16_to_cpu((a).status) & BIT1)
+#define desc_abort(a) (le16_to_cpu((a).status) & BIT0)
+#define desc_residue(a) ((le16_to_cpu((a).status) & 0x38) >> 3)
+
+struct _input_signal_events {
+ int ri_up;
+ int ri_down;
+ int dsr_up;
+ int dsr_down;
+ int dcd_up;
+ int dcd_down;
+ int cts_up;
+ int cts_down;
+};
+
+/*
+ * device instance data structure
+ */
+struct slgt_info {
+ void *if_ptr; /* General purpose pointer (used by SPPP) */
+
+ struct slgt_info *next_device; /* device list link */
+
+ int magic;
+ int flags;
+
+ char device_name[25];
+ struct pci_dev *pdev;
+
+ int port_count; /* count of ports on adapter */
+ int adapter_num; /* adapter instance number */
+ int port_num; /* port instance number */
+
+ /* array of pointers to port contexts on this adapter */
+ struct slgt_info *port_array[SLGT_MAX_PORTS];
+
+ int count; /* count of opens */
+ int line; /* tty line instance number */
+ unsigned short close_delay;
+ unsigned short closing_wait; /* time to wait before closing */
+
+ struct mgsl_icount icount;
+
+ struct tty_struct *tty;
+ int timeout;
+ int x_char; /* xon/xoff character */
+ int blocked_open; /* # of blocked opens */
+ unsigned int read_status_mask;
+ unsigned int ignore_status_mask;
+
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+
+ wait_queue_head_t status_event_wait_q;
+ wait_queue_head_t event_wait_q;
+ struct timer_list tx_timer;
+ struct timer_list rx_timer;
+
+ spinlock_t lock; /* spinlock for synchronizing with ISR */
+
+ struct work_struct task;
+ u32 pending_bh;
+ int bh_requested;
+ int bh_running;
+
+ int isr_overflow;
+ int irq_requested; /* nonzero if IRQ requested */
+ int irq_occurred; /* for diagnostics use */
+
+ /* device configuration */
+
+ unsigned int bus_type;
+ unsigned int irq_level;
+ unsigned long irq_flags;
+
+ unsigned char __iomem * reg_addr; /* memory mapped registers address */
+ u32 phys_reg_addr;
+ u32 reg_offset;
+ int reg_addr_requested;
+
+ MGSL_PARAMS params; /* communications parameters */
+ u32 idle_mode;
+ u32 max_frame_size; /* as set by device config */
+
+ unsigned int raw_rx_size;
+ unsigned int if_mode;
+
+ /* device status */
+
+ int rx_enabled;
+ int rx_restart;
+
+ int tx_enabled;
+ int tx_active;
+
+ unsigned char signals; /* serial signal states */
+ unsigned int init_error; /* initialization error */
+
+ unsigned char *tx_buf;
+ int tx_count;
+
+ char flag_buf[MAX_ASYNC_BUFFER_SIZE];
+ char char_buf[MAX_ASYNC_BUFFER_SIZE];
+ BOOLEAN drop_rts_on_tx_done;
+ struct _input_signal_events input_signal_events;
+
+ int dcd_chkcount; /* check counts to prevent */
+ int cts_chkcount; /* too many IRQs if a signal */
+ int dsr_chkcount; /* is floating */
+ int ri_chkcount;
+
+ char *bufs; /* virtual address of DMA buffer lists */
+ dma_addr_t bufs_dma_addr; /* physical address of buffer descriptors */
+
+ unsigned int rbuf_count;
+ struct slgt_desc *rbufs;
+ unsigned int rbuf_current;
+ unsigned int rbuf_index;
+
+ unsigned int tbuf_count;
+ struct slgt_desc *tbufs;
+ unsigned int tbuf_current;
+ unsigned int tbuf_start;
+
+ unsigned char *tmp_rbuf;
+ unsigned int tmp_rbuf_count;
+
+ /* SPPP/Cisco HDLC device parts */
+
+ int netcount;
+ int dosyncppp;
+ spinlock_t netlock;
+#ifdef CONFIG_HDLC
+ struct net_device *netdev;
+#endif
+
+};
+
+static MGSL_PARAMS default_params = {
+ .mode = MGSL_MODE_HDLC,
+ .loopback = 0,
+ .flags = HDLC_FLAG_UNDERRUN_ABORT15,
+ .encoding = HDLC_ENCODING_NRZI_SPACE,
+ .clock_speed = 0,
+ .addr_filter = 0xff,
+ .crc_type = HDLC_CRC_16_CCITT,
+ .preamble_length = HDLC_PREAMBLE_LENGTH_8BITS,
+ .preamble = HDLC_PREAMBLE_PATTERN_NONE,
+ .data_rate = 9600,
+ .data_bits = 8,
+ .stop_bits = 1,
+ .parity = ASYNC_PARITY_NONE
+};
+
+
+#define BH_RECEIVE 1
+#define BH_TRANSMIT 2
+#define BH_STATUS 4
+#define IO_PIN_SHUTDOWN_LIMIT 100
+
+#define DMABUFSIZE 256
+#define DESC_LIST_SIZE 4096
+
+#define MASK_PARITY BIT1
+#define MASK_FRAMING BIT2
+#define MASK_BREAK BIT3
+#define MASK_OVERRUN BIT4
+
+#define GSR 0x00 /* global status */
+#define TDR 0x80 /* tx data */
+#define RDR 0x80 /* rx data */
+#define TCR 0x82 /* tx control */
+#define TIR 0x84 /* tx idle */
+#define TPR 0x85 /* tx preamble */
+#define RCR 0x86 /* rx control */
+#define VCR 0x88 /* V.24 control */
+#define CCR 0x89 /* clock control */
+#define BDR 0x8a /* baud divisor */
+#define SCR 0x8c /* serial control */
+#define SSR 0x8e /* serial status */
+#define RDCSR 0x90 /* rx DMA control/status */
+#define TDCSR 0x94 /* tx DMA control/status */
+#define RDDAR 0x98 /* rx DMA descriptor address */
+#define TDDAR 0x9c /* tx DMA descriptor address */
+
+#define RXIDLE BIT14
+#define RXBREAK BIT14
+#define IRQ_TXDATA BIT13
+#define IRQ_TXIDLE BIT12
+#define IRQ_TXUNDER BIT11 /* HDLC */
+#define IRQ_RXDATA BIT10
+#define IRQ_RXIDLE BIT9 /* HDLC */
+#define IRQ_RXBREAK BIT9 /* async */
+#define IRQ_RXOVER BIT8
+#define IRQ_DSR BIT7
+#define IRQ_CTS BIT6
+#define IRQ_DCD BIT5
+#define IRQ_RI BIT4
+#define IRQ_ALL 0x3ff0
+#define IRQ_MASTER BIT0
+
+#define slgt_irq_on(info, mask) \
+ wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) | (mask)))
+#define slgt_irq_off(info, mask) \
+ wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) & ~(mask)))
+
+static __u8 rd_reg8(struct slgt_info *info, unsigned int addr);
+static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value);
+static __u16 rd_reg16(struct slgt_info *info, unsigned int addr);
+static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value);
+static __u32 rd_reg32(struct slgt_info *info, unsigned int addr);
+static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value);
+
+static void msc_set_vcr(struct slgt_info *info);
+
+static int startup(struct slgt_info *info);
+static int block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info);
+static void shutdown(struct slgt_info *info);
+static void program_hw(struct slgt_info *info);
+static void change_params(struct slgt_info *info);
+
+static int register_test(struct slgt_info *info);
+static int irq_test(struct slgt_info *info);
+static int loopback_test(struct slgt_info *info);
+static int adapter_test(struct slgt_info *info);
+
+static void reset_adapter(struct slgt_info *info);
+static void reset_port(struct slgt_info *info);
+static void async_mode(struct slgt_info *info);
+static void hdlc_mode(struct slgt_info *info);
+
+static void rx_stop(struct slgt_info *info);
+static void rx_start(struct slgt_info *info);
+static void reset_rbufs(struct slgt_info *info);
+static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last);
+static void rdma_reset(struct slgt_info *info);
+static int rx_get_frame(struct slgt_info *info);
+static int rx_get_buf(struct slgt_info *info);
+
+static void tx_start(struct slgt_info *info);
+static void tx_stop(struct slgt_info *info);
+static void tx_set_idle(struct slgt_info *info);
+static unsigned int free_tbuf_count(struct slgt_info *info);
+static void reset_tbufs(struct slgt_info *info);
+static void tdma_reset(struct slgt_info *info);
+static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
+
+static void get_signals(struct slgt_info *info);
+static void set_signals(struct slgt_info *info);
+static void enable_loopback(struct slgt_info *info);
+static void set_rate(struct slgt_info *info, u32 data_rate);
+
+static int bh_action(struct slgt_info *info);
+static void bh_handler(void* context);
+static void bh_transmit(struct slgt_info *info);
+static void isr_serial(struct slgt_info *info);
+static void isr_rdma(struct slgt_info *info);
+static void isr_txeom(struct slgt_info *info, unsigned short status);
+static void isr_tdma(struct slgt_info *info);
+static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+
+static int alloc_dma_bufs(struct slgt_info *info);
+static void free_dma_bufs(struct slgt_info *info);
+static int alloc_desc(struct slgt_info *info);
+static void free_desc(struct slgt_info *info);
+static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count);
+static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count);
+
+static int alloc_tmp_rbuf(struct slgt_info *info);
+static void free_tmp_rbuf(struct slgt_info *info);
+
+static void tx_timeout(unsigned long context);
+static void rx_timeout(unsigned long context);
+
+/*
+ * ioctl handlers
+ */
+static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount);
+static int get_params(struct slgt_info *info, MGSL_PARAMS __user *params);
+static int set_params(struct slgt_info *info, MGSL_PARAMS __user *params);
+static int get_txidle(struct slgt_info *info, int __user *idle_mode);
+static int set_txidle(struct slgt_info *info, int idle_mode);
+static int tx_enable(struct slgt_info *info, int enable);
+static int tx_abort(struct slgt_info *info);
+static int rx_enable(struct slgt_info *info, int enable);
+static int modem_input_wait(struct slgt_info *info,int arg);
+static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr);
+static int tiocmget(struct tty_struct *tty, struct file *file);
+static int tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear);
+static void set_break(struct tty_struct *tty, int break_state);
+static int get_interface(struct slgt_info *info, int __user *if_mode);
+static int set_interface(struct slgt_info *info, int if_mode);
+
+/*
+ * driver functions
+ */
+static void add_device(struct slgt_info *info);
+static void device_init(int adapter_num, struct pci_dev *pdev);
+static int claim_resources(struct slgt_info *info);
+static void release_resources(struct slgt_info *info);
+
+/*
+ * DEBUG OUTPUT CODE
+ */
+#ifndef DBGINFO
+#define DBGINFO(fmt)
+#endif
+#ifndef DBGERR
+#define DBGERR(fmt)
+#endif
+#ifndef DBGBH
+#define DBGBH(fmt)
+#endif
+#ifndef DBGISR
+#define DBGISR(fmt)
+#endif
+
+#ifdef DBGDATA
+static void trace_block(struct slgt_info *info, const char *data, int count, const char *label)
+{
+ int i;
+ int linecount;
+ printk("%s %s data:\n",info->device_name, label);
+ while(count) {
+ linecount = (count > 16) ? 16 : count;
+ for(i=0; i < linecount; i++)
+ printk("%02X ",(unsigned char)data[i]);
+ for(;i<17;i++)
+ printk(" ");
+ for(i=0;i<linecount;i++) {
+ if (data[i]>=040 && data[i]<=0176)
+ printk("%c",data[i]);
+ else
+ printk(".");
+ }
+ printk("\n");
+ data += linecount;
+ count -= linecount;
+ }
+}
+#else
+#define DBGDATA(info, buf, size, label)
+#endif
+
+#ifdef DBGTBUF
+static void dump_tbufs(struct slgt_info *info)
+{
+ int i;
+ printk("tbuf_current=%d\n", info->tbuf_current);
+ for (i=0 ; i < info->tbuf_count ; i++) {
+ printk("%d: count=%04X status=%04X\n",
+ i, le16_to_cpu(info->tbufs[i].count), le16_to_cpu(info->tbufs[i].status));
+ }
+}
+#else
+#define DBGTBUF(info)
+#endif
+
+#ifdef DBGRBUF
+static void dump_rbufs(struct slgt_info *info)
+{
+ int i;
+ printk("rbuf_current=%d\n", info->rbuf_current);
+ for (i=0 ; i < info->rbuf_count ; i++) {
+ printk("%d: count=%04X status=%04X\n",
+ i, le16_to_cpu(info->rbufs[i].count), le16_to_cpu(info->rbufs[i].status));
+ }
+}
+#else
+#define DBGRBUF(info)
+#endif
+
+static inline int sanity_check(struct slgt_info *info, char *devname, const char *name)
+{
+#ifdef SANITY_CHECK
+ if (!info) {
+ printk("null struct slgt_info for (%s) in %s\n", devname, name);
+ return 1;
+ }
+ if (info->magic != MGSL_MAGIC) {
+ printk("bad magic number struct slgt_info (%s) in %s\n", devname, name);
+ return 1;
+ }
+#else
+ if (!info)
+ return 1;
+#endif
+ return 0;
+}
+
+/**
+ * line discipline callback wrappers
+ *
+ * The wrappers maintain line discipline references
+ * while calling into the line discipline.
+ *
+ * ldisc_receive_buf - pass receive data to line discipline
+ */
+static void ldisc_receive_buf(struct tty_struct *tty,
+ const __u8 *data, char *flags, int count)
+{
+ struct tty_ldisc *ld;
+ if (!tty)
+ return;
+ ld = tty_ldisc_ref(tty);
+ if (ld) {
+ if (ld->receive_buf)
+ ld->receive_buf(tty, data, flags, count);
+ tty_ldisc_deref(ld);
+ }
+}
+
+/* tty callbacks */
+
+static int open(struct tty_struct *tty, struct file *filp)
+{
+ struct slgt_info *info;
+ int retval, line;
+ unsigned long flags;
+
+ line = tty->index;
+ if ((line < 0) || (line >= slgt_device_count)) {
+ DBGERR(("%s: open with invalid line #%d.\n", driver_name, line));
+ return -ENODEV;
+ }
+
+ info = slgt_device_list;
+ while(info && info->line != line)
+ info = info->next_device;
+ if (sanity_check(info, tty->name, "open"))
+ return -ENODEV;
+ if (info->init_error) {
+ DBGERR(("%s init error=%d\n", info->device_name, info->init_error));
+ return -ENODEV;
+ }
+
+ tty->driver_data = info;
+ info->tty = tty;
+
+ DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->count));
+
+ /* If port is closing, signal caller to try again */
+ if (tty_hung_up_p(filp) || info->flags & ASYNC_CLOSING){
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+ retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+ goto cleanup;
+ }
+
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+ spin_lock_irqsave(&info->netlock, flags);
+ if (info->netcount) {
+ retval = -EBUSY;
+ spin_unlock_irqrestore(&info->netlock, flags);
+ goto cleanup;
+ }
+ info->count++;
+ spin_unlock_irqrestore(&info->netlock, flags);
+
+ if (info->count == 1) {
+ /* 1st open on this device, init hardware */
+ retval = startup(info);
+ if (retval < 0)
+ goto cleanup;
+ }
+
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+ DBGINFO(("%s block_til_ready rc=%d\n", info->device_name, retval));
+ goto cleanup;
+ }
+
+ retval = 0;
+
+cleanup:
+ if (retval) {
+ if (tty->count == 1)
+ info->tty = NULL; /* tty layer will release tty struct */
+ if(info->count)
+ info->count--;
+ }
+
+ DBGINFO(("%s open rc=%d\n", info->device_name, retval));
+ return retval;
+}
+
+static void close(struct tty_struct *tty, struct file *filp)
+{
+ struct slgt_info *info = tty->driver_data;
+
+ if (sanity_check(info, tty->name, "close"))
+ return;
+ DBGINFO(("%s close entry, count=%d\n", info->device_name, info->count));
+
+ if (!info->count)
+ return;
+
+ if (tty_hung_up_p(filp))
+ goto cleanup;
+
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * tty->count is 1 and the tty structure will be freed.
+ * info->count should be one in this case.
+ * if it's not, correct it so that the port is shutdown.
+ */
+ DBGERR(("%s close: bad refcount; tty->count=1, "
+ "info->count=%d\n", info->device_name, info->count));
+ info->count = 1;
+ }
+
+ info->count--;
+
+ /* if at least one open remaining, leave hardware active */
+ if (info->count)
+ goto cleanup;
+
+ info->flags |= ASYNC_CLOSING;
+
+ /* set tty->closing to notify line discipline to
+ * only process XON/XOFF characters. Only the N_TTY
+ * discipline appears to use this (ppp does not).
+ */
+ tty->closing = 1;
+
+ /* wait for transmit data to clear all layers */
+
+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
+ DBGINFO(("%s call tty_wait_until_sent\n", info->device_name));
+ tty_wait_until_sent(tty, info->closing_wait);
+ }
+
+ if (info->flags & ASYNC_INITIALIZED)
+ wait_until_sent(tty, info->timeout);
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+ tty_ldisc_flush(tty);
+
+ shutdown(info);
+
+ tty->closing = 0;
+ info->tty = NULL;
+
+ 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);
+
+cleanup:
+ DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->count));
+}
+
+static void hangup(struct tty_struct *tty)
+{
+ struct slgt_info *info = tty->driver_data;
+
+ if (sanity_check(info, tty->name, "hangup"))
+ return;
+ DBGINFO(("%s hangup\n", info->device_name));
+
+ flush_buffer(tty);
+ shutdown(info);
+
+ info->count = 0;
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ info->tty = NULL;
+
+ wake_up_interruptible(&info->open_wait);
+}
+
+static void set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ DBGINFO(("%s set_termios\n", tty->driver->name));
+
+ /* just return if nothing has changed */
+ if ((tty->termios->c_cflag == old_termios->c_cflag)
+ && (RELEVANT_IFLAG(tty->termios->c_iflag)
+ == RELEVANT_IFLAG(old_termios->c_iflag)))
+ return;
+
+ change_params(info);
+
+ /* Handle transition to B0 status */
+ if (old_termios->c_cflag & CBAUD &&
+ !(tty->termios->c_cflag & CBAUD)) {
+ info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+ spin_lock_irqsave(&info->lock,flags);
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ }
+
+ /* Handle transition away from B0 status */
+ if (!(old_termios->c_cflag & CBAUD) &&
+ tty->termios->c_cflag & CBAUD) {
+ info->signals |= SerialSignal_DTR;
+ if (!(tty->termios->c_cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &tty->flags)) {
+ info->signals |= SerialSignal_RTS;
+ }
+ spin_lock_irqsave(&info->lock,flags);
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ }
+
+ /* Handle turning off CRTSCTS */
+ if (old_termios->c_cflag & CRTSCTS &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ tx_release(tty);
+ }
+}
+
+static int write(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ int ret = 0;
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "write"))
+ goto cleanup;
+ DBGINFO(("%s write count=%d\n", info->device_name, count));
+
+ if (!tty || !info->tx_buf)
+ goto cleanup;
+
+ if (count > info->max_frame_size) {
+ ret = -EIO;
+ goto cleanup;
+ }
+
+ if (!count)
+ goto cleanup;
+
+ if (info->params.mode == MGSL_MODE_RAW) {
+ unsigned int bufs_needed = (count/DMABUFSIZE);
+ unsigned int bufs_free = free_tbuf_count(info);
+ if (count % DMABUFSIZE)
+ ++bufs_needed;
+ if (bufs_needed > bufs_free)
+ goto cleanup;
+ } else {
+ if (info->tx_active)
+ goto cleanup;
+ if (info->tx_count) {
+ /* send accumulated data from send_char() calls */
+ /* as frame and wait before accepting more data. */
+ tx_load(info, info->tx_buf, info->tx_count);
+ goto start;
+ }
+ }
+
+ ret = info->tx_count = count;
+ tx_load(info, buf, count);
+ goto start;
+
+start:
+ if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
+ spin_lock_irqsave(&info->lock,flags);
+ if (!info->tx_active)
+ tx_start(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ }
+
+cleanup:
+ DBGINFO(("%s write rc=%d\n", info->device_name, ret));
+ return ret;
+}
+
+static void put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "put_char"))
+ return;
+ DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
+ if (!tty || !info->tx_buf)
+ return;
+ spin_lock_irqsave(&info->lock,flags);
+ if (!info->tx_active && (info->tx_count < info->max_frame_size))
+ info->tx_buf[info->tx_count++] = ch;
+ spin_unlock_irqrestore(&info->lock,flags);
+}
+
+static void send_xchar(struct tty_struct *tty, char ch)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "send_xchar"))
+ return;
+ DBGINFO(("%s send_xchar(%d)\n", info->device_name, ch));
+ info->x_char = ch;
+ if (ch) {
+ spin_lock_irqsave(&info->lock,flags);
+ if (!info->tx_enabled)
+ tx_start(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ }
+}
+
+static void wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long orig_jiffies, char_time;
+
+ if (!info )
+ return;
+ if (sanity_check(info, tty->name, "wait_until_sent"))
+ return;
+ DBGINFO(("%s wait_until_sent entry\n", info->device_name));
+ if (!(info->flags & ASYNC_INITIALIZED))
+ goto exit;
+
+ orig_jiffies = jiffies;
+
+ /* Set check interval to 1/5 of estimated time to
+ * send a character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ * Note: use tight timings here to satisfy the NIST-PCTS.
+ */
+
+ if (info->params.data_rate) {
+ char_time = info->timeout/(32 * 5);
+ if (!char_time)
+ char_time++;
+ } else
+ char_time = 1;
+
+ if (timeout)
+ char_time = min_t(unsigned long, char_time, timeout);
+
+ while (info->tx_active) {
+ msleep_interruptible(jiffies_to_msecs(char_time));
+ if (signal_pending(current))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
+ break;
+ }
+
+exit:
+ DBGINFO(("%s wait_until_sent exit\n", info->device_name));
+}
+
+static int write_room(struct tty_struct *tty)
+{
+ struct slgt_info *info = tty->driver_data;
+ int ret;
+
+ if (sanity_check(info, tty->name, "write_room"))
+ return 0;
+ ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
+ DBGINFO(("%s write_room=%d\n", info->device_name, ret));
+ return ret;
+}
+
+static void flush_chars(struct tty_struct *tty)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "flush_chars"))
+ return;
+ DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count));
+
+ if (info->tx_count <= 0 || tty->stopped ||
+ tty->hw_stopped || !info->tx_buf)
+ return;
+
+ DBGINFO(("%s flush_chars start transmit\n", info->device_name));
+
+ spin_lock_irqsave(&info->lock,flags);
+ if (!info->tx_active && info->tx_count) {
+ tx_load(info, info->tx_buf,info->tx_count);
+ tx_start(info);
+ }
+ spin_unlock_irqrestore(&info->lock,flags);
+}
+
+static void flush_buffer(struct tty_struct *tty)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "flush_buffer"))
+ return;
+ DBGINFO(("%s flush_buffer\n", info->device_name));
+
+ spin_lock_irqsave(&info->lock,flags);
+ if (!info->tx_active)
+ info->tx_count = 0;
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ wake_up_interruptible(&tty->write_wait);
+ tty_wakeup(tty);
+}
+
+/*
+ * throttle (stop) transmitter
+ */
+static void tx_hold(struct tty_struct *tty)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "tx_hold"))
+ return;
+ DBGINFO(("%s tx_hold\n", info->device_name));
+ spin_lock_irqsave(&info->lock,flags);
+ if (info->tx_enabled && info->params.mode == MGSL_MODE_ASYNC)
+ tx_stop(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/*
+ * release (start) transmitter
+ */
+static void tx_release(struct tty_struct *tty)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "tx_release"))
+ return;
+ DBGINFO(("%s tx_release\n", info->device_name));
+ spin_lock_irqsave(&info->lock,flags);
+ if (!info->tx_active && info->tx_count) {
+ tx_load(info, info->tx_buf, info->tx_count);
+ tx_start(info);
+ }
+ spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/*
+ * Service an IOCTL request
+ *
+ * Arguments
+ *
+ * tty pointer to tty instance data
+ * file pointer to associated file object for device
+ * cmd IOCTL command code
+ * arg command argument/context
+ *
+ * Return 0 if success, otherwise error code
+ */
+static int ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct slgt_info *info = tty->driver_data;
+ struct mgsl_icount cnow; /* kernel counter temps */
+ struct serial_icounter_struct __user *p_cuser; /* user space */
+ unsigned long flags;
+ void __user *argp = (void __user *)arg;
+
+ if (sanity_check(info, tty->name, "ioctl"))
+ return -ENODEV;
+ DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd));
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case MGSL_IOCGPARAMS:
+ return get_params(info, argp);
+ case MGSL_IOCSPARAMS:
+ return set_params(info, argp);
+ case MGSL_IOCGTXIDLE:
+ return get_txidle(info, argp);
+ case MGSL_IOCSTXIDLE:
+ return set_txidle(info, (int)arg);
+ case MGSL_IOCTXENABLE:
+ return tx_enable(info, (int)arg);
+ case MGSL_IOCRXENABLE:
+ return rx_enable(info, (int)arg);
+ case MGSL_IOCTXABORT:
+ return tx_abort(info);
+ case MGSL_IOCGSTATS:
+ return get_stats(info, argp);
+ case MGSL_IOCWAITEVENT:
+ return wait_mgsl_event(info, argp);
+ case TIOCMIWAIT:
+ return modem_input_wait(info,(int)arg);
+ case MGSL_IOCGIF:
+ return get_interface(info, argp);
+ case MGSL_IOCSIF:
+ return set_interface(info,(int)arg);
+ case TIOCGICOUNT:
+ spin_lock_irqsave(&info->lock,flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->lock,flags);
+ p_cuser = argp;
+ if (put_user(cnow.cts, &p_cuser->cts) ||
+ put_user(cnow.dsr, &p_cuser->dsr) ||
+ put_user(cnow.rng, &p_cuser->rng) ||
+ put_user(cnow.dcd, &p_cuser->dcd) ||
+ put_user(cnow.rx, &p_cuser->rx) ||
+ put_user(cnow.tx, &p_cuser->tx) ||
+ put_user(cnow.frame, &p_cuser->frame) ||
+ put_user(cnow.overrun, &p_cuser->overrun) ||
+ put_user(cnow.parity, &p_cuser->parity) ||
+ put_user(cnow.brk, &p_cuser->brk) ||
+ put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
+ return -EFAULT;
+ return 0;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+/*
+ * proc fs support
+ */
+static inline int line_info(char *buf, struct slgt_info *info)
+{
+ char stat_buf[30];
+ int ret;
+ unsigned long flags;
+
+ ret = sprintf(buf, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n",
+ info->device_name, info->phys_reg_addr,
+ info->irq_level, info->max_frame_size);
+
+ /* output current serial signal states */
+ spin_lock_irqsave(&info->lock,flags);
+ get_signals(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ stat_buf[0] = 0;
+ stat_buf[1] = 0;
+ if (info->signals & SerialSignal_RTS)
+ strcat(stat_buf, "|RTS");
+ if (info->signals & SerialSignal_CTS)
+ strcat(stat_buf, "|CTS");
+ if (info->signals & SerialSignal_DTR)
+ strcat(stat_buf, "|DTR");
+ if (info->signals & SerialSignal_DSR)
+ strcat(stat_buf, "|DSR");
+ if (info->signals & SerialSignal_DCD)
+ strcat(stat_buf, "|CD");
+ if (info->signals & SerialSignal_RI)
+ strcat(stat_buf, "|RI");
+
+ if (info->params.mode != MGSL_MODE_ASYNC) {
+ ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",
+ info->icount.txok, info->icount.rxok);
+ if (info->icount.txunder)
+ ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);
+ if (info->icount.txabort)
+ ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
+ if (info->icount.rxshort)
+ ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+ if (info->icount.rxlong)
+ ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
+ if (info->icount.rxover)
+ ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);
+ if (info->icount.rxcrc)
+ ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc);
+ } else {
+ ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d",
+ info->icount.tx, info->icount.rx);
+ if (info->icount.frame)
+ ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+ if (info->icount.parity)
+ ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+ if (info->icount.brk)
+ ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+ if (info->icount.overrun)
+ ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+ }
+
+ /* Append serial signal status to end */
+ ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+
+ ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
+ info->tx_active,info->bh_requested,info->bh_running,
+ info->pending_bh);
+
+ return ret;
+}
+
+/* Called to print information about devices
+ */
+static int read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int len = 0, l;
+ off_t begin = 0;
+ struct slgt_info *info;
+
+ len += sprintf(page, "synclink_gt driver:%s\n", driver_version);
+
+ info = slgt_device_list;
+ while( info ) {
+ l = line_info(page + len, info);
+ len += l;
+ if (len+begin > off+count)
+ goto done;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ info = info->next_device;
+ }
+
+ *eof = 1;
+done:
+ if (off >= len+begin)
+ return 0;
+ *start = page + (off-begin);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * return count of bytes in transmit buffer
+ */
+static int chars_in_buffer(struct tty_struct *tty)
+{
+ struct slgt_info *info = tty->driver_data;
+ if (sanity_check(info, tty->name, "chars_in_buffer"))
+ return 0;
+ DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, info->tx_count));
+ return info->tx_count;
+}
+
+/*
+ * signal remote device to throttle send data (our receive data)
+ */
+static void throttle(struct tty_struct * tty)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "throttle"))
+ return;
+ DBGINFO(("%s throttle\n", info->device_name));
+ if (I_IXOFF(tty))
+ send_xchar(tty, STOP_CHAR(tty));
+ if (tty->termios->c_cflag & CRTSCTS) {
+ spin_lock_irqsave(&info->lock,flags);
+ info->signals &= ~SerialSignal_RTS;
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ }
+}
+
+/*
+ * signal remote device to stop throttling send data (our receive data)
+ */
+static void unthrottle(struct tty_struct * tty)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "unthrottle"))
+ return;
+ DBGINFO(("%s unthrottle\n", info->device_name));
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ send_xchar(tty, START_CHAR(tty));
+ }
+ if (tty->termios->c_cflag & CRTSCTS) {
+ spin_lock_irqsave(&info->lock,flags);
+ info->signals |= SerialSignal_RTS;
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ }
+}
+
+/*
+ * set or clear transmit break condition
+ * break_state -1=set break condition, 0=clear
+ */
+static void set_break(struct tty_struct *tty, int break_state)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned short value;
+ unsigned long flags;
+
+ if (sanity_check(info, tty->name, "set_break"))
+ return;
+ DBGINFO(("%s set_break(%d)\n", info->device_name, break_state));
+
+ spin_lock_irqsave(&info->lock,flags);
+ value = rd_reg16(info, TCR);
+ if (break_state == -1)
+ value |= BIT6;
+ else
+ value &= ~BIT6;
+ wr_reg16(info, TCR, value);
+ spin_unlock_irqrestore(&info->lock,flags);
+}
+
+#ifdef CONFIG_HDLC
+
+/**
+ * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
+ * set encoding and frame check sequence (FCS) options
+ *
+ * dev pointer to network device structure
+ * encoding serial encoding setting
+ * parity FCS setting
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
+ unsigned short parity)
+{
+ struct slgt_info *info = dev_to_port(dev);
+ unsigned char new_encoding;
+ unsigned short new_crctype;
+
+ /* return error if TTY interface open */
+ if (info->count)
+ return -EBUSY;
+
+ DBGINFO(("%s hdlcdev_attach\n", info->device_name));
+
+ switch (encoding)
+ {
+ case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break;
+ case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break;
+ case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break;
+ case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break;
+ case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break;
+ default: return -EINVAL;
+ }
+
+ switch (parity)
+ {
+ case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break;
+ case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break;
+ case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break;
+ default: return -EINVAL;
+ }
+
+ info->params.encoding = new_encoding;
+ info->params.crc_type = new_crctype;;
+
+ /* if network interface up, reprogram hardware */
+ if (info->netcount)
+ program_hw(info);
+
+ return 0;
+}
+
+/**
+ * called by generic HDLC layer to send frame
+ *
+ * skb socket buffer containing HDLC frame
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct slgt_info *info = dev_to_port(dev);
+ struct net_device_stats *stats = hdlc_stats(dev);
+ unsigned long flags;
+
+ DBGINFO(("%s hdlc_xmit\n", dev->name));
+
+ /* stop sending until this frame completes */
+ netif_stop_queue(dev);
+
+ /* copy data to device buffers */
+ info->tx_count = skb->len;
+ tx_load(info, skb->data, skb->len);
+
+ /* update network statistics */
+ stats->tx_packets++;
+ stats->tx_bytes += skb->len;
+
+ /* done with socket buffer, so free it */
+ dev_kfree_skb(skb);
+
+ /* save start time for transmit timeout detection */
+ dev->trans_start = jiffies;
+
+ /* start hardware transmitter if necessary */
+ spin_lock_irqsave(&info->lock,flags);
+ if (!info->tx_active)
+ tx_start(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ return 0;
+}
+
+/**
+ * called by network layer when interface enabled
+ * claim resources and initialize hardware
+ *
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_open(struct net_device *dev)
+{
+ struct slgt_info *info = dev_to_port(dev);
+ int rc;
+ unsigned long flags;
+
+ DBGINFO(("%s hdlcdev_open\n", dev->name));
+
+ /* generic HDLC layer open processing */
+ if ((rc = hdlc_open(dev)))
+ return rc;
+
+ /* arbitrate between network and tty opens */
+ spin_lock_irqsave(&info->netlock, flags);
+ if (info->count != 0 || info->netcount != 0) {
+ DBGINFO(("%s hdlc_open busy\n", dev->name));
+ spin_unlock_irqrestore(&info->netlock, flags);
+ return -EBUSY;
+ }
+ info->netcount=1;
+ spin_unlock_irqrestore(&info->netlock, flags);
+
+ /* claim resources and init adapter */
+ if ((rc = startup(info)) != 0) {
+ spin_lock_irqsave(&info->netlock, flags);
+ info->netcount=0;
+ spin_unlock_irqrestore(&info->netlock, flags);
+ return rc;
+ }
+
+ /* assert DTR and RTS, apply hardware settings */
+ info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+ program_hw(info);
+
+ /* enable network layer transmit */
+ dev->trans_start = jiffies;
+ netif_start_queue(dev);
+
+ /* inform generic HDLC layer of current DCD status */
+ spin_lock_irqsave(&info->lock, flags);
+ get_signals(info);
+ spin_unlock_irqrestore(&info->lock, flags);
+ hdlc_set_carrier(info->signals & SerialSignal_DCD, dev);
+
+ return 0;
+}
+
+/**
+ * called by network layer when interface is disabled
+ * shutdown hardware and release resources
+ *
+ * dev pointer to network device structure
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_close(struct net_device *dev)
+{
+ struct slgt_info *info = dev_to_port(dev);
+ unsigned long flags;
+
+ DBGINFO(("%s hdlcdev_close\n", dev->name));
+
+ netif_stop_queue(dev);
+
+ /* shutdown adapter and release resources */
+ shutdown(info);
+
+ hdlc_close(dev);
+
+ spin_lock_irqsave(&info->netlock, flags);
+ info->netcount=0;
+ spin_unlock_irqrestore(&info->netlock, flags);
+
+ return 0;
+}
+
+/**
+ * called by network layer to process IOCTL call to network device
+ *
+ * dev pointer to network device structure
+ * ifr pointer to network interface request structure
+ * cmd IOCTL command code
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ const size_t size = sizeof(sync_serial_settings);
+ sync_serial_settings new_line;
+ sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+ struct slgt_info *info = dev_to_port(dev);
+ unsigned int flags;
+
+ DBGINFO(("%s hdlcdev_ioctl\n", dev->name));
+
+ /* return error if TTY interface open */
+ if (info->count)
+ return -EBUSY;
+
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ switch(ifr->ifr_settings.type) {
+ case IF_GET_IFACE: /* return current sync_serial_settings */
+
+ ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+
+ flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+
+ switch (flags){
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break;
+ case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break;
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break;
+ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break;
+ default: new_line.clock_type = CLOCK_DEFAULT;
+ }
+
+ new_line.clock_rate = info->params.clock_speed;
+ new_line.loopback = info->params.loopback ? 1:0;
+
+ if (copy_to_user(line, &new_line, size))
+ return -EFAULT;
+ return 0;
+
+ case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */
+
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&new_line, line, size))
+ return -EFAULT;
+
+ switch (new_line.clock_type)
+ {
+ case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break;
+ case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break;
+ case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break;
+ case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break;
+ case CLOCK_DEFAULT: flags = info->params.flags &
+ (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break;
+ default: return -EINVAL;
+ }
+
+ if (new_line.loopback != 0 && new_line.loopback != 1)
+ return -EINVAL;
+
+ info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL |
+ HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN |
+ HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL |
+ HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN);
+ info->params.flags |= flags;
+
+ info->params.loopback = new_line.loopback;
+
+ if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG))
+ info->params.clock_speed = new_line.clock_rate;
+ else
+ info->params.clock_speed = 0;
+
+ /* if network interface up, reprogram hardware */
+ if (info->netcount)
+ program_hw(info);
+ return 0;
+
+ default:
+ return hdlc_ioctl(dev, ifr, cmd);
+ }
+}
+
+/**
+ * called by network layer when transmit timeout is detected
+ *
+ * dev pointer to network device structure
+ */
+static void hdlcdev_tx_timeout(struct net_device *dev)
+{
+ struct slgt_info *info = dev_to_port(dev);
+ struct net_device_stats *stats = hdlc_stats(dev);
+ unsigned long flags;
+
+ DBGINFO(("%s hdlcdev_tx_timeout\n", dev->name));
+
+ stats->tx_errors++;
+ stats->tx_aborted_errors++;
+
+ spin_lock_irqsave(&info->lock,flags);
+ tx_stop(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ netif_wake_queue(dev);
+}
+
+/**
+ * called by device driver when transmit completes
+ * reenable network layer transmit if stopped
+ *
+ * info pointer to device instance information
+ */
+static void hdlcdev_tx_done(struct slgt_info *info)
+{
+ if (netif_queue_stopped(info->netdev))
+ netif_wake_queue(info->netdev);
+}
+
+/**
+ * called by device driver when frame received
+ * pass frame to network layer
+ *
+ * info pointer to device instance information
+ * buf pointer to buffer contianing frame data
+ * size count of data bytes in buf
+ */
+static void hdlcdev_rx(struct slgt_info *info, char *buf, int size)
+{
+ struct sk_buff *skb = dev_alloc_skb(size);
+ struct net_device *dev = info->netdev;
+ struct net_device_stats *stats = hdlc_stats(dev);
+
+ DBGINFO(("%s hdlcdev_rx\n", dev->name));
+
+ if (skb == NULL) {
+ DBGERR(("%s: can't alloc skb, drop packet\n", dev->name));
+ stats->rx_dropped++;
+ return;
+ }
+
+ memcpy(skb_put(skb, size),buf,size);
+
+ skb->protocol = hdlc_type_trans(skb, info->netdev);
+
+ stats->rx_packets++;
+ stats->rx_bytes += size;
+
+ netif_rx(skb);
+
+ info->netdev->last_rx = jiffies;
+}
+
+/**
+ * called by device driver when adding device instance
+ * do generic HDLC initialization
+ *
+ * info pointer to device instance information
+ *
+ * returns 0 if success, otherwise error code
+ */
+static int hdlcdev_init(struct slgt_info *info)
+{
+ int rc;
+ struct net_device *dev;
+ hdlc_device *hdlc;
+
+ /* allocate and initialize network and HDLC layer objects */
+
+ if (!(dev = alloc_hdlcdev(info))) {
+ printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name);
+ return -ENOMEM;
+ }
+
+ /* for network layer reporting purposes only */
+ dev->mem_start = info->phys_reg_addr;
+ dev->mem_end = info->phys_reg_addr + SLGT_REG_SIZE - 1;
+ dev->irq = info->irq_level;
+
+ /* network layer callbacks and settings */
+ dev->do_ioctl = hdlcdev_ioctl;
+ dev->open = hdlcdev_open;
+ dev->stop = hdlcdev_close;
+ dev->tx_timeout = hdlcdev_tx_timeout;
+ dev->watchdog_timeo = 10*HZ;
+ dev->tx_queue_len = 50;
+
+ /* generic HDLC layer callbacks and settings */
+ hdlc = dev_to_hdlc(dev);
+ hdlc->attach = hdlcdev_attach;
+ hdlc->xmit = hdlcdev_xmit;
+
+ /* register objects with HDLC layer */
+ if ((rc = register_hdlc_device(dev))) {
+ printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
+ free_netdev(dev);
+ return rc;
+ }
+
+ info->netdev = dev;
+ return 0;
+}
+
+/**
+ * called by device driver when removing device instance
+ * do generic HDLC cleanup
+ *
+ * info pointer to device instance information
+ */
+static void hdlcdev_exit(struct slgt_info *info)
+{
+ unregister_hdlc_device(info->netdev);
+ free_netdev(info->netdev);
+ info->netdev = NULL;
+}
+
+#endif /* ifdef CONFIG_HDLC */
+
+/*
+ * get async data from rx DMA buffers
+ */
+static void rx_async(struct slgt_info *info)
+{
+ struct tty_struct *tty = info->tty;
+ struct mgsl_icount *icount = &info->icount;
+ unsigned int start, end;
+ unsigned char *p;
+ unsigned char status;
+ struct slgt_desc *bufs = info->rbufs;
+ int i, count;
+ int chars = 0;
+ int stat;
+ unsigned char ch;
+
+ start = end = info->rbuf_current;
+
+ while(desc_complete(bufs[end])) {
+ count = desc_count(bufs[end]) - info->rbuf_index;
+ p = bufs[end].buf + info->rbuf_index;
+
+ DBGISR(("%s rx_async count=%d\n", info->device_name, count));
+ DBGDATA(info, p, count, "rx");
+
+ for(i=0 ; i < count; i+=2, p+=2) {
+ if (tty && chars) {
+ tty_flip_buffer_push(tty);
+ chars = 0;
+ }
+ ch = *p;
+ icount->rx++;
+
+ stat = 0;
+
+ if ((status = *(p+1) & (BIT9 + BIT8))) {
+ if (status & BIT9)
+ icount->parity++;
+ else if (status & BIT8)
+ icount->frame++;
+ /* discard char if tty control flags say so */
+ if (status & info->ignore_status_mask)
+ continue;
+ if (status & BIT9)
+ stat = TTY_PARITY;
+ else if (status & BIT8)
+ stat = TTY_FRAME;
+ }
+ if (tty) {
+ tty_insert_flip_char(tty, ch, stat);
+ chars++;
+ }
+ }
+
+ if (i < count) {
+ /* receive buffer not completed */
+ info->rbuf_index += i;
+ info->rx_timer.expires = jiffies + 1;
+ add_timer(&info->rx_timer);
+ break;
+ }
+
+ info->rbuf_index = 0;
+ free_rbufs(info, end, end);
+
+ if (++end == info->rbuf_count)
+ end = 0;
+
+ /* if entire list searched then no frame available */
+ if (end == start)
+ break;
+ }
+
+ if (tty && chars)
+ tty_flip_buffer_push(tty);
+}
+
+/*
+ * return next bottom half action to perform
+ */
+static int bh_action(struct slgt_info *info)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&info->lock,flags);
+
+ if (info->pending_bh & BH_RECEIVE) {
+ info->pending_bh &= ~BH_RECEIVE;
+ rc = BH_RECEIVE;
+ } else if (info->pending_bh & BH_TRANSMIT) {
+ info->pending_bh &= ~BH_TRANSMIT;
+ rc = BH_TRANSMIT;
+ } else if (info->pending_bh & BH_STATUS) {
+ info->pending_bh &= ~BH_STATUS;
+ rc = BH_STATUS;
+ } else {
+ /* Mark BH routine as complete */
+ info->bh_running = 0;
+ info->bh_requested = 0;
+ rc = 0;
+ }
+
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ return rc;
+}
+
+/*
+ * perform bottom half processing
+ */
+static void bh_handler(void* context)
+{
+ struct slgt_info *info = context;
+ int action;
+
+ if (!info)
+ return;
+ info->bh_running = 1;
+
+ while((action = bh_action(info))) {
+ switch (action) {
+ case BH_RECEIVE:
+ DBGBH(("%s bh receive\n", info->device_name));
+ switch(info->params.mode) {
+ case MGSL_MODE_ASYNC:
+ rx_async(info);
+ break;
+ case MGSL_MODE_HDLC:
+ while(rx_get_frame(info));
+ break;
+ case MGSL_MODE_RAW:
+ while(rx_get_buf(info));
+ break;
+ }
+ /* restart receiver if rx DMA buffers exhausted */
+ if (info->rx_restart)
+ rx_start(info);
+ break;
+ case BH_TRANSMIT:
+ bh_transmit(info);
+ break;
+ case BH_STATUS:
+ DBGBH(("%s bh status\n", info->device_name));
+ info->ri_chkcount = 0;
+ info->dsr_chkcount = 0;
+ info->dcd_chkcount = 0;
+ info->cts_chkcount = 0;
+ break;
+ default:
+ DBGBH(("%s unknown action\n", info->device_name));
+ break;
+ }
+ }
+ DBGBH(("%s bh_handler exit\n", info->device_name));
+}
+
+static void bh_transmit(struct slgt_info *info)
+{
+ struct tty_struct *tty = info->tty;
+
+ DBGBH(("%s bh_transmit\n", info->device_name));
+ if (tty) {
+ tty_wakeup(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+}
+
+static void dsr_change(struct slgt_info *info)
+{
+ get_signals(info);
+ DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals));
+ if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
+ slgt_irq_off(info, IRQ_DSR);
+ return;
+ }
+ info->icount.dsr++;
+ if (info->signals & SerialSignal_DSR)
+ info->input_signal_events.dsr_up++;
+ else
+ info->input_signal_events.dsr_down++;
+ wake_up_interruptible(&info->status_event_wait_q);
+ wake_up_interruptible(&info->event_wait_q);
+ info->pending_bh |= BH_STATUS;
+}
+
+static void cts_change(struct slgt_info *info)
+{
+ get_signals(info);
+ DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals));
+ if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
+ slgt_irq_off(info, IRQ_CTS);
+ return;
+ }
+ info->icount.cts++;
+ if (info->signals & SerialSignal_CTS)
+ info->input_signal_events.cts_up++;
+ else
+ info->input_signal_events.cts_down++;
+ wake_up_interruptible(&info->status_event_wait_q);
+ wake_up_interruptible(&info->event_wait_q);
+ info->pending_bh |= BH_STATUS;
+
+ if (info->flags & ASYNC_CTS_FLOW) {
+ if (info->tty) {
+ if (info->tty->hw_stopped) {
+ if (info->signals & SerialSignal_CTS) {
+ info->tty->hw_stopped = 0;
+ info->pending_bh |= BH_TRANSMIT;
+ return;
+ }
+ } else {
+ if (!(info->signals & SerialSignal_CTS))
+ info->tty->hw_stopped = 1;
+ }
+ }
+ }
+}
+
+static void dcd_change(struct slgt_info *info)
+{
+ get_signals(info);
+ DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals));
+ if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
+ slgt_irq_off(info, IRQ_DCD);
+ return;
+ }
+ info->icount.dcd++;
+ if (info->signals & SerialSignal_DCD) {
+ info->input_signal_events.dcd_up++;
+ } else {
+ info->input_signal_events.dcd_down++;
+ }
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlc_set_carrier(info->signals & SerialSignal_DCD, info->netdev);
+#endif
+ wake_up_interruptible(&info->status_event_wait_q);
+ wake_up_interruptible(&info->event_wait_q);
+ info->pending_bh |= BH_STATUS;
+
+ if (info->flags & ASYNC_CHECK_CD) {
+ if (info->signals & SerialSignal_DCD)
+ wake_up_interruptible(&info->open_wait);
+ else {
+ if (info->tty)
+ tty_hangup(info->tty);
+ }
+ }
+}
+
+static void ri_change(struct slgt_info *info)
+{
+ get_signals(info);
+ DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals));
+ if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
+ slgt_irq_off(info, IRQ_RI);
+ return;
+ }
+ info->icount.dcd++;
+ if (info->signals & SerialSignal_RI) {
+ info->input_signal_events.ri_up++;
+ } else {
+ info->input_signal_events.ri_down++;
+ }
+ wake_up_interruptible(&info->status_event_wait_q);
+ wake_up_interruptible(&info->event_wait_q);
+ info->pending_bh |= BH_STATUS;
+}
+
+static void isr_serial(struct slgt_info *info)
+{
+ unsigned short status = rd_reg16(info, SSR);
+
+ DBGISR(("%s isr_serial status=%04X\n", info->device_name, status));
+
+ wr_reg16(info, SSR, status); /* clear pending */
+
+ info->irq_occurred = 1;
+
+ if (info->params.mode == MGSL_MODE_ASYNC) {
+ if (status & IRQ_TXIDLE) {
+ if (info->tx_count)
+ isr_txeom(info, status);
+ }
+ if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
+ info->icount.brk++;
+ /* process break detection if tty control allows */
+ if (info->tty) {
+ if (!(status & info->ignore_status_mask)) {
+ if (info->read_status_mask & MASK_BREAK) {
+ tty_insert_flip_char(info->tty, 0, TTY_BREAK);
+ if (info->flags & ASYNC_SAK)
+ do_SAK(info->tty);
+ }
+ }
+ }
+ }
+ } else {
+ if (status & (IRQ_TXIDLE + IRQ_TXUNDER))
+ isr_txeom(info, status);
+
+ if (status & IRQ_RXIDLE) {
+ if (status & RXIDLE)
+ info->icount.rxidle++;
+ else
+ info->icount.exithunt++;
+ wake_up_interruptible(&info->event_wait_q);
+ }
+
+ if (status & IRQ_RXOVER)
+ rx_start(info);
+ }
+
+ if (status & IRQ_DSR)
+ dsr_change(info);
+ if (status & IRQ_CTS)
+ cts_change(info);
+ if (status & IRQ_DCD)
+ dcd_change(info);
+ if (status & IRQ_RI)
+ ri_change(info);
+}
+
+static void isr_rdma(struct slgt_info *info)
+{
+ unsigned int status = rd_reg32(info, RDCSR);
+
+ DBGISR(("%s isr_rdma status=%08x\n", info->device_name, status));
+
+ /* RDCSR (rx DMA control/status)
+ *
+ * 31..07 reserved
+ * 06 save status byte to DMA buffer
+ * 05 error
+ * 04 eol (end of list)
+ * 03 eob (end of buffer)
+ * 02 IRQ enable
+ * 01 reset
+ * 00 enable
+ */
+ wr_reg32(info, RDCSR, status); /* clear pending */
+
+ if (status & (BIT5 + BIT4)) {
+ DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name));
+ info->rx_restart = 1;
+ }
+ info->pending_bh |= BH_RECEIVE;
+}
+
+static void isr_tdma(struct slgt_info *info)
+{
+ unsigned int status = rd_reg32(info, TDCSR);
+
+ DBGISR(("%s isr_tdma status=%08x\n", info->device_name, status));
+
+ /* TDCSR (tx DMA control/status)
+ *
+ * 31..06 reserved
+ * 05 error
+ * 04 eol (end of list)
+ * 03 eob (end of buffer)
+ * 02 IRQ enable
+ * 01 reset
+ * 00 enable
+ */
+ wr_reg32(info, TDCSR, status); /* clear pending */
+
+ if (status & (BIT5 + BIT4 + BIT3)) {
+ // another transmit buffer has completed
+ // run bottom half to get more send data from user
+ info->pending_bh |= BH_TRANSMIT;
+ }
+}
+
+static void isr_txeom(struct slgt_info *info, unsigned short status)
+{
+ DBGISR(("%s txeom status=%04x\n", info->device_name, status));
+
+ slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
+ tdma_reset(info);
+ reset_tbufs(info);
+ if (status & IRQ_TXUNDER) {
+ unsigned short val = rd_reg16(info, TCR);
+ wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
+ wr_reg16(info, TCR, val); /* clear reset bit */
+ }
+
+ if (info->tx_active) {
+ if (info->params.mode != MGSL_MODE_ASYNC) {
+ if (status & IRQ_TXUNDER)
+ info->icount.txunder++;
+ else if (status & IRQ_TXIDLE)
+ info->icount.txok++;
+ }
+
+ info->tx_active = 0;
+ info->tx_count = 0;
+
+ del_timer(&info->tx_timer);
+
+ if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) {
+ info->signals &= ~SerialSignal_RTS;
+ info->drop_rts_on_tx_done = 0;
+ set_signals(info);
+ }
+
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlcdev_tx_done(info);
+ else
+#endif
+ {
+ if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
+ tx_stop(info);
+ return;
+ }
+ info->pending_bh |= BH_TRANSMIT;
+ }
+ }
+}
+
+/* interrupt service routine
+ *
+ * irq interrupt number
+ * dev_id device ID supplied during interrupt registration
+ * regs interrupted processor context
+ */
+static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct slgt_info *info;
+ unsigned int gsr;
+ unsigned int i;
+
+ DBGISR(("slgt_interrupt irq=%d entry\n", irq));
+
+ info = dev_id;
+ if (!info)
+ return IRQ_NONE;
+
+ spin_lock(&info->lock);
+
+ while((gsr = rd_reg32(info, GSR) & 0xffffff00)) {
+ DBGISR(("%s gsr=%08x\n", info->device_name, gsr));
+ info->irq_occurred = 1;
+ for(i=0; i < info->port_count ; i++) {
+ if (info->port_array[i] == NULL)
+ continue;
+ if (gsr & (BIT8 << i))
+ isr_serial(info->port_array[i]);
+ if (gsr & (BIT16 << (i*2)))
+ isr_rdma(info->port_array[i]);
+ if (gsr & (BIT17 << (i*2)))
+ isr_tdma(info->port_array[i]);
+ }
+ }
+
+ for(i=0; i < info->port_count ; i++) {
+ struct slgt_info *port = info->port_array[i];
+
+ if (port && (port->count || port->netcount) &&
+ port->pending_bh && !port->bh_running &&
+ !port->bh_requested) {
+ DBGISR(("%s bh queued\n", port->device_name));
+ schedule_work(&port->task);
+ port->bh_requested = 1;
+ }
+ }
+
+ spin_unlock(&info->lock);
+
+ DBGISR(("slgt_interrupt irq=%d exit\n", irq));
+ return IRQ_HANDLED;
+}
+
+static int startup(struct slgt_info *info)
+{
+ DBGINFO(("%s startup\n", info->device_name));
+
+ if (info->flags & ASYNC_INITIALIZED)
+ return 0;
+
+ if (!info->tx_buf) {
+ info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL);
+ if (!info->tx_buf) {
+ DBGERR(("%s can't allocate tx buffer\n", info->device_name));
+ return -ENOMEM;
+ }
+ }
+
+ info->pending_bh = 0;
+
+ memset(&info->icount, 0, sizeof(info->icount));
+
+ /* program hardware for current parameters */
+ change_params(info);
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags |= ASYNC_INITIALIZED;
+
+ return 0;
+}
+
+/*
+ * called by close() and hangup() to shutdown hardware
+ */
+static void shutdown(struct slgt_info *info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+ DBGINFO(("%s shutdown\n", info->device_name));
+
+ /* clear status wait queue because status changes */
+ /* can't happen after shutting down the hardware */
+ wake_up_interruptible(&info->status_event_wait_q);
+ wake_up_interruptible(&info->event_wait_q);
+
+ del_timer_sync(&info->tx_timer);
+ del_timer_sync(&info->rx_timer);
+
+ kfree(info->tx_buf);
+ info->tx_buf = NULL;
+
+ spin_lock_irqsave(&info->lock,flags);
+
+ tx_stop(info);
+ rx_stop(info);
+
+ slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
+
+ if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
+ info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+ set_signals(info);
+ }
+
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+}
+
+static void program_hw(struct slgt_info *info)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock,flags);
+
+ rx_stop(info);
+ tx_stop(info);
+
+ if (info->params.mode == MGSL_MODE_HDLC ||
+ info->params.mode == MGSL_MODE_RAW ||
+ info->netcount)
+ hdlc_mode(info);
+ else
+ async_mode(info);
+
+ set_signals(info);
+
+ info->dcd_chkcount = 0;
+ info->cts_chkcount = 0;
+ info->ri_chkcount = 0;
+ info->dsr_chkcount = 0;
+
+ slgt_irq_on(info, IRQ_DCD | IRQ_CTS | IRQ_DSR);
+ get_signals(info);
+
+ if (info->netcount ||
+ (info->tty && info->tty->termios->c_cflag & CREAD))
+ rx_start(info);
+
+ spin_unlock_irqrestore(&info->lock,flags);
+}
+
+/*
+ * reconfigure adapter based on new parameters
+ */
+static void change_params(struct slgt_info *info)
+{
+ unsigned cflag;
+ int bits_per_char;
+
+ if (!info->tty || !info->tty->termios)
+ return;
+ DBGINFO(("%s change_params\n", info->device_name));
+
+ cflag = info->tty->termios->c_cflag;
+
+ /* if B0 rate (hangup) specified then negate DTR and RTS */
+ /* otherwise assert DTR and RTS */
+ if (cflag & CBAUD)
+ info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+ else
+ info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
+
+ /* byte size and parity */
+
+ switch (cflag & CSIZE) {
+ case CS5: info->params.data_bits = 5; break;
+ case CS6: info->params.data_bits = 6; break;
+ case CS7: info->params.data_bits = 7; break;
+ case CS8: info->params.data_bits = 8; break;
+ default: info->params.data_bits = 7; break;
+ }
+
+ info->params.stop_bits = (cflag & CSTOPB) ? 2 : 1;
+
+ if (cflag & PARENB)
+ info->params.parity = (cflag & PARODD) ? ASYNC_PARITY_ODD : ASYNC_PARITY_EVEN;
+ else
+ info->params.parity = ASYNC_PARITY_NONE;
+
+ /* calculate number of jiffies to transmit a full
+ * FIFO (32 bytes) at specified data rate
+ */
+ bits_per_char = info->params.data_bits +
+ info->params.stop_bits + 1;
+
+ info->params.data_rate = tty_get_baud_rate(info->tty);
+
+ if (info->params.data_rate) {
+ info->timeout = (32*HZ*bits_per_char) /
+ info->params.data_rate;
+ }
+ info->timeout += HZ/50; /* Add .02 seconds of slop */
+
+ if (cflag & CRTSCTS)
+ info->flags |= ASYNC_CTS_FLOW;
+ else
+ info->flags &= ~ASYNC_CTS_FLOW;
+
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else
+ info->flags |= ASYNC_CHECK_CD;
+
+ /* process tty input control flags */
+
+ info->read_status_mask = IRQ_RXOVER;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= MASK_PARITY | MASK_FRAMING;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= MASK_BREAK;
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING;
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= MASK_BREAK;
+ /* If ignoring parity and break indicators, ignore
+ * overruns too. (For real raw support).
+ */
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= MASK_OVERRUN;
+ }
+
+ program_hw(info);
+}
+
+static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount)
+{
+ DBGINFO(("%s get_stats\n", info->device_name));
+ if (!user_icount) {
+ memset(&info->icount, 0, sizeof(info->icount));
+ } else {
+ if (copy_to_user(user_icount, &info->icount, sizeof(struct mgsl_icount)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int get_params(struct slgt_info *info, MGSL_PARAMS __user *user_params)
+{
+ DBGINFO(("%s get_params\n", info->device_name));
+ if (copy_to_user(user_params, &info->params, sizeof(MGSL_PARAMS)))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params)
+{
+ unsigned long flags;
+ MGSL_PARAMS tmp_params;
+
+ DBGINFO(("%s set_params\n", info->device_name));
+ if (copy_from_user(&tmp_params, new_params, sizeof(MGSL_PARAMS)))
+ return -EFAULT;
+
+ spin_lock_irqsave(&info->lock, flags);
+ memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS));
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ change_params(info);
+
+ return 0;
+}
+
+static int get_txidle(struct slgt_info *info, int __user *idle_mode)
+{
+ DBGINFO(("%s get_txidle=%d\n", info->device_name, info->idle_mode));
+ if (put_user(info->idle_mode, idle_mode))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_txidle(struct slgt_info *info, int idle_mode)
+{
+ unsigned long flags;
+ DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode));
+ spin_lock_irqsave(&info->lock,flags);
+ info->idle_mode = idle_mode;
+ tx_set_idle(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ return 0;
+}
+
+static int tx_enable(struct slgt_info *info, int enable)
+{
+ unsigned long flags;
+ DBGINFO(("%s tx_enable(%d)\n", info->device_name, enable));
+ spin_lock_irqsave(&info->lock,flags);
+ if (enable) {
+ if (!info->tx_enabled)
+ tx_start(info);
+ } else {
+ if (info->tx_enabled)
+ tx_stop(info);
+ }
+ spin_unlock_irqrestore(&info->lock,flags);
+ return 0;
+}
+
+/*
+ * abort transmit HDLC frame
+ */
+static int tx_abort(struct slgt_info *info)
+{
+ unsigned long flags;
+ DBGINFO(("%s tx_abort\n", info->device_name));
+ spin_lock_irqsave(&info->lock,flags);
+ tdma_reset(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ return 0;
+}
+
+static int rx_enable(struct slgt_info *info, int enable)
+{
+ unsigned long flags;
+ DBGINFO(("%s rx_enable(%d)\n", info->device_name, enable));
+ spin_lock_irqsave(&info->lock,flags);
+ if (enable) {
+ if (!info->rx_enabled)
+ rx_start(info);
+ } else {
+ if (info->rx_enabled)
+ rx_stop(info);
+ }
+ spin_unlock_irqrestore(&info->lock,flags);
+ return 0;
+}
+
+/*
+ * wait for specified event to occur
+ */
+static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr)
+{
+ unsigned long flags;
+ int s;
+ int rc=0;
+ struct mgsl_icount cprev, cnow;
+ int events;
+ int mask;
+ struct _input_signal_events oldsigs, newsigs;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (get_user(mask, mask_ptr))
+ return -EFAULT;
+
+ DBGINFO(("%s wait_mgsl_event(%d)\n", info->device_name, mask));
+
+ spin_lock_irqsave(&info->lock,flags);
+
+ /* return immediately if state matches requested events */
+ get_signals(info);
+ s = info->signals;
+
+ events = mask &
+ ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
+ ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
+ ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
+ ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) );
+ if (events) {
+ spin_unlock_irqrestore(&info->lock,flags);
+ goto exit;
+ }
+
+ /* save current irq counts */
+ cprev = info->icount;
+ oldsigs = info->input_signal_events;
+
+ /* enable hunt and idle irqs if needed */
+ if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) {
+ unsigned short val = rd_reg16(info, SCR);
+ if (!(val & IRQ_RXIDLE))
+ wr_reg16(info, SCR, (unsigned short)(val | IRQ_RXIDLE));
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&info->event_wait_q, &wait);
+
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ for(;;) {
+ schedule();
+ if (signal_pending(current)) {
+ rc = -ERESTARTSYS;
+ break;
+ }
+
+ /* get current irq counts */
+ spin_lock_irqsave(&info->lock,flags);
+ cnow = info->icount;
+ newsigs = info->input_signal_events;
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ /* if no change, wait aborted for some reason */
+ if (newsigs.dsr_up == oldsigs.dsr_up &&
+ newsigs.dsr_down == oldsigs.dsr_down &&
+ newsigs.dcd_up == oldsigs.dcd_up &&
+ newsigs.dcd_down == oldsigs.dcd_down &&
+ newsigs.cts_up == oldsigs.cts_up &&
+ newsigs.cts_down == oldsigs.cts_down &&
+ newsigs.ri_up == oldsigs.ri_up &&
+ newsigs.ri_down == oldsigs.ri_down &&
+ cnow.exithunt == cprev.exithunt &&
+ cnow.rxidle == cprev.rxidle) {
+ rc = -EIO;
+ break;
+ }
+
+ events = mask &
+ ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) +
+ (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) +
+ (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) +
+ (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) +
+ (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) +
+ (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) +
+ (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) +
+ (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) +
+ (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) +
+ (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) );
+ if (events)
+ break;
+
+ cprev = cnow;
+ oldsigs = newsigs;
+ }
+
+ remove_wait_queue(&info->event_wait_q, &wait);
+ set_current_state(TASK_RUNNING);
+
+
+ if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
+ spin_lock_irqsave(&info->lock,flags);
+ if (!waitqueue_active(&info->event_wait_q)) {
+ /* disable enable exit hunt mode/idle rcvd IRQs */
+ wr_reg16(info, SCR,
+ (unsigned short)(rd_reg16(info, SCR) & ~IRQ_RXIDLE));
+ }
+ spin_unlock_irqrestore(&info->lock,flags);
+ }
+exit:
+ if (rc == 0)
+ rc = put_user(events, mask_ptr);
+ return rc;
+}
+
+static int get_interface(struct slgt_info *info, int __user *if_mode)
+{
+ DBGINFO(("%s get_interface=%x\n", info->device_name, info->if_mode));
+ if (put_user(info->if_mode, if_mode))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_interface(struct slgt_info *info, int if_mode)
+{
+ unsigned long flags;
+ unsigned char val;
+
+ DBGINFO(("%s set_interface=%x)\n", info->device_name, if_mode));
+ spin_lock_irqsave(&info->lock,flags);
+ info->if_mode = if_mode;
+
+ msc_set_vcr(info);
+
+ /* TCR (tx control) 07 1=RTS driver control */
+ val = rd_reg16(info, TCR);
+ if (info->if_mode & MGSL_INTERFACE_RTS_EN)
+ val |= BIT7;
+ else
+ val &= ~BIT7;
+ wr_reg16(info, TCR, val);
+
+ spin_unlock_irqrestore(&info->lock,flags);
+ return 0;
+}
+
+static int modem_input_wait(struct slgt_info *info,int arg)
+{
+ unsigned long flags;
+ int rc;
+ struct mgsl_icount cprev, cnow;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /* save current irq counts */
+ spin_lock_irqsave(&info->lock,flags);
+ cprev = info->icount;
+ add_wait_queue(&info->status_event_wait_q, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ for(;;) {
+ schedule();
+ if (signal_pending(current)) {
+ rc = -ERESTARTSYS;
+ break;
+ }
+
+ /* get new irq counts */
+ spin_lock_irqsave(&info->lock,flags);
+ cnow = info->icount;
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ /* if no change, wait aborted for some reason */
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+ rc = -EIO;
+ break;
+ }
+
+ /* check for change in caller specified modem input */
+ if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) ||
+ (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) ||
+ (arg & TIOCM_CD && cnow.dcd != cprev.dcd) ||
+ (arg & TIOCM_CTS && cnow.cts != cprev.cts)) {
+ rc = 0;
+ break;
+ }
+
+ cprev = cnow;
+ }
+ remove_wait_queue(&info->status_event_wait_q, &wait);
+ set_current_state(TASK_RUNNING);
+ return rc;
+}
+
+/*
+ * return state of serial control and status signals
+ */
+static int tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned int result;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock,flags);
+ get_signals(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ result = ((info->signals & SerialSignal_RTS) ? TIOCM_RTS:0) +
+ ((info->signals & SerialSignal_DTR) ? TIOCM_DTR:0) +
+ ((info->signals & SerialSignal_DCD) ? TIOCM_CAR:0) +
+ ((info->signals & SerialSignal_RI) ? TIOCM_RNG:0) +
+ ((info->signals & SerialSignal_DSR) ? TIOCM_DSR:0) +
+ ((info->signals & SerialSignal_CTS) ? TIOCM_CTS:0);
+
+ DBGINFO(("%s tiocmget value=%08X\n", info->device_name, result));
+ return result;
+}
+
+/*
+ * set modem control signals (DTR/RTS)
+ *
+ * cmd signal command: TIOCMBIS = set bit TIOCMBIC = clear bit
+ * TIOCMSET = set/clear signal values
+ * value bit mask for command
+ */
+static int tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct slgt_info *info = tty->driver_data;
+ unsigned long flags;
+
+ DBGINFO(("%s tiocmset(%x,%x)\n", info->device_name, set, clear));
+
+ if (set & TIOCM_RTS)
+ info->signals |= SerialSignal_RTS;
+ if (set & TIOCM_DTR)
+ info->signals |= SerialSignal_DTR;
+ if (clear & TIOCM_RTS)
+ info->signals &= ~SerialSignal_RTS;
+ if (clear & TIOCM_DTR)
+ info->signals &= ~SerialSignal_DTR;
+
+ spin_lock_irqsave(&info->lock,flags);
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ return 0;
+}
+
+/*
+ * block current process until the device is ready to open
+ */
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct slgt_info *info)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int retval;
+ int do_clocal = 0, extra_count = 0;
+ unsigned long flags;
+
+ DBGINFO(("%s block_til_ready\n", tty->driver->name));
+
+ if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
+ /* nonblock mode is set or port is not enabled */
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+
+ /* Wait for 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
+ * close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+
+ spin_lock_irqsave(&info->lock, flags);
+ if (!tty_hung_up_p(filp)) {
+ extra_count = 1;
+ info->count--;
+ }
+ spin_unlock_irqrestore(&info->lock, flags);
+ info->blocked_open++;
+
+ while (1) {
+ if ((tty->termios->c_cflag & CBAUD)) {
+ spin_lock_irqsave(&info->lock,flags);
+ info->signals |= SerialSignal_RTS + SerialSignal_DTR;
+ set_signals(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
+ retval = (info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS;
+ break;
+ }
+
+ spin_lock_irqsave(&info->lock,flags);
+ get_signals(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ if (!(info->flags & ASYNC_CLOSING) &&
+ (do_clocal || (info->signals & SerialSignal_DCD)) ) {
+ break;
+ }
+
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+
+ DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
+ schedule();
+ }
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&info->open_wait, &wait);
+
+ if (extra_count)
+ info->count++;
+ info->blocked_open--;
+
+ if (!retval)
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+
+ DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
+ return retval;
+}
+
+static int alloc_tmp_rbuf(struct slgt_info *info)
+{
+ info->tmp_rbuf = kmalloc(info->max_frame_size, GFP_KERNEL);
+ if (info->tmp_rbuf == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void free_tmp_rbuf(struct slgt_info *info)
+{
+ kfree(info->tmp_rbuf);
+ info->tmp_rbuf = NULL;
+}
+
+/*
+ * allocate DMA descriptor lists.
+ */
+static int alloc_desc(struct slgt_info *info)
+{
+ unsigned int i;
+ unsigned int pbufs;
+
+ /* allocate memory to hold descriptor lists */
+ info->bufs = pci_alloc_consistent(info->pdev, DESC_LIST_SIZE, &info->bufs_dma_addr);
+ if (info->bufs == NULL)
+ return -ENOMEM;
+
+ memset(info->bufs, 0, DESC_LIST_SIZE);
+
+ info->rbufs = (struct slgt_desc*)info->bufs;
+ info->tbufs = ((struct slgt_desc*)info->bufs) + info->rbuf_count;
+
+ pbufs = (unsigned int)info->bufs_dma_addr;
+
+ /*
+ * Build circular lists of descriptors
+ */
+
+ for (i=0; i < info->rbuf_count; i++) {
+ /* physical address of this descriptor */
+ info->rbufs[i].pdesc = pbufs + (i * sizeof(struct slgt_desc));
+
+ /* physical address of next descriptor */
+ if (i == info->rbuf_count - 1)
+ info->rbufs[i].next = cpu_to_le32(pbufs);
+ else
+ info->rbufs[i].next = cpu_to_le32(pbufs + ((i+1) * sizeof(struct slgt_desc)));
+ set_desc_count(info->rbufs[i], DMABUFSIZE);
+ }
+
+ for (i=0; i < info->tbuf_count; i++) {
+ /* physical address of this descriptor */
+ info->tbufs[i].pdesc = pbufs + ((info->rbuf_count + i) * sizeof(struct slgt_desc));
+
+ /* physical address of next descriptor */
+ if (i == info->tbuf_count - 1)
+ info->tbufs[i].next = cpu_to_le32(pbufs + info->rbuf_count * sizeof(struct slgt_desc));
+ else
+ info->tbufs[i].next = cpu_to_le32(pbufs + ((info->rbuf_count + i + 1) * sizeof(struct slgt_desc)));
+ }
+
+ return 0;
+}
+
+static void free_desc(struct slgt_info *info)
+{
+ if (info->bufs != NULL) {
+ pci_free_consistent(info->pdev, DESC_LIST_SIZE, info->bufs, info->bufs_dma_addr);
+ info->bufs = NULL;
+ info->rbufs = NULL;
+ info->tbufs = NULL;
+ }
+}
+
+static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count)
+{
+ int i;
+ for (i=0; i < count; i++) {
+ if ((bufs[i].buf = pci_alloc_consistent(info->pdev, DMABUFSIZE, &bufs[i].buf_dma_addr)) == NULL)
+ return -ENOMEM;
+ bufs[i].pbuf = cpu_to_le32((unsigned int)bufs[i].buf_dma_addr);
+ }
+ return 0;
+}
+
+static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count)
+{
+ int i;
+ for (i=0; i < count; i++) {
+ if (bufs[i].buf == NULL)
+ continue;
+ pci_free_consistent(info->pdev, DMABUFSIZE, bufs[i].buf, bufs[i].buf_dma_addr);
+ bufs[i].buf = NULL;
+ }
+}
+
+static int alloc_dma_bufs(struct slgt_info *info)
+{
+ info->rbuf_count = 32;
+ info->tbuf_count = 32;
+
+ if (alloc_desc(info) < 0 ||
+ alloc_bufs(info, info->rbufs, info->rbuf_count) < 0 ||
+ alloc_bufs(info, info->tbufs, info->tbuf_count) < 0 ||
+ alloc_tmp_rbuf(info) < 0) {
+ DBGERR(("%s DMA buffer alloc fail\n", info->device_name));
+ return -ENOMEM;
+ }
+ reset_rbufs(info);
+ return 0;
+}
+
+static void free_dma_bufs(struct slgt_info *info)
+{
+ if (info->bufs) {
+ free_bufs(info, info->rbufs, info->rbuf_count);
+ free_bufs(info, info->tbufs, info->tbuf_count);
+ free_desc(info);
+ }
+ free_tmp_rbuf(info);
+}
+
+static int claim_resources(struct slgt_info *info)
+{
+ if (request_mem_region(info->phys_reg_addr, SLGT_REG_SIZE, "synclink_gt") == NULL) {
+ DBGERR(("%s reg addr conflict, addr=%08X\n",
+ info->device_name, info->phys_reg_addr));
+ info->init_error = DiagStatus_AddressConflict;
+ goto errout;
+ }
+ else
+ info->reg_addr_requested = 1;
+
+ info->reg_addr = ioremap(info->phys_reg_addr, PAGE_SIZE);
+ if (!info->reg_addr) {
+ DBGERR(("%s cant map device registers, addr=%08X\n",
+ info->device_name, info->phys_reg_addr));
+ info->init_error = DiagStatus_CantAssignPciResources;
+ goto errout;
+ }
+ info->reg_addr += info->reg_offset;
+ return 0;
+
+errout:
+ release_resources(info);
+ return -ENODEV;
+}
+
+static void release_resources(struct slgt_info *info)
+{
+ if (info->irq_requested) {
+ free_irq(info->irq_level, info);
+ info->irq_requested = 0;
+ }
+
+ if (info->reg_addr_requested) {
+ release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE);
+ info->reg_addr_requested = 0;
+ }
+
+ if (info->reg_addr) {
+ iounmap(info->reg_addr - info->reg_offset);
+ info->reg_addr = NULL;
+ }
+}
+
+/* Add the specified device instance data structure to the
+ * global linked list of devices and increment the device count.
+ */
+static void add_device(struct slgt_info *info)
+{
+ char *devstr;
+
+ info->next_device = NULL;
+ info->line = slgt_device_count;
+ sprintf(info->device_name, "%s%d", tty_dev_prefix, info->line);
+
+ if (info->line < MAX_DEVICES) {
+ if (maxframe[info->line])
+ info->max_frame_size = maxframe[info->line];
+ info->dosyncppp = dosyncppp[info->line];
+ }
+
+ slgt_device_count++;
+
+ if (!slgt_device_list)
+ slgt_device_list = info;
+ else {
+ struct slgt_info *current_dev = slgt_device_list;
+ while(current_dev->next_device)
+ current_dev = current_dev->next_device;
+ current_dev->next_device = info;
+ }
+
+ if (info->max_frame_size < 4096)
+ info->max_frame_size = 4096;
+ else if (info->max_frame_size > 65535)
+ info->max_frame_size = 65535;
+
+ switch(info->pdev->device) {
+ case SYNCLINK_GT_DEVICE_ID:
+ devstr = "GT";
+ break;
+ case SYNCLINK_GT4_DEVICE_ID:
+ devstr = "GT4";
+ break;
+ case SYNCLINK_AC_DEVICE_ID:
+ devstr = "AC";
+ info->params.mode = MGSL_MODE_ASYNC;
+ break;
+ default:
+ devstr = "(unknown model)";
+ }
+ printk("SyncLink %s %s IO=%08x IRQ=%d MaxFrameSize=%u\n",
+ devstr, info->device_name, info->phys_reg_addr,
+ info->irq_level, info->max_frame_size);
+
+#ifdef CONFIG_HDLC
+ hdlcdev_init(info);
+#endif
+}
+
+/*
+ * allocate device instance structure, return NULL on failure
+ */
+static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
+{
+ struct slgt_info *info;
+
+ info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL);
+
+ if (!info) {
+ DBGERR(("%s device alloc failed adapter=%d port=%d\n",
+ driver_name, adapter_num, port_num));
+ } else {
+ memset(info, 0, sizeof(struct slgt_info));
+ info->magic = MGSL_MAGIC;
+ INIT_WORK(&info->task, bh_handler, info);
+ info->max_frame_size = 4096;
+ info->raw_rx_size = DMABUFSIZE;
+ info->close_delay = 5*HZ/10;
+ info->closing_wait = 30*HZ;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->status_event_wait_q);
+ init_waitqueue_head(&info->event_wait_q);
+ spin_lock_init(&info->netlock);
+ memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
+ info->idle_mode = HDLC_TXIDLE_FLAGS;
+ info->adapter_num = adapter_num;
+ info->port_num = port_num;
+
+ init_timer(&info->tx_timer);
+ info->tx_timer.data = (unsigned long)info;
+ info->tx_timer.function = tx_timeout;
+
+ init_timer(&info->rx_timer);
+ info->rx_timer.data = (unsigned long)info;
+ info->rx_timer.function = rx_timeout;
+
+ /* Copy configuration info to device instance data */
+ info->pdev = pdev;
+ info->irq_level = pdev->irq;
+ info->phys_reg_addr = pci_resource_start(pdev,0);
+
+ /* veremap works on page boundaries
+ * map full page starting at the page boundary
+ */
+ info->reg_offset = info->phys_reg_addr & (PAGE_SIZE-1);
+ info->phys_reg_addr &= ~(PAGE_SIZE-1);
+
+ info->bus_type = MGSL_BUS_TYPE_PCI;
+ info->irq_flags = SA_SHIRQ;
+
+ info->init_error = -1; /* assume error, set to 0 on successful init */
+ }
+
+ return info;
+}
+
+static void device_init(int adapter_num, struct pci_dev *pdev)
+{
+ struct slgt_info *port_array[SLGT_MAX_PORTS];
+ int i;
+ int port_count = 1;
+
+ if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
+ port_count = 4;
+
+ /* allocate device instances for all ports */
+ for (i=0; i < port_count; ++i) {
+ port_array[i] = alloc_dev(adapter_num, i, pdev);
+ if (port_array[i] == NULL) {
+ for (--i; i >= 0; --i)
+ kfree(port_array[i]);
+ return;
+ }
+ }
+
+ /* give copy of port_array to all ports and add to device list */
+ for (i=0; i < port_count; ++i) {
+ memcpy(port_array[i]->port_array, port_array, sizeof(port_array));
+ add_device(port_array[i]);
+ port_array[i]->port_count = port_count;
+ spin_lock_init(&port_array[i]->lock);
+ }
+
+ /* Allocate and claim adapter resources */
+ if (!claim_resources(port_array[0])) {
+
+ alloc_dma_bufs(port_array[0]);
+
+ /* copy resource information from first port to others */
+ for (i = 1; i < port_count; ++i) {
+ port_array[i]->lock = port_array[0]->lock;
+ port_array[i]->irq_level = port_array[0]->irq_level;
+ port_array[i]->reg_addr = port_array[0]->reg_addr;
+ alloc_dma_bufs(port_array[i]);
+ }
+
+ if (request_irq(port_array[0]->irq_level,
+ slgt_interrupt,
+ port_array[0]->irq_flags,
+ port_array[0]->device_name,
+ port_array[0]) < 0) {
+ DBGERR(("%s request_irq failed IRQ=%d\n",
+ port_array[0]->device_name,
+ port_array[0]->irq_level));
+ } else {
+ port_array[0]->irq_requested = 1;
+ adapter_test(port_array[0]);
+ for (i=1 ; i < port_count ; i++)
+ port_array[i]->init_error = port_array[0]->init_error;
+ }
+ }
+}
+
+static int __devinit init_one(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ if (pci_enable_device(dev)) {
+ printk("error enabling pci device %p\n", dev);
+ return -EIO;
+ }
+ pci_set_master(dev);
+ device_init(slgt_device_count, dev);
+ return 0;
+}
+
+static void __devexit remove_one(struct pci_dev *dev)
+{
+}
+
+static struct tty_operations ops = {
+ .open = open,
+ .close = close,
+ .write = write,
+ .put_char = put_char,
+ .flush_chars = flush_chars,
+ .write_room = write_room,
+ .chars_in_buffer = chars_in_buffer,
+ .flush_buffer = flush_buffer,
+ .ioctl = ioctl,
+ .throttle = throttle,
+ .unthrottle = unthrottle,
+ .send_xchar = send_xchar,
+ .break_ctl = set_break,
+ .wait_until_sent = wait_until_sent,
+ .read_proc = read_proc,
+ .set_termios = set_termios,
+ .stop = tx_hold,
+ .start = tx_release,
+ .hangup = hangup,
+ .tiocmget = tiocmget,
+ .tiocmset = tiocmset,
+};
+
+static void slgt_cleanup(void)
+{
+ int rc;
+ struct slgt_info *info;
+ struct slgt_info *tmp;
+
+ printk("unload %s %s\n", driver_name, driver_version);
+
+ if (serial_driver) {
+ if ((rc = tty_unregister_driver(serial_driver)))
+ DBGERR(("tty_unregister_driver error=%d\n", rc));
+ put_tty_driver(serial_driver);
+ }
+
+ /* reset devices */
+ info = slgt_device_list;
+ while(info) {
+ reset_port(info);
+ info = info->next_device;
+ }
+
+ /* release devices */
+ info = slgt_device_list;
+ while(info) {
+#ifdef CONFIG_HDLC
+ hdlcdev_exit(info);
+#endif
+ free_dma_bufs(info);
+ free_tmp_rbuf(info);
+ if (info->port_num == 0)
+ release_resources(info);
+ tmp = info;
+ info = info->next_device;
+ kfree(tmp);
+ }
+
+ if (pci_registered)
+ pci_unregister_driver(&pci_driver);
+}
+
+/*
+ * Driver initialization entry point.
+ */
+static int __init slgt_init(void)
+{
+ int rc;
+
+ printk("%s %s\n", driver_name, driver_version);
+
+ slgt_device_count = 0;
+ if ((rc = pci_register_driver(&pci_driver)) < 0) {
+ printk("%s pci_register_driver error=%d\n", driver_name, rc);
+ return rc;
+ }
+ pci_registered = 1;
+
+ if (!slgt_device_list) {
+ printk("%s no devices found\n",driver_name);
+ return -ENODEV;
+ }
+
+ serial_driver = alloc_tty_driver(MAX_DEVICES);
+ if (!serial_driver) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ /* Initialize the tty_driver structure */
+
+ serial_driver->owner = THIS_MODULE;
+ serial_driver->driver_name = tty_driver_name;
+ serial_driver->name = tty_dev_prefix;
+ serial_driver->major = ttymajor;
+ serial_driver->minor_start = 64;
+ serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver->subtype = SERIAL_TYPE_NORMAL;
+ serial_driver->init_termios = tty_std_termios;
+ serial_driver->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(serial_driver, &ops);
+ if ((rc = tty_register_driver(serial_driver)) < 0) {
+ DBGERR(("%s can't register serial driver\n", driver_name));
+ put_tty_driver(serial_driver);
+ serial_driver = NULL;
+ goto error;
+ }
+
+ printk("%s %s, tty major#%d\n",
+ driver_name, driver_version,
+ serial_driver->major);
+
+ return 0;
+
+error:
+ slgt_cleanup();
+ return rc;
+}
+
+static void __exit slgt_exit(void)
+{
+ slgt_cleanup();
+}
+
+module_init(slgt_init);
+module_exit(slgt_exit);
+
+/*
+ * register access routines
+ */
+
+#define CALC_REGADDR() \
+ unsigned long reg_addr = ((unsigned long)info->reg_addr) + addr; \
+ if (addr >= 0x80) \
+ reg_addr += (info->port_num) * 32;
+
+static __u8 rd_reg8(struct slgt_info *info, unsigned int addr)
+{
+ CALC_REGADDR();
+ return readb((void __iomem *)reg_addr);
+}
+
+static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value)
+{
+ CALC_REGADDR();
+ writeb(value, (void __iomem *)reg_addr);
+}
+
+static __u16 rd_reg16(struct slgt_info *info, unsigned int addr)
+{
+ CALC_REGADDR();
+ return readw((void __iomem *)reg_addr);
+}
+
+static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value)
+{
+ CALC_REGADDR();
+ writew(value, (void __iomem *)reg_addr);
+}
+
+static __u32 rd_reg32(struct slgt_info *info, unsigned int addr)
+{
+ CALC_REGADDR();
+ return readl((void __iomem *)reg_addr);
+}
+
+static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value)
+{
+ CALC_REGADDR();
+ writel(value, (void __iomem *)reg_addr);
+}
+
+static void rdma_reset(struct slgt_info *info)
+{
+ unsigned int i;
+
+ /* set reset bit */
+ wr_reg32(info, RDCSR, BIT1);
+
+ /* wait for enable bit cleared */
+ for(i=0 ; i < 1000 ; i++)
+ if (!(rd_reg32(info, RDCSR) & BIT0))
+ break;
+}
+
+static void tdma_reset(struct slgt_info *info)
+{
+ unsigned int i;
+
+ /* set reset bit */
+ wr_reg32(info, TDCSR, BIT1);
+
+ /* wait for enable bit cleared */
+ for(i=0 ; i < 1000 ; i++)
+ if (!(rd_reg32(info, TDCSR) & BIT0))
+ break;
+}
+
+/*
+ * enable internal loopback
+ * TxCLK and RxCLK are generated from BRG
+ * and TxD is looped back to RxD internally.
+ */
+static void enable_loopback(struct slgt_info *info)
+{
+ /* SCR (serial control) BIT2=looopback enable */
+ wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT2));
+
+ if (info->params.mode != MGSL_MODE_ASYNC) {
+ /* CCR (clock control)
+ * 07..05 tx clock source (010 = BRG)
+ * 04..02 rx clock source (010 = BRG)
+ * 01 auxclk enable (0 = disable)
+ * 00 BRG enable (1 = enable)
+ *
+ * 0100 1001
+ */
+ wr_reg8(info, CCR, 0x49);
+
+ /* set speed if available, otherwise use default */
+ if (info->params.clock_speed)
+ set_rate(info, info->params.clock_speed);
+ else
+ set_rate(info, 3686400);
+ }
+}
+
+/*
+ * set baud rate generator to specified rate
+ */
+static void set_rate(struct slgt_info *info, u32 rate)
+{
+ unsigned int div;
+ static unsigned int osc = 14745600;
+
+ /* div = osc/rate - 1
+ *
+ * Round div up if osc/rate is not integer to
+ * force to next slowest rate.
+ */
+
+ if (rate) {
+ div = osc/rate;
+ if (!(osc % rate) && div)
+ div--;
+ wr_reg16(info, BDR, (unsigned short)div);
+ }
+}
+
+static void rx_stop(struct slgt_info *info)
+{
+ unsigned short val;
+
+ /* disable and reset receiver */
+ val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */
+ wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */
+ wr_reg16(info, RCR, val); /* clear reset bit */
+
+ slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA + IRQ_RXIDLE);
+
+ /* clear pending rx interrupts */
+ wr_reg16(info, SSR, IRQ_RXIDLE + IRQ_RXOVER);
+
+ rdma_reset(info);
+
+ info->rx_enabled = 0;
+ info->rx_restart = 0;
+}
+
+static void rx_start(struct slgt_info *info)
+{
+ unsigned short val;
+
+ slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA);
+
+ /* clear pending rx overrun IRQ */
+ wr_reg16(info, SSR, IRQ_RXOVER);
+
+ /* reset and disable receiver */
+ val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */
+ wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */
+ wr_reg16(info, RCR, val); /* clear reset bit */
+
+ rdma_reset(info);
+ reset_rbufs(info);
+
+ /* set 1st descriptor address */
+ wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
+
+ if (info->params.mode != MGSL_MODE_ASYNC) {
+ /* enable rx DMA and DMA interrupt */
+ wr_reg32(info, RDCSR, (BIT2 + BIT0));
+ } else {
+ /* enable saving of rx status, rx DMA and DMA interrupt */
+ wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
+ }
+
+ slgt_irq_on(info, IRQ_RXOVER);
+
+ /* enable receiver */
+ wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1));
+
+ info->rx_restart = 0;
+ info->rx_enabled = 1;
+}
+
+static void tx_start(struct slgt_info *info)
+{
+ if (!info->tx_enabled) {
+ wr_reg16(info, TCR,
+ (unsigned short)(rd_reg16(info, TCR) | BIT1));
+ info->tx_enabled = TRUE;
+ }
+
+ if (info->tx_count) {
+ info->drop_rts_on_tx_done = 0;
+
+ if (info->params.mode != MGSL_MODE_ASYNC) {
+ if (info->params.flags & HDLC_FLAG_AUTO_RTS) {
+ get_signals(info);
+ if (!(info->signals & SerialSignal_RTS)) {
+ info->signals |= SerialSignal_RTS;
+ set_signals(info);
+ info->drop_rts_on_tx_done = 1;
+ }
+ }
+
+ slgt_irq_off(info, IRQ_TXDATA);
+ slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
+ /* clear tx idle and underrun status bits */
+ wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
+
+ if (!(rd_reg32(info, TDCSR) & BIT0)) {
+ /* tx DMA stopped, restart tx DMA */
+ tdma_reset(info);
+ /* set 1st descriptor address */
+ wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+ if (info->params.mode == MGSL_MODE_RAW)
+ wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
+ else
+ wr_reg32(info, TDCSR, BIT0); /* DMA enable */
+ }
+
+ if (info->params.mode != MGSL_MODE_RAW) {
+ info->tx_timer.expires = jiffies + msecs_to_jiffies(5000);
+ add_timer(&info->tx_timer);
+ }
+ } else {
+ tdma_reset(info);
+ /* set 1st descriptor address */
+ wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+
+ slgt_irq_off(info, IRQ_TXDATA);
+ slgt_irq_on(info, IRQ_TXIDLE);
+ /* clear tx idle status bit */
+ wr_reg16(info, SSR, IRQ_TXIDLE);
+
+ /* enable tx DMA */
+ wr_reg32(info, TDCSR, BIT0);
+ }
+
+ info->tx_active = 1;
+ }
+}
+
+static void tx_stop(struct slgt_info *info)
+{
+ unsigned short val;
+
+ del_timer(&info->tx_timer);
+
+ tdma_reset(info);
+
+ /* reset and disable transmitter */
+ val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */
+ wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
+ wr_reg16(info, TCR, val); /* clear reset */
+
+ slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
+
+ /* clear tx idle and underrun status bit */
+ wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
+
+ reset_tbufs(info);
+
+ info->tx_enabled = 0;
+ info->tx_active = 0;
+}
+
+static void reset_port(struct slgt_info *info)
+{
+ if (!info->reg_addr)
+ return;
+
+ tx_stop(info);
+ rx_stop(info);
+
+ info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
+ set_signals(info);
+
+ slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
+}
+
+static void reset_adapter(struct slgt_info *info)
+{
+ int i;
+ for (i=0; i < info->port_count; ++i) {
+ if (info->port_array[i])
+ reset_port(info->port_array[i]);
+ }
+}
+
+static void async_mode(struct slgt_info *info)
+{
+ unsigned short val;
+
+ slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
+ tx_stop(info);
+ rx_stop(info);
+
+ /* TCR (tx control)
+ *
+ * 15..13 mode, 010=async
+ * 12..10 encoding, 000=NRZ
+ * 09 parity enable
+ * 08 1=odd parity, 0=even parity
+ * 07 1=RTS driver control
+ * 06 1=break enable
+ * 05..04 character length
+ * 00=5 bits
+ * 01=6 bits
+ * 10=7 bits
+ * 11=8 bits
+ * 03 0=1 stop bit, 1=2 stop bits
+ * 02 reset
+ * 01 enable
+ * 00 auto-CTS enable
+ */
+ val = 0x4000;
+
+ if (info->if_mode & MGSL_INTERFACE_RTS_EN)
+ val |= BIT7;
+
+ if (info->params.parity != ASYNC_PARITY_NONE) {
+ val |= BIT9;
+ if (info->params.parity == ASYNC_PARITY_ODD)
+ val |= BIT8;
+ }
+
+ switch (info->params.data_bits)
+ {
+ case 6: val |= BIT4; break;
+ case 7: val |= BIT5; break;
+ case 8: val |= BIT5 + BIT4; break;
+ }
+
+ if (info->params.stop_bits != 1)
+ val |= BIT3;
+
+ if (info->params.flags & HDLC_FLAG_AUTO_CTS)
+ val |= BIT0;
+
+ wr_reg16(info, TCR, val);
+
+ /* RCR (rx control)
+ *
+ * 15..13 mode, 010=async
+ * 12..10 encoding, 000=NRZ
+ * 09 parity enable
+ * 08 1=odd parity, 0=even parity
+ * 07..06 reserved, must be 0
+ * 05..04 character length
+ * 00=5 bits
+ * 01=6 bits
+ * 10=7 bits
+ * 11=8 bits
+ * 03 reserved, must be zero
+ * 02 reset
+ * 01 enable
+ * 00 auto-DCD enable
+ */
+ val = 0x4000;
+
+ if (info->params.parity != ASYNC_PARITY_NONE) {
+ val |= BIT9;
+ if (info->params.parity == ASYNC_PARITY_ODD)
+ val |= BIT8;
+ }
+
+ switch (info->params.data_bits)
+ {
+ case 6: val |= BIT4; break;
+ case 7: val |= BIT5; break;
+ case 8: val |= BIT5 + BIT4; break;
+ }
+
+ if (info->params.flags & HDLC_FLAG_AUTO_DCD)
+ val |= BIT0;
+
+ wr_reg16(info, RCR, val);
+
+ /* CCR (clock control)
+ *
+ * 07..05 011 = tx clock source is BRG/16
+ * 04..02 010 = rx clock source is BRG
+ * 01 0 = auxclk disabled
+ * 00 1 = BRG enabled
+ *
+ * 0110 1001
+ */
+ wr_reg8(info, CCR, 0x69);
+
+ msc_set_vcr(info);
+
+ tx_set_idle(info);
+
+ /* SCR (serial control)
+ *
+ * 15 1=tx req on FIFO half empty
+ * 14 1=rx req on FIFO half full
+ * 13 tx data IRQ enable
+ * 12 tx idle IRQ enable
+ * 11 rx break on IRQ enable
+ * 10 rx data IRQ enable
+ * 09 rx break off IRQ enable
+ * 08 overrun IRQ enable
+ * 07 DSR IRQ enable
+ * 06 CTS IRQ enable
+ * 05 DCD IRQ enable
+ * 04 RI IRQ enable
+ * 03 reserved, must be zero
+ * 02 1=txd->rxd internal loopback enable
+ * 01 reserved, must be zero
+ * 00 1=master IRQ enable
+ */
+ val = BIT15 + BIT14 + BIT0;
+ wr_reg16(info, SCR, val);
+
+ slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER);
+
+ set_rate(info, info->params.data_rate * 16);
+
+ if (info->params.loopback)
+ enable_loopback(info);
+}
+
+static void hdlc_mode(struct slgt_info *info)
+{
+ unsigned short val;
+
+ slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
+ tx_stop(info);
+ rx_stop(info);
+
+ /* TCR (tx control)
+ *
+ * 15..13 mode, 000=HDLC 001=raw sync
+ * 12..10 encoding
+ * 09 CRC enable
+ * 08 CRC32
+ * 07 1=RTS driver control
+ * 06 preamble enable
+ * 05..04 preamble length
+ * 03 share open/close flag
+ * 02 reset
+ * 01 enable
+ * 00 auto-CTS enable
+ */
+ val = 0;
+
+ if (info->params.mode == MGSL_MODE_RAW)
+ val |= BIT13;
+ if (info->if_mode & MGSL_INTERFACE_RTS_EN)
+ val |= BIT7;
+
+ switch(info->params.encoding)
+ {
+ case HDLC_ENCODING_NRZB: val |= BIT10; break;
+ case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break;
+ case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break;
+ case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break;
+ case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break;
+ case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break;
+ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
+ }
+
+ switch (info->params.crc_type)
+ {
+ case HDLC_CRC_16_CCITT: val |= BIT9; break;
+ case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
+ }
+
+ if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE)
+ val |= BIT6;
+
+ switch (info->params.preamble_length)
+ {
+ case HDLC_PREAMBLE_LENGTH_16BITS: val |= BIT5; break;
+ case HDLC_PREAMBLE_LENGTH_32BITS: val |= BIT4; break;
+ case HDLC_PREAMBLE_LENGTH_64BITS: val |= BIT5 + BIT4; break;
+ }
+
+ if (info->params.flags & HDLC_FLAG_AUTO_CTS)
+ val |= BIT0;
+
+ wr_reg16(info, TCR, val);
+
+ /* TPR (transmit preamble) */
+
+ switch (info->params.preamble)
+ {
+ case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break;
+ case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break;
+ case HDLC_PREAMBLE_PATTERN_ZEROS: val = 0x00; break;
+ case HDLC_PREAMBLE_PATTERN_10: val = 0x55; break;
+ case HDLC_PREAMBLE_PATTERN_01: val = 0xaa; break;
+ default: val = 0x7e; break;
+ }
+ wr_reg8(info, TPR, (unsigned char)val);
+
+ /* RCR (rx control)
+ *
+ * 15..13 mode, 000=HDLC 001=raw sync
+ * 12..10 encoding
+ * 09 CRC enable
+ * 08 CRC32
+ * 07..03 reserved, must be 0
+ * 02 reset
+ * 01 enable
+ * 00 auto-DCD enable
+ */
+ val = 0;
+
+ if (info->params.mode == MGSL_MODE_RAW)
+ val |= BIT13;
+
+ switch(info->params.encoding)
+ {
+ case HDLC_ENCODING_NRZB: val |= BIT10; break;
+ case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break;
+ case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break;
+ case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break;
+ case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break;
+ case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break;
+ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
+ }
+
+ switch (info->params.crc_type)
+ {
+ case HDLC_CRC_16_CCITT: val |= BIT9; break;
+ case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
+ }
+
+ if (info->params.flags & HDLC_FLAG_AUTO_DCD)
+ val |= BIT0;
+
+ wr_reg16(info, RCR, val);
+
+ /* CCR (clock control)
+ *
+ * 07..05 tx clock source
+ * 04..02 rx clock source
+ * 01 auxclk enable
+ * 00 BRG enable
+ */
+ val = 0;
+
+ if (info->params.flags & HDLC_FLAG_TXC_BRG)
+ {
+ // when RxC source is DPLL, BRG generates 16X DPLL
+ // reference clock, so take TxC from BRG/16 to get
+ // transmit clock at actual data rate
+ if (info->params.flags & HDLC_FLAG_RXC_DPLL)
+ val |= BIT6 + BIT5; /* 011, txclk = BRG/16 */
+ else
+ val |= BIT6; /* 010, txclk = BRG */
+ }
+ else if (info->params.flags & HDLC_FLAG_TXC_DPLL)
+ val |= BIT7; /* 100, txclk = DPLL Input */
+ else if (info->params.flags & HDLC_FLAG_TXC_RXCPIN)
+ val |= BIT5; /* 001, txclk = RXC Input */
+
+ if (info->params.flags & HDLC_FLAG_RXC_BRG)
+ val |= BIT3; /* 010, rxclk = BRG */
+ else if (info->params.flags & HDLC_FLAG_RXC_DPLL)
+ val |= BIT4; /* 100, rxclk = DPLL */
+ else if (info->params.flags & HDLC_FLAG_RXC_TXCPIN)
+ val |= BIT2; /* 001, rxclk = TXC Input */
+
+ if (info->params.clock_speed)
+ val |= BIT1 + BIT0;
+
+ wr_reg8(info, CCR, (unsigned char)val);
+
+ if (info->params.flags & (HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL))
+ {
+ // program DPLL mode
+ switch(info->params.encoding)
+ {
+ case HDLC_ENCODING_BIPHASE_MARK:
+ case HDLC_ENCODING_BIPHASE_SPACE:
+ val = BIT7; break;
+ case HDLC_ENCODING_BIPHASE_LEVEL:
+ case HDLC_ENCODING_DIFF_BIPHASE_LEVEL:
+ val = BIT7 + BIT6; break;
+ default: val = BIT6; // NRZ encodings
+ }
+ wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | val));
+
+ // DPLL requires a 16X reference clock from BRG
+ set_rate(info, info->params.clock_speed * 16);
+ }
+ else
+ set_rate(info, info->params.clock_speed);
+
+ tx_set_idle(info);
+
+ msc_set_vcr(info);
+
+ /* SCR (serial control)
+ *
+ * 15 1=tx req on FIFO half empty
+ * 14 1=rx req on FIFO half full
+ * 13 tx data IRQ enable
+ * 12 tx idle IRQ enable
+ * 11 underrun IRQ enable
+ * 10 rx data IRQ enable
+ * 09 rx idle IRQ enable
+ * 08 overrun IRQ enable
+ * 07 DSR IRQ enable
+ * 06 CTS IRQ enable
+ * 05 DCD IRQ enable
+ * 04 RI IRQ enable
+ * 03 reserved, must be zero
+ * 02 1=txd->rxd internal loopback enable
+ * 01 reserved, must be zero
+ * 00 1=master IRQ enable
+ */
+ wr_reg16(info, SCR, BIT15 + BIT14 + BIT0);
+
+ if (info->params.loopback)
+ enable_loopback(info);
+}
+
+/*
+ * set transmit idle mode
+ */
+static void tx_set_idle(struct slgt_info *info)
+{
+ unsigned char val = 0xff;
+
+ switch(info->idle_mode)
+ {
+ case HDLC_TXIDLE_FLAGS: val = 0x7e; break;
+ case HDLC_TXIDLE_ALT_ZEROS_ONES: val = 0xaa; break;
+ case HDLC_TXIDLE_ZEROS: val = 0x00; break;
+ case HDLC_TXIDLE_ONES: val = 0xff; break;
+ case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
+ case HDLC_TXIDLE_SPACE: val = 0x00; break;
+ case HDLC_TXIDLE_MARK: val = 0xff; break;
+ }
+
+ wr_reg8(info, TIR, val);
+}
+
+/*
+ * get state of V24 status (input) signals
+ */
+static void get_signals(struct slgt_info *info)
+{
+ unsigned short status = rd_reg16(info, SSR);
+
+ /* clear all serial signals except DTR and RTS */
+ info->signals &= SerialSignal_DTR + SerialSignal_RTS;
+
+ if (status & BIT3)
+ info->signals |= SerialSignal_DSR;
+ if (status & BIT2)
+ info->signals |= SerialSignal_CTS;
+ if (status & BIT1)
+ info->signals |= SerialSignal_DCD;
+ if (status & BIT0)
+ info->signals |= SerialSignal_RI;
+}
+
+/*
+ * set V.24 Control Register based on current configuration
+ */
+static void msc_set_vcr(struct slgt_info *info)
+{
+ unsigned char val = 0;
+
+ /* VCR (V.24 control)
+ *
+ * 07..04 serial IF select
+ * 03 DTR
+ * 02 RTS
+ * 01 LL
+ * 00 RL
+ */
+
+ switch(info->if_mode & MGSL_INTERFACE_MASK)
+ {
+ case MGSL_INTERFACE_RS232:
+ val |= BIT5; /* 0010 */
+ break;
+ case MGSL_INTERFACE_V35:
+ val |= BIT7 + BIT6 + BIT5; /* 1110 */
+ break;
+ case MGSL_INTERFACE_RS422:
+ val |= BIT6; /* 0100 */
+ break;
+ }
+
+ if (info->signals & SerialSignal_DTR)
+ val |= BIT3;
+ if (info->signals & SerialSignal_RTS)
+ val |= BIT2;
+ if (info->if_mode & MGSL_INTERFACE_LL)
+ val |= BIT1;
+ if (info->if_mode & MGSL_INTERFACE_RL)
+ val |= BIT0;
+ wr_reg8(info, VCR, val);
+}
+
+/*
+ * set state of V24 control (output) signals
+ */
+static void set_signals(struct slgt_info *info)
+{
+ unsigned char val = rd_reg8(info, VCR);
+ if (info->signals & SerialSignal_DTR)
+ val |= BIT3;
+ else
+ val &= ~BIT3;
+ if (info->signals & SerialSignal_RTS)
+ val |= BIT2;
+ else
+ val &= ~BIT2;
+ wr_reg8(info, VCR, val);
+}
+
+/*
+ * free range of receive DMA buffers (i to last)
+ */
+static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last)
+{
+ int done = 0;
+
+ while(!done) {
+ /* reset current buffer for reuse */
+ info->rbufs[i].status = 0;
+ if (info->params.mode == MGSL_MODE_RAW)
+ set_desc_count(info->rbufs[i], info->raw_rx_size);
+ else
+ set_desc_count(info->rbufs[i], DMABUFSIZE);
+
+ if (i == last)
+ done = 1;
+ if (++i == info->rbuf_count)
+ i = 0;
+ }
+ info->rbuf_current = i;
+}
+
+/*
+ * mark all receive DMA buffers as free
+ */
+static void reset_rbufs(struct slgt_info *info)
+{
+ free_rbufs(info, 0, info->rbuf_count - 1);
+}
+
+/*
+ * pass receive HDLC frame to upper layer
+ *
+ * return 1 if frame available, otherwise 0
+ */
+static int rx_get_frame(struct slgt_info *info)
+{
+ unsigned int start, end;
+ unsigned short status;
+ unsigned int framesize = 0;
+ int rc = 0;
+ unsigned long flags;
+ struct tty_struct *tty = info->tty;
+ unsigned char addr_field = 0xff;
+
+check_again:
+
+ framesize = 0;
+ addr_field = 0xff;
+ start = end = info->rbuf_current;
+
+ for (;;) {
+ if (!desc_complete(info->rbufs[end]))
+ goto cleanup;
+
+ if (framesize == 0 && info->params.addr_filter != 0xff)
+ addr_field = info->rbufs[end].buf[0];
+
+ framesize += desc_count(info->rbufs[end]);
+
+ if (desc_eof(info->rbufs[end]))
+ break;
+
+ if (++end == info->rbuf_count)
+ end = 0;
+
+ if (end == info->rbuf_current) {
+ if (info->rx_enabled){
+ spin_lock_irqsave(&info->lock,flags);
+ rx_start(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+ }
+ goto cleanup;
+ }
+ }
+
+ /* status
+ *
+ * 15 buffer complete
+ * 14..06 reserved
+ * 05..04 residue
+ * 02 eof (end of frame)
+ * 01 CRC error
+ * 00 abort
+ */
+ status = desc_status(info->rbufs[end]);
+
+ /* ignore CRC bit if not using CRC (bit is undefined) */
+ if (info->params.crc_type == HDLC_CRC_NONE)
+ status &= ~BIT1;
+
+ if (framesize == 0 ||
+ (addr_field != 0xff && addr_field != info->params.addr_filter)) {
+ free_rbufs(info, start, end);
+ goto check_again;
+ }
+
+ if (framesize < 2 || status & (BIT1+BIT0)) {
+ if (framesize < 2 || (status & BIT0))
+ info->icount.rxshort++;
+ else
+ info->icount.rxcrc++;
+ framesize = 0;
+
+#ifdef CONFIG_HDLC
+ {
+ struct net_device_stats *stats = hdlc_stats(info->netdev);
+ stats->rx_errors++;
+ stats->rx_frame_errors++;
+ }
+#endif
+ } else {
+ /* adjust frame size for CRC, if any */
+ if (info->params.crc_type == HDLC_CRC_16_CCITT)
+ framesize -= 2;
+ else if (info->params.crc_type == HDLC_CRC_32_CCITT)
+ framesize -= 4;
+ }
+
+ DBGBH(("%s rx frame status=%04X size=%d\n",
+ info->device_name, status, framesize));
+ DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx");
+
+ if (framesize) {
+ if (framesize > info->max_frame_size)
+ info->icount.rxlong++;
+ else {
+ /* copy dma buffer(s) to contiguous temp buffer */
+ int copy_count = framesize;
+ int i = start;
+ unsigned char *p = info->tmp_rbuf;
+ info->tmp_rbuf_count = framesize;
+
+ info->icount.rxok++;
+
+ while(copy_count) {
+ int partial_count = min(copy_count, DMABUFSIZE);
+ memcpy(p, info->rbufs[i].buf, partial_count);
+ p += partial_count;
+ copy_count -= partial_count;
+ if (++i == info->rbuf_count)
+ i = 0;
+ }
+
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlcdev_rx(info,info->tmp_rbuf, framesize);
+ else
+#endif
+ ldisc_receive_buf(tty, info->tmp_rbuf, info->flag_buf, framesize);
+ }
+ }
+ free_rbufs(info, start, end);
+ rc = 1;
+
+cleanup:
+ return rc;
+}
+
+/*
+ * pass receive buffer (RAW synchronous mode) to tty layer
+ * return 1 if buffer available, otherwise 0
+ */
+static int rx_get_buf(struct slgt_info *info)
+{
+ unsigned int i = info->rbuf_current;
+
+ if (!desc_complete(info->rbufs[i]))
+ return 0;
+ DBGDATA(info, info->rbufs[i].buf, desc_count(info->rbufs[i]), "rx");
+ DBGINFO(("rx_get_buf size=%d\n", desc_count(info->rbufs[i])));
+ ldisc_receive_buf(info->tty, info->rbufs[i].buf,
+ info->flag_buf, desc_count(info->rbufs[i]));
+ free_rbufs(info, i, i);
+ return 1;
+}
+
+static void reset_tbufs(struct slgt_info *info)
+{
+ unsigned int i;
+ info->tbuf_current = 0;
+ for (i=0 ; i < info->tbuf_count ; i++) {
+ info->tbufs[i].status = 0;
+ info->tbufs[i].count = 0;
+ }
+}
+
+/*
+ * return number of free transmit DMA buffers
+ */
+static unsigned int free_tbuf_count(struct slgt_info *info)
+{
+ unsigned int count = 0;
+ unsigned int i = info->tbuf_current;
+
+ do
+ {
+ if (desc_count(info->tbufs[i]))
+ break; /* buffer in use */
+ ++count;
+ if (++i == info->tbuf_count)
+ i=0;
+ } while (i != info->tbuf_current);
+
+ /* last buffer with zero count may be in use, assume it is */
+ if (count)
+ --count;
+
+ return count;
+}
+
+/*
+ * load transmit DMA buffer(s) with data
+ */
+static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
+{
+ unsigned short count;
+ unsigned int i;
+ struct slgt_desc *d;
+
+ if (size == 0)
+ return;
+
+ DBGDATA(info, buf, size, "tx");
+
+ info->tbuf_start = i = info->tbuf_current;
+
+ while (size) {
+ d = &info->tbufs[i];
+ if (++i == info->tbuf_count)
+ i = 0;
+
+ count = (unsigned short)((size > DMABUFSIZE) ? DMABUFSIZE : size);
+ memcpy(d->buf, buf, count);
+
+ size -= count;
+ buf += count;
+
+ if (!size && info->params.mode != MGSL_MODE_RAW)
+ set_desc_eof(*d, 1); /* HDLC: set EOF of last desc */
+ else
+ set_desc_eof(*d, 0);
+
+ set_desc_count(*d, count);
+ }
+
+ info->tbuf_current = i;
+}
+
+static int register_test(struct slgt_info *info)
+{
+ static unsigned short patterns[] =
+ {0x0000, 0xffff, 0xaaaa, 0x5555, 0x6969, 0x9696};
+ static unsigned int count = sizeof(patterns)/sizeof(patterns[0]);
+ unsigned int i;
+ int rc = 0;
+
+ for (i=0 ; i < count ; i++) {
+ wr_reg16(info, TIR, patterns[i]);
+ wr_reg16(info, BDR, patterns[(i+1)%count]);
+ if ((rd_reg16(info, TIR) != patterns[i]) ||
+ (rd_reg16(info, BDR) != patterns[(i+1)%count])) {
+ rc = -ENODEV;
+ break;
+ }
+ }
+
+ info->init_error = rc ? 0 : DiagStatus_AddressFailure;
+ return rc;
+}
+
+static int irq_test(struct slgt_info *info)
+{
+ unsigned long timeout;
+ unsigned long flags;
+ struct tty_struct *oldtty = info->tty;
+ u32 speed = info->params.data_rate;
+
+ info->params.data_rate = 921600;
+ info->tty = NULL;
+
+ spin_lock_irqsave(&info->lock, flags);
+ async_mode(info);
+ slgt_irq_on(info, IRQ_TXIDLE);
+
+ /* enable transmitter */
+ wr_reg16(info, TCR,
+ (unsigned short)(rd_reg16(info, TCR) | BIT1));
+
+ /* write one byte and wait for tx idle */
+ wr_reg16(info, TDR, 0);
+
+ /* assume failure */
+ info->init_error = DiagStatus_IrqFailure;
+ info->irq_occurred = FALSE;
+
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ timeout=100;
+ while(timeout-- && !info->irq_occurred)
+ msleep_interruptible(10);
+
+ spin_lock_irqsave(&info->lock,flags);
+ reset_port(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ info->params.data_rate = speed;
+ info->tty = oldtty;
+
+ info->init_error = info->irq_occurred ? 0 : DiagStatus_IrqFailure;
+ return info->irq_occurred ? 0 : -ENODEV;
+}
+
+static int loopback_test_rx(struct slgt_info *info)
+{
+ unsigned char *src, *dest;
+ int count;
+
+ if (desc_complete(info->rbufs[0])) {
+ count = desc_count(info->rbufs[0]);
+ src = info->rbufs[0].buf;
+ dest = info->tmp_rbuf;
+
+ for( ; count ; count-=2, src+=2) {
+ /* src=data byte (src+1)=status byte */
+ if (!(*(src+1) & (BIT9 + BIT8))) {
+ *dest = *src;
+ dest++;
+ info->tmp_rbuf_count++;
+ }
+ }
+ DBGDATA(info, info->tmp_rbuf, info->tmp_rbuf_count, "rx");
+ return 1;
+ }
+ return 0;
+}
+
+static int loopback_test(struct slgt_info *info)
+{
+#define TESTFRAMESIZE 20
+
+ unsigned long timeout;
+ u16 count = TESTFRAMESIZE;
+ unsigned char buf[TESTFRAMESIZE];
+ int rc = -ENODEV;
+ unsigned long flags;
+
+ struct tty_struct *oldtty = info->tty;
+ MGSL_PARAMS params;
+
+ memcpy(&params, &info->params, sizeof(params));
+
+ info->params.mode = MGSL_MODE_ASYNC;
+ info->params.data_rate = 921600;
+ info->params.loopback = 1;
+ info->tty = NULL;
+
+ /* build and send transmit frame */
+ for (count = 0; count < TESTFRAMESIZE; ++count)
+ buf[count] = (unsigned char)count;
+
+ info->tmp_rbuf_count = 0;
+ memset(info->tmp_rbuf, 0, TESTFRAMESIZE);
+
+ /* program hardware for HDLC and enabled receiver */
+ spin_lock_irqsave(&info->lock,flags);
+ async_mode(info);
+ rx_start(info);
+ info->tx_count = count;
+ tx_load(info, buf, count);
+ tx_start(info);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ /* wait for receive complete */
+ for (timeout = 100; timeout; --timeout) {
+ msleep_interruptible(10);
+ if (loopback_test_rx(info)) {
+ rc = 0;
+ break;
+ }
+ }
+
+ /* verify received frame length and contents */
+ if (!rc && (info->tmp_rbuf_count != count ||
+ memcmp(buf, info->tmp_rbuf, count))) {
+ rc = -ENODEV;
+ }
+
+ spin_lock_irqsave(&info->lock,flags);
+ reset_adapter(info);
+ spin_unlock_irqrestore(&info->lock,flags);
+
+ memcpy(&info->params, &params, sizeof(info->params));
+ info->tty = oldtty;
+
+ info->init_error = rc ? DiagStatus_DmaFailure : 0;
+ return rc;
+}
+
+static int adapter_test(struct slgt_info *info)
+{
+ DBGINFO(("testing %s\n", info->device_name));
+ if ((info->init_error = register_test(info)) < 0) {
+ printk("register test failure %s addr=%08X\n",
+ info->device_name, info->phys_reg_addr);
+ } else if ((info->init_error = irq_test(info)) < 0) {
+ printk("IRQ test failure %s IRQ=%d\n",
+ info->device_name, info->irq_level);
+ } else if ((info->init_error = loopback_test(info)) < 0) {
+ printk("loopback test failure %s\n", info->device_name);
+ }
+ return info->init_error;
+}
+
+/*
+ * transmit timeout handler
+ */
+static void tx_timeout(unsigned long context)
+{
+ struct slgt_info *info = (struct slgt_info*)context;
+ unsigned long flags;
+
+ DBGINFO(("%s tx_timeout\n", info->device_name));
+ if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) {
+ info->icount.txtimeout++;
+ }
+ spin_lock_irqsave(&info->lock,flags);
+ info->tx_active = 0;
+ info->tx_count = 0;
+ spin_unlock_irqrestore(&info->lock,flags);
+
+#ifdef CONFIG_HDLC
+ if (info->netcount)
+ hdlcdev_tx_done(info);
+ else
+#endif
+ bh_transmit(info);
+}
+
+/*
+ * receive buffer polling timer
+ */
+static void rx_timeout(unsigned long context)
+{
+ struct slgt_info *info = (struct slgt_info*)context;
+ unsigned long flags;
+
+ DBGINFO(("%s rx_timeout\n", info->device_name));
+ spin_lock_irqsave(&info->lock, flags);
+ info->pending_bh |= BH_RECEIVE;
+ spin_unlock_irqrestore(&info->lock, flags);
+ bh_handler(info);
+}
+
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index ee5a40be9f9..960adb256fb 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -2196,7 +2196,7 @@ void isr_rxint(SLMP_INFO * info)
if ( tty ) {
if (!(status & info->ignore_status_mask1)) {
if (info->read_status_mask1 & BRKD) {
- *tty->flip.flag_buf_ptr = TTY_BREAK;
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
if (info->flags & ASYNC_SAK)
do_SAK(tty);
}
@@ -2240,16 +2240,10 @@ void isr_rxrdy(SLMP_INFO * info)
while((status = read_reg(info,CST0)) & BIT0)
{
+ int flag = 0;
+ int over = 0;
DataByte = read_reg(info,TRB);
- if ( tty ) {
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- continue;
-
- *tty->flip.char_buf_ptr = DataByte;
- *tty->flip.flag_buf_ptr = 0;
- }
-
icount->rx++;
if ( status & (PE + FRME + OVRN) ) {
@@ -2272,42 +2266,34 @@ void isr_rxrdy(SLMP_INFO * info)
if ( tty ) {
if (status & PE)
- *tty->flip.flag_buf_ptr = TTY_PARITY;
+ flag = TTY_PARITY;
else if (status & FRME)
- *tty->flip.flag_buf_ptr = TTY_FRAME;
+ flag = TTY_FRAME;
if (status & OVRN) {
/* Overrun is special, since it's
* reported immediately, and doesn't
* affect the current character
*/
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- }
+ over = 1;
}
}
} /* end of if (error) */
if ( tty ) {
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ tty_insert_flip_char(tty, DataByte, flag);
+ if (over)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
}
if ( debug_level >= DEBUG_LEVEL_ISR ) {
- printk("%s(%d):%s isr_rxrdy() flip count=%d\n",
- __FILE__,__LINE__,info->device_name,
- tty ? tty->flip.count : 0);
printk("%s(%d):%s rx=%d brk=%d parity=%d frame=%d overrun=%d\n",
__FILE__,__LINE__,info->device_name,
icount->rx,icount->brk,icount->parity,
icount->frame,icount->overrun);
}
- if ( tty && tty->flip.count )
+ if ( tty )
tty_flip_buffer_push(tty);
}
@@ -5104,7 +5090,7 @@ void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count)
int register_test(SLMP_INFO *info)
{
static unsigned char testval[] = {0x00, 0xff, 0xaa, 0x55, 0x69, 0x96};
- static unsigned int count = sizeof(testval)/sizeof(unsigned char);
+ static unsigned int count = ARRAY_SIZE(testval);
unsigned int i;
int rc = TRUE;
unsigned long flags;
@@ -5422,7 +5408,7 @@ int memory_test(SLMP_INFO *info)
{
static unsigned long testval[] = { 0x0, 0x55555555, 0xaaaaaaaa,
0x66666666, 0x99999999, 0xffffffff, 0x12345678 };
- unsigned long count = sizeof(testval)/sizeof(unsigned long);
+ unsigned long count = ARRAY_SIZE(testval);
unsigned long i;
unsigned long limit = SCA_MEM_SIZE/sizeof(unsigned long);
unsigned long * addr = (unsigned long *)info->memory_base;
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 145275ebdd7..5765f672e85 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -153,6 +153,21 @@ static struct sysrq_key_op sysrq_mountro_op = {
/* END SYNC SYSRQ HANDLERS BLOCK */
+#ifdef CONFIG_DEBUG_MUTEXES
+
+static void
+sysrq_handle_showlocks(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
+{
+ mutex_debug_show_all_locks();
+}
+
+static struct sysrq_key_op sysrq_showlocks_op = {
+ .handler = sysrq_handle_showlocks,
+ .help_msg = "show-all-locks(D)",
+ .action_msg = "Show Locks Held",
+};
+
+#endif
/* SHOW SYSRQ HANDLERS BLOCK */
@@ -294,7 +309,11 @@ static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
#else
/* c */ NULL,
#endif
+#ifdef CONFIG_DEBUG_MUTEXES
+/* d */ &sysrq_showlocks_op,
+#else
/* d */ NULL,
+#endif
/* e */ &sysrq_term_op,
/* f */ &sysrq_moom_op,
/* g */ NULL,
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 2392e404e8d..ba4582d160f 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -2,6 +2,9 @@
# Makefile for the kernel tpm device drivers.
#
obj-$(CONFIG_TCG_TPM) += tpm.o
+ifdef CONFIG_ACPI
+ obj-$(CONFIG_TCG_TPM) += tpm_bios.o
+endif
obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index a9be0e8eaea..5a3870477ef 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -466,6 +466,7 @@ void tpm_remove_hardware(struct device *dev)
kfree(chip->vendor->miscdev.name);
sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
+ tpm_bios_log_teardown(chip->bios_dir);
dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &=
~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
@@ -593,6 +594,8 @@ dev_num_search_complete:
sysfs_create_group(&dev->kobj, chip->vendor->attr_group);
+ chip->bios_dir = tpm_bios_log_setup(devname);
+
return 0;
}
EXPORT_SYMBOL_GPL(tpm_register_hardware);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 159882ca69d..fd3a4beaa53 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -82,6 +82,8 @@ struct tpm_chip {
struct tpm_vendor_specific *vendor;
+ struct dentry **bios_dir;
+
struct list_head list;
};
@@ -107,3 +109,16 @@ extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
extern void tpm_remove_hardware(struct device *);
extern int tpm_pm_suspend(struct device *, pm_message_t);
extern int tpm_pm_resume(struct device *);
+
+#ifdef CONFIG_ACPI
+extern struct dentry ** tpm_bios_log_setup(char *);
+extern void tpm_bios_log_teardown(struct dentry **);
+#else
+static inline struct dentry* tpm_bios_log_setup(char *name)
+{
+ return NULL;
+}
+static inline void tpm_bios_log_teardown(struct dentry **dir)
+{
+}
+#endif
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
new file mode 100644
index 00000000000..aedf7a8e6da
--- /dev/null
+++ b/drivers/char/tpm/tpm_bios.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Seiji Munetoh <munetoh@jp.ibm.com>
+ * Stefan Berger <stefanb@us.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Access to the eventlog extended by the TCG BIOS of PC platform
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/seq_file.h>
+#include <linux/fs.h>
+#include <linux/security.h>
+#include <linux/module.h>
+#include <acpi/acpi.h>
+#include <acpi/actypes.h>
+#include <acpi/actbl.h>
+#include "tpm.h"
+
+#define TCG_EVENT_NAME_LEN_MAX 255
+#define MAX_TEXT_EVENT 1000 /* Max event string length */
+#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
+
+struct tpm_bios_log {
+ void *bios_event_log;
+ void *bios_event_log_end;
+};
+
+struct acpi_tcpa {
+ struct acpi_table_header hdr;
+ u16 reserved;
+ u32 log_max_len __attribute__ ((packed));
+ u32 log_start_addr __attribute__ ((packed));
+};
+
+struct tcpa_event {
+ u32 pcr_index;
+ u32 event_type;
+ u8 pcr_value[20]; /* SHA1 */
+ u32 event_size;
+ u8 event_data[0];
+};
+
+enum tcpa_event_types {
+ PREBOOT = 0,
+ POST_CODE,
+ UNUSED,
+ NO_ACTION,
+ SEPARATOR,
+ ACTION,
+ EVENT_TAG,
+ SCRTM_CONTENTS,
+ SCRTM_VERSION,
+ CPU_MICROCODE,
+ PLATFORM_CONFIG_FLAGS,
+ TABLE_OF_DEVICES,
+ COMPACT_HASH,
+ IPL,
+ IPL_PARTITION_DATA,
+ NONHOST_CODE,
+ NONHOST_CONFIG,
+ NONHOST_INFO,
+};
+
+static const char* tcpa_event_type_strings[] = {
+ "PREBOOT",
+ "POST CODE",
+ "",
+ "NO ACTION",
+ "SEPARATOR",
+ "ACTION",
+ "EVENT TAG",
+ "S-CRTM Contents",
+ "S-CRTM Version",
+ "CPU Microcode",
+ "Platform Config Flags",
+ "Table of Devices",
+ "Compact Hash",
+ "IPL",
+ "IPL Partition Data",
+ "Non-Host Code",
+ "Non-Host Config",
+ "Non-Host Info"
+};
+
+enum tcpa_pc_event_ids {
+ SMBIOS = 1,
+ BIS_CERT,
+ POST_BIOS_ROM,
+ ESCD,
+ CMOS,
+ NVRAM,
+ OPTION_ROM_EXEC,
+ OPTION_ROM_CONFIG,
+ OPTION_ROM_MICROCODE,
+ S_CRTM_VERSION,
+ S_CRTM_CONTENTS,
+ POST_CONTENTS,
+};
+
+static const char* tcpa_pc_event_id_strings[] = {
+ ""
+ "SMBIOS",
+ "BIS Certificate",
+ "POST BIOS ",
+ "ESCD ",
+ "CMOS",
+ "NVRAM",
+ "Option ROM",
+ "Option ROM config",
+ "Option ROM microcode",
+ "S-CRTM Version",
+ "S-CRTM Contents",
+ "S-CRTM POST Contents",
+};
+
+/* returns pointer to start of pos. entry of tcg log */
+static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
+{
+ loff_t i;
+ struct tpm_bios_log *log = m->private;
+ void *addr = log->bios_event_log;
+ void *limit = log->bios_event_log_end;
+ struct tcpa_event *event;
+
+ /* read over *pos measurements */
+ for (i = 0; i < *pos; i++) {
+ event = addr;
+
+ if ((addr + sizeof(struct tcpa_event)) < limit) {
+ if (event->event_type == 0 && event->event_size == 0)
+ return NULL;
+ addr += sizeof(struct tcpa_event) + event->event_size;
+ }
+ }
+
+ /* now check if current entry is valid */
+ if ((addr + sizeof(struct tcpa_event)) >= limit)
+ return NULL;
+
+ event = addr;
+
+ if ((event->event_type == 0 && event->event_size == 0) ||
+ ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit))
+ return NULL;
+
+ return addr;
+}
+
+static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
+ loff_t *pos)
+{
+ struct tcpa_event *event = v;
+ struct tpm_bios_log *log = m->private;
+ void *limit = log->bios_event_log_end;
+
+ v += sizeof(struct tcpa_event) + event->event_size;
+
+ /* now check if current entry is valid */
+ if ((v + sizeof(struct tcpa_event)) >= limit)
+ return NULL;
+
+ event = v;
+
+ if (event->event_type == 0 && event->event_size == 0)
+ return NULL;
+
+ if ((event->event_type == 0 && event->event_size == 0) ||
+ ((v + sizeof(struct tcpa_event) + event->event_size) >= limit))
+ return NULL;
+
+ (*pos)++;
+ return v;
+}
+
+static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+static int get_event_name(char *dest, struct tcpa_event *event,
+ unsigned char * event_entry)
+{
+ const char *name = "";
+ char data[40] = "";
+ int i, n_len = 0, d_len = 0;
+ u32 event_id, event_data_size;
+
+ switch(event->event_type) {
+ case PREBOOT:
+ case POST_CODE:
+ case UNUSED:
+ case NO_ACTION:
+ case SCRTM_CONTENTS:
+ case SCRTM_VERSION:
+ case CPU_MICROCODE:
+ case PLATFORM_CONFIG_FLAGS:
+ case TABLE_OF_DEVICES:
+ case COMPACT_HASH:
+ case IPL:
+ case IPL_PARTITION_DATA:
+ case NONHOST_CODE:
+ case NONHOST_CONFIG:
+ case NONHOST_INFO:
+ name = tcpa_event_type_strings[event->event_type];
+ n_len = strlen(name);
+ break;
+ case SEPARATOR:
+ case ACTION:
+ if (MAX_TEXT_EVENT > event->event_size) {
+ name = event_entry;
+ n_len = event->event_size;
+ }
+ break;
+ case EVENT_TAG:
+ event_id = be32_to_cpu(event_entry);
+ event_data_size = be32_to_cpu(&event_entry[4]);
+
+ /* ToDo Row data -> Base64 */
+
+ switch (event_id) {
+ case SMBIOS:
+ case BIS_CERT:
+ case CMOS:
+ case NVRAM:
+ case OPTION_ROM_EXEC:
+ case OPTION_ROM_CONFIG:
+ case OPTION_ROM_MICROCODE:
+ case S_CRTM_VERSION:
+ case S_CRTM_CONTENTS:
+ case POST_CONTENTS:
+ name = tcpa_pc_event_id_strings[event_id];
+ n_len = strlen(name);
+ break;
+ case POST_BIOS_ROM:
+ case ESCD:
+ name = tcpa_pc_event_id_strings[event_id];
+ n_len = strlen(name);
+ for (i = 0; i < 20; i++)
+ d_len += sprintf(data, "%02x",
+ event_entry[8 + i]);
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
+ n_len, name, d_len, data);
+
+}
+
+static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
+{
+
+ char *eventname;
+ char data[4];
+ u32 help;
+ int i, len;
+ struct tcpa_event *event = (struct tcpa_event *) v;
+ unsigned char *event_entry =
+ (unsigned char *) (v + sizeof(struct tcpa_event));
+
+ eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
+ if (!eventname) {
+ printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* 1st: PCR used is in little-endian format (4 bytes) */
+ help = le32_to_cpu(event->pcr_index);
+ memcpy(data, &help, 4);
+ for (i = 0; i < 4; i++)
+ seq_putc(m, data[i]);
+
+ /* 2nd: SHA1 (20 bytes) */
+ for (i = 0; i < 20; i++)
+ seq_putc(m, event->pcr_value[i]);
+
+ /* 3rd: event type identifier (4 bytes) */
+ help = le32_to_cpu(event->event_type);
+ memcpy(data, &help, 4);
+ for (i = 0; i < 4; i++)
+ seq_putc(m, data[i]);
+
+ len = 0;
+
+ len += get_event_name(eventname, event, event_entry);
+
+ /* 4th: filename <= 255 + \'0' delimiter */
+ if (len > TCG_EVENT_NAME_LEN_MAX)
+ len = TCG_EVENT_NAME_LEN_MAX;
+
+ for (i = 0; i < len; i++)
+ seq_putc(m, eventname[i]);
+
+ /* 5th: delimiter */
+ seq_putc(m, '\0');
+
+ return 0;
+}
+
+static int tpm_bios_measurements_release(struct inode *inode,
+ struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct tpm_bios_log *log = seq->private;
+
+ if (log) {
+ kfree(log->bios_event_log);
+ kfree(log);
+ }
+
+ return seq_release(inode, file);
+}
+
+static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
+{
+ int len = 0;
+ int i;
+ char *eventname;
+ struct tcpa_event *event = v;
+ unsigned char *event_entry =
+ (unsigned char *) (v + sizeof(struct tcpa_event));
+
+ eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
+ if (!eventname) {
+ printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
+ __func__);
+ return -EFAULT;
+ }
+
+ seq_printf(m, "%2d ", event->pcr_index);
+
+ /* 2nd: SHA1 */
+ for (i = 0; i < 20; i++)
+ seq_printf(m, "%02x", event->pcr_value[i]);
+
+ /* 3rd: event type identifier */
+ seq_printf(m, " %02x", event->event_type);
+
+ len += get_event_name(eventname, event, event_entry);
+
+ /* 4th: eventname <= max + \'0' delimiter */
+ seq_printf(m, " %s\n", eventname);
+
+ return 0;
+}
+
+static struct seq_operations tpm_ascii_b_measurments_seqops = {
+ .start = tpm_bios_measurements_start,
+ .next = tpm_bios_measurements_next,
+ .stop = tpm_bios_measurements_stop,
+ .show = tpm_ascii_bios_measurements_show,
+};
+
+static struct seq_operations tpm_binary_b_measurments_seqops = {
+ .start = tpm_bios_measurements_start,
+ .next = tpm_bios_measurements_next,
+ .stop = tpm_bios_measurements_stop,
+ .show = tpm_binary_bios_measurements_show,
+};
+
+/* read binary bios log */
+static int read_log(struct tpm_bios_log *log)
+{
+ struct acpi_tcpa *buff;
+ acpi_status status;
+ void *virt;
+
+ if (log->bios_event_log != NULL) {
+ printk(KERN_ERR
+ "%s: ERROR - Eventlog already initialized\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
+ status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
+ ACPI_LOGICAL_ADDRESSING,
+ (struct acpi_table_header **)
+ &buff);
+
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
+ __func__);
+ return -EIO;
+ }
+
+ if (buff->log_max_len == 0) {
+ printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__);
+ return -EIO;
+ }
+
+ /* malloc EventLog space */
+ log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL);
+ if (!log->bios_event_log) {
+ printk
+ ("%s: ERROR - Not enough Memory for BIOS measurements\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ log->bios_event_log_end = log->bios_event_log + buff->log_max_len;
+
+ acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, &virt);
+
+ memcpy(log->bios_event_log, virt, buff->log_max_len);
+
+ acpi_os_unmap_memory(virt, buff->log_max_len);
+ return 0;
+}
+
+static int tpm_ascii_bios_measurements_open(struct inode *inode,
+ struct file *file)
+{
+ int err;
+ struct tpm_bios_log *log;
+ struct seq_file *seq;
+
+ log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
+ if (!log)
+ return -ENOMEM;
+
+ if ((err = read_log(log)))
+ return err;
+
+ /* now register seq file */
+ err = seq_open(file, &tpm_ascii_b_measurments_seqops);
+ if (!err) {
+ seq = file->private_data;
+ seq->private = log;
+ } else {
+ kfree(log->bios_event_log);
+ kfree(log);
+ }
+ return err;
+}
+
+struct file_operations tpm_ascii_bios_measurements_ops = {
+ .open = tpm_ascii_bios_measurements_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = tpm_bios_measurements_release,
+};
+
+static int tpm_binary_bios_measurements_open(struct inode *inode,
+ struct file *file)
+{
+ int err;
+ struct tpm_bios_log *log;
+ struct seq_file *seq;
+
+ log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL);
+ if (!log)
+ return -ENOMEM;
+
+ if ((err = read_log(log)))
+ return err;
+
+ /* now register seq file */
+ err = seq_open(file, &tpm_binary_b_measurments_seqops);
+ if (!err) {
+ seq = file->private_data;
+ seq->private = log;
+ } else {
+ kfree(log->bios_event_log);
+ kfree(log);
+ }
+ return err;
+}
+
+struct file_operations tpm_binary_bios_measurements_ops = {
+ .open = tpm_binary_bios_measurements_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = tpm_bios_measurements_release,
+};
+
+struct dentry **tpm_bios_log_setup(char *name)
+{
+ struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file;
+
+ tpm_dir = securityfs_create_dir(name, NULL);
+ if (!tpm_dir)
+ goto out;
+
+ bin_file =
+ securityfs_create_file("binary_bios_measurements",
+ S_IRUSR | S_IRGRP, tpm_dir, NULL,
+ &tpm_binary_bios_measurements_ops);
+ if (!bin_file)
+ goto out_tpm;
+
+ ascii_file =
+ securityfs_create_file("ascii_bios_measurements",
+ S_IRUSR | S_IRGRP, tpm_dir, NULL,
+ &tpm_ascii_bios_measurements_ops);
+ if (!ascii_file)
+ goto out_bin;
+
+ ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL);
+ if (!ret)
+ goto out_ascii;
+
+ ret[0] = ascii_file;
+ ret[1] = bin_file;
+ ret[2] = tpm_dir;
+
+ return ret;
+
+out_ascii:
+ securityfs_remove(ascii_file);
+out_bin:
+ securityfs_remove(bin_file);
+out_tpm:
+ securityfs_remove(tpm_dir);
+out:
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(tpm_bios_log_setup);
+
+void tpm_bios_log_teardown(struct dentry **lst)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ securityfs_remove(lst[i]);
+}
+EXPORT_SYMBOL_GPL(tpm_bios_log_teardown);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 4b1eef51ec5..1eda82b31a6 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -166,9 +166,12 @@ static struct tty_struct *alloc_tty_struct(void)
return tty;
}
+static void tty_buffer_free_all(struct tty_struct *);
+
static inline void free_tty_struct(struct tty_struct *tty)
{
kfree(tty->write_buf);
+ tty_buffer_free_all(tty);
kfree(tty);
}
@@ -231,6 +234,201 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
}
/*
+ * Tty buffer allocation management
+ */
+
+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;
+}
+
+static void tty_buffer_init(struct tty_struct *tty)
+{
+ tty->buf.head = NULL;
+ tty->buf.tail = NULL;
+ tty->buf.free = NULL;
+}
+
+static struct tty_buffer *tty_buffer_alloc(size_t size)
+{
+ struct tty_buffer *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->char_buf_ptr = (char *)(p->data);
+ p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
+/* printk("Flip create %p\n", p); */
+ return p;
+}
+
+/* Must be called with the tty_read lock held. This needs to acquire strategy
+ code to decide if we should kfree or relink a given expired buffer */
+
+static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+{
+ /* Dumb strategy for now - should keep some stats */
+/* printk("Flip dispose %p\n", b); */
+ if(b->size >= 512)
+ kfree(b);
+ else {
+ b->next = tty->buf.free;
+ tty->buf.free = b;
+ }
+}
+
+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;
+ /* DEBUG ONLY */
+ memset(t->data, '*', size);
+/* printk("Flip recycle %p\n", t); */
+ return t;
+ }
+ tbh = &((*tbh)->next);
+ }
+ /* Round the buffer size out */
+ size = (size + 0xFF) & ~ 0xFF;
+ return tty_buffer_alloc(size);
+ /* Should possibly check if this fails for the largest buffer we
+ have queued and recycle that ? */
+}
+
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+ struct tty_buffer *b = tty->buf.head, *n;
+ int left = 0;
+
+ /* 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 != NULL)
+ left = b->size - b->used;
+ if(left >= size)
+ return size;
+ /* This is the slow path - looking for new buffers to use */
+ n = tty_buffer_find(tty, size);
+ if(n == NULL)
+ return left;
+ n->next = b;
+ if(b != NULL)
+ b->next = n;
+ else
+ tty->buf.head = n;
+ tty->buf.tail = n;
+ return size;
+}
+
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+
+int tty_insert_flip_string(struct tty_struct *tty, 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;
+/* printk("Flip insert %d.\n", 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_GPL(tty_insert_flip_string);
+
+int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned char *chars, 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_GPL(tty_insert_flip_string_flags);
+
+
+/*
+ * 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!
+ */
+
+int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size)
+{
+ int space = tty_buffer_request_room(tty, size);
+ 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);
+
+/*
+ * 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!
+ */
+
+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);
+ 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);
+
+
+
+/*
* This is probably overkill for real world processors but
* they are not on hot paths so a little discipline won't do
* any harm.
@@ -492,6 +690,17 @@ restart:
if (ld == NULL)
return -EINVAL;
+ /*
+ * No more input please, we are switching. The new ldisc
+ * will update this value in the ldisc open function
+ */
+
+ tty->receive_room = 0;
+
+ /*
+ * Problem: What do we do if this blocks ?
+ */
+
tty_wait_until_sent(tty, 0);
if (tty->ldisc.num == ldisc) {
@@ -560,9 +769,9 @@ restart:
* we say so later on.
*/
- work = cancel_delayed_work(&tty->flip.work);
+ work = cancel_delayed_work(&tty->buf.work);
/*
- * Wait for ->hangup_work and ->flip.work handlers to terminate
+ * Wait for ->hangup_work and ->buf.work handlers to terminate
*/
flush_scheduled_work();
@@ -616,7 +825,7 @@ restart:
/* Restart it in case no characters kick it off. Safe if
already running */
if (work)
- schedule_delayed_work(&tty->flip.work, 1);
+ schedule_delayed_work(&tty->buf.work, 1);
return retval;
}
@@ -1721,10 +1930,10 @@ static void release_dev(struct file * filp)
*/
clear_bit(TTY_LDISC, &tty->flags);
clear_bit(TTY_DONT_FLIP, &tty->flags);
- cancel_delayed_work(&tty->flip.work);
+ cancel_delayed_work(&tty->buf.work);
/*
- * Wait for ->hangup_work and ->flip.work handlers to terminate
+ * Wait for ->hangup_work and ->buf.work handlers to terminate
*/
flush_scheduled_work();
@@ -2518,17 +2727,15 @@ EXPORT_SYMBOL(do_SAK);
/*
* This routine is called out of the software interrupt to flush data
- * from the flip buffer to the line discipline.
+ * from the buffer chain to the line discipline.
*/
static void flush_to_ldisc(void *private_)
{
struct tty_struct *tty = (struct tty_struct *) private_;
- unsigned char *cp;
- char *fp;
- int count;
unsigned long flags;
struct tty_ldisc *disc;
+ struct tty_buffer *tbuf;
disc = tty_ldisc_ref(tty);
if (disc == NULL) /* !TTY_LDISC */
@@ -2538,28 +2745,22 @@ static void flush_to_ldisc(void *private_)
/*
* Do it after the next timer tick:
*/
- schedule_delayed_work(&tty->flip.work, 1);
+ schedule_delayed_work(&tty->buf.work, 1);
goto out;
}
spin_lock_irqsave(&tty->read_lock, flags);
- if (tty->flip.buf_num) {
- cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
- fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
- tty->flip.buf_num = 0;
- tty->flip.char_buf_ptr = tty->flip.char_buf;
- tty->flip.flag_buf_ptr = tty->flip.flag_buf;
- } else {
- cp = tty->flip.char_buf;
- fp = tty->flip.flag_buf;
- tty->flip.buf_num = 1;
- tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
- tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
- }
- count = tty->flip.count;
- tty->flip.count = 0;
+ while((tbuf = tty->buf.head) != NULL) {
+ tty->buf.head = tbuf->next;
+ spin_unlock_irqrestore(&tty->read_lock, flags);
+ /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */
+ disc->receive_buf(tty, tbuf->char_buf_ptr,
+ tbuf->flag_buf_ptr,
+ tbuf->used);
+ spin_lock_irqsave(&tty->read_lock, flags);
+ tty_buffer_free(tty, tbuf);
+ }
+ tty->buf.tail = NULL;
spin_unlock_irqrestore(&tty->read_lock, flags);
-
- disc->receive_buf(tty, cp, fp, count);
out:
tty_ldisc_deref(disc);
}
@@ -2654,11 +2855,12 @@ void tty_flip_buffer_push(struct tty_struct *tty)
if (tty->low_latency)
flush_to_ldisc((void *) tty);
else
- schedule_delayed_work(&tty->flip.work, 1);
+ schedule_delayed_work(&tty->buf.work, 1);
}
EXPORT_SYMBOL(tty_flip_buffer_push);
+
/*
* This subroutine initializes a tty structure.
*/
@@ -2669,10 +2871,10 @@ static void initialize_tty_struct(struct tty_struct *tty)
tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
tty->pgrp = -1;
tty->overrun_time = jiffies;
- tty->flip.char_buf_ptr = tty->flip.char_buf;
- tty->flip.flag_buf_ptr = tty->flip.flag_buf;
- INIT_WORK(&tty->flip.work, flush_to_ldisc, tty);
- init_MUTEX(&tty->flip.pty_sem);
+ tty->buf.head = tty->buf.tail = NULL;
+ tty_buffer_init(tty);
+ INIT_WORK(&tty->buf.work, flush_to_ldisc, tty);
+ init_MUTEX(&tty->buf.pty_sem);
init_MUTEX(&tty->termios_sem);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 4d75c261f98..cb82ebf4cb0 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -993,11 +993,10 @@ static void vioHandleData(struct HvLpEvent *event)
* Don't attempt to copy more data into the buffer than we
* have room for because it would fail without indication.
*/
- if ((tty->flip.count + 1) > TTY_FLIPBUF_SIZE) {
+ if(tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL) == 0) {
printk(VIOCONS_KERN_WARN "input buffer overflow!\n");
break;
}
- tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL);
}
/* if cevent->len == 0 then no data was added to the buffer and flip.count == 0 */
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index 19ba83635dd..d9325281e48 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -434,13 +434,7 @@ static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp)
SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
return IRQ_HANDLED;
}
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- *tty->flip.char_buf_ptr = ch;
- *tty->flip.flag_buf_ptr = 0;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
- }
+ tty_insert_flip_char(tty, ch, 0);
/* Check if another character is already ready; in that case, the
* spcond_int() function must be used, because this character may have an
@@ -487,13 +481,7 @@ static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp)
else
err = 0;
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- *tty->flip.char_buf_ptr = ch;
- *tty->flip.flag_buf_ptr = err;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
- }
+ tty_insert_flip_char(tty, ch, err);
/* ++TeSche: *All* errors have to be cleared manually,
* else the condition persists for the next chars
@@ -875,13 +863,13 @@ static int scc_open (struct tty_struct * tty, struct file * filp)
local_irq_save(flags);
#if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC)
if (MACH_IS_MVME147 || MACH_IS_MVME16x) {
- for (i=0; i<sizeof(mvme_init_tab)/sizeof(*mvme_init_tab); ++i)
+ for (i = 0; i < ARRAY_SIZE(mvme_init_tab); ++i)
SCCwrite(mvme_init_tab[i].reg, mvme_init_tab[i].val);
}
#endif
#if defined(CONFIG_BVME6000_SCC)
if (MACH_IS_BVME6000) {
- for (i=0; i<sizeof(bvme_init_tab)/sizeof(*bvme_init_tab); ++i)
+ for (i = 0; i < ARRAY_SIZE(bvme_init_tab); ++i)
SCCwrite(bvme_init_tab[i].reg, bvme_init_tab[i].val);
}
#endif
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index 9ac6d43437b..a5b18e086a9 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -718,7 +718,7 @@ static struct platform_driver giu_device_driver = {
},
};
-static int __devinit vr41xx_giu_init(void)
+static int __init vr41xx_giu_init(void)
{
int retval;
@@ -733,7 +733,7 @@ static int __devinit vr41xx_giu_init(void)
return retval;
}
-static void __devexit vr41xx_giu_exit(void)
+static void __exit vr41xx_giu_exit(void)
{
platform_driver_unregister(&giu_device_driver);
diff --git a/drivers/char/vr41xx_rtc.c b/drivers/char/vr41xx_rtc.c
index 435b30748e2..159acd8b778 100644
--- a/drivers/char/vr41xx_rtc.c
+++ b/drivers/char/vr41xx_rtc.c
@@ -127,8 +127,6 @@ struct resource rtc_resource[2] = {
.flags = IORESOURCE_MEM, },
};
-#define RTC_NUM_RESOURCES sizeof(rtc_resource) / sizeof(struct resource)
-
static inline unsigned long read_elapsed_second(void)
{
unsigned long first_low, first_mid, first_high;
@@ -686,7 +684,8 @@ static int __devinit vr41xx_rtc_init(void)
break;
}
- rtc_platform_device = platform_device_register_simple("RTC", -1, rtc_resource, RTC_NUM_RESOURCES);
+ rtc_platform_device = platform_device_register_simple("RTC", -1,
+ rtc_resource, ARRAY_SIZE(rtc_resource));
if (IS_ERR(rtc_platform_device))
return PTR_ERR(rtc_platform_device);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index e91268e8683..f1d9cb7feae 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -2758,29 +2758,6 @@ static void set_vesa_blanking(char __user *p)
vesa_blank_mode = (mode < 4) ? mode : 0;
}
-/*
- * This is called by a timer handler
- */
-static void vesa_powerdown(void)
-{
- struct vc_data *c = vc_cons[fg_console].d;
- /*
- * Power down if currently suspended (1 or 2),
- * suspend if currently blanked (0),
- * else do nothing (i.e. already powered down (3)).
- * Called only if powerdown features are allowed.
- */
- switch (vesa_blank_mode) {
- case VESA_NO_BLANKING:
- c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1, 0);
- break;
- case VESA_VSYNC_SUSPEND:
- case VESA_HSYNC_SUSPEND:
- c->vc_sw->con_blank(c, VESA_POWERDOWN+1, 0);
- break;
- }
-}
-
void do_blank_screen(int entering_gfx)
{
struct vc_data *vc = vc_cons[fg_console].d;
@@ -2791,8 +2768,7 @@ void do_blank_screen(int entering_gfx)
if (console_blanked) {
if (blank_state == blank_vesa_wait) {
blank_state = blank_off;
- vesa_powerdown();
-
+ vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
}
return;
}
@@ -2822,7 +2798,7 @@ void do_blank_screen(int entering_gfx)
save_screen(vc);
/* In case we need to reset origin, blanking hook returns 1 */
- i = vc->vc_sw->con_blank(vc, 1, 0);
+ i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
console_blanked = fg_console + 1;
if (i)
set_origin(vc);
@@ -2830,13 +2806,10 @@ void do_blank_screen(int entering_gfx)
if (console_blank_hook && console_blank_hook(1))
return;
- if (vesa_off_interval) {
+ if (vesa_off_interval && vesa_blank_mode) {
blank_state = blank_vesa_wait;
mod_timer(&console_timer, jiffies + vesa_off_interval);
}
-
- if (vesa_blank_mode)
- vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
}
EXPORT_SYMBOL(do_blank_screen);
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 344001b45af..a6544790af6 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -438,7 +438,7 @@ config INDYDOG
config ZVM_WATCHDOG
tristate "z/VM Watchdog Timer"
- depends on WATCHDOG && ARCH_S390
+ depends on WATCHDOG && S390
help
IBM s/390 and zSeries machines running under z/VM 5.1 or later
provide a virtual watchdog timer to their guest that cause a
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
index e75045fe264..3e8410b5a65 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -28,6 +28,7 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/timer.h>
+#include <linux/completion.h>
#include <linux/jiffies.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -57,7 +58,7 @@ static int ticks = 10000;
/* some device data */
static struct {
- struct semaphore stop;
+ struct completion stop;
volatile int running;
struct timer_list timer;
volatile int queue;
@@ -85,7 +86,7 @@ static void cpu5wdt_trigger(unsigned long unused)
}
else {
/* ticks doesn't matter anyway */
- up(&cpu5wdt_device.stop);
+ complete(&cpu5wdt_device.stop);
}
}
@@ -239,7 +240,7 @@ static int __devinit cpu5wdt_init(void)
if ( !val )
printk(KERN_INFO PFX "sorry, was my fault\n");
- init_MUTEX_LOCKED(&cpu5wdt_device.stop);
+ init_completion(&cpu5wdt_device.stop);
cpu5wdt_device.queue = 0;
clear_bit(0, &cpu5wdt_device.inuse);
@@ -269,7 +270,7 @@ static void __devexit cpu5wdt_exit(void)
{
if ( cpu5wdt_device.queue ) {
cpu5wdt_device.queue = 0;
- down(&cpu5wdt_device.stop);
+ wait_for_completion(&cpu5wdt_device.stop);
}
misc_deregister(&cpu5wdt_misc);
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
index 56d62ba7c6c..b2fc71e2085 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -18,6 +18,7 @@
#include <linux/watchdog.h>
#include <asm/8xx_immap.h>
#include <asm/uaccess.h>
+#include <asm/io.h>
#include <syslib/m8xx_wdt.h>
static unsigned long wdt_opened;
@@ -25,18 +26,26 @@ static int wdt_status;
static void mpc8xx_wdt_handler_disable(void)
{
- volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+ volatile uint __iomem *piscr;
+ piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
- imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE);
+ if (!m8xx_has_internal_rtc)
+ m8xx_wdt_stop_timer();
+ else
+ out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE));
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
}
static void mpc8xx_wdt_handler_enable(void)
{
- volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+ volatile uint __iomem *piscr;
+ piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
- imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE;
+ if (!m8xx_has_internal_rtc)
+ m8xx_wdt_install_timer();
+ else
+ out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE);
printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
}
@@ -68,9 +77,6 @@ static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
loff_t * ppos)
{
- if (ppos != &file->f_pos)
- return -ESPIPE;
-
if (len)
m8xx_wdt_reset();
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index eb667daee19..9dc54736e4e 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -46,12 +46,12 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/clk.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/arch/map.h>
-#include <asm/hardware/clock.h>
#undef S3C24XX_VA_WATCHDOG
#define S3C24XX_VA_WATCHDOG (0)
@@ -397,7 +397,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
return -ENOENT;
}
- clk_use(wdt_clock);
clk_enable(wdt_clock);
/* see if we can actually set the requested timer margin, and if
@@ -444,7 +443,6 @@ static int s3c2410wdt_remove(struct platform_device *dev)
if (wdt_clock != NULL) {
clk_disable(wdt_clock);
- clk_unuse(wdt_clock);
clk_put(wdt_clock);
wdt_clock = NULL;
}
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
index 44d49dfacbb..3843900e94c 100644
--- a/drivers/char/watchdog/wdt977.c
+++ b/drivers/char/watchdog/wdt977.c
@@ -1,5 +1,5 @@
/*
- * Wdt977 0.03: A Watchdog Device for Netwinder W83977AF chip
+ * Wdt977 0.04: A Watchdog Device for Netwinder W83977AF chip
*
* (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
*
@@ -18,6 +18,8 @@
* from minutes to seconds.
* 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
* nwwatchdog_init.
+ * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks
+ * remove limitiation to be used on Netwinders only
*/
#include <linux/module.h>
@@ -28,6 +30,7 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <linux/watchdog.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
@@ -37,8 +40,18 @@
#include <asm/mach-types.h>
#include <asm/uaccess.h>
-#define PFX "Wdt977: "
-#define WATCHDOG_MINOR 130
+#define WATCHDOG_VERSION "0.04"
+#define WATCHDOG_NAME "Wdt977"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+
+#define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */
+#define IO_DATA_PORT (IO_INDEX_PORT+1)
+
+#define UNLOCK_DATA 0x87
+#define LOCK_DATA 0xAA
+#define DEVICE_REGISTER 0x07
+
#define DEFAULT_TIMEOUT 60 /* default timeout in seconds */
@@ -47,6 +60,7 @@ static int timeoutM; /* timeout in minutes */
static unsigned long timer_alive;
static int testmode;
static char expect_close;
+static spinlock_t spinlock;
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
@@ -63,9 +77,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
static int wdt977_start(void)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&spinlock, flags);
+
/* unlock the SuperIO chip */
- outb(0x87,0x370);
- outb(0x87,0x370);
+ outb_p(UNLOCK_DATA, IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA, IO_INDEX_PORT);
/* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
* F2 has the timeout in minutes
@@ -73,28 +91,29 @@ static int wdt977_start(void)
* at timeout, and to reset timer on kbd/mouse activity (not impl.)
* F4 is used to just clear the TIMEOUT'ed state (bit 0)
*/
- outb(0x07,0x370);
- outb(0x08,0x371);
- outb(0xF2,0x370);
- outb(timeoutM,0x371);
- outb(0xF3,0x370);
- outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */
- outb(0xF4,0x370);
- outb(0x00,0x371);
+ outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+ outb_p(0x08, IO_DATA_PORT);
+ outb_p(0xF2, IO_INDEX_PORT);
+ outb_p(timeoutM, IO_DATA_PORT);
+ outb_p(0xF3, IO_INDEX_PORT);
+ outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for kbd/mouse/LED */
+ outb_p(0xF4, IO_INDEX_PORT);
+ outb_p(0x00, IO_DATA_PORT);
/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
/* in test mode watch the bit 1 on F4 to indicate "triggered" */
if (!testmode)
{
- outb(0x07,0x370);
- outb(0x07,0x371);
- outb(0xE6,0x370);
- outb(0x08,0x371);
+ outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+ outb_p(0x07, IO_DATA_PORT);
+ outb_p(0xE6, IO_INDEX_PORT);
+ outb_p(0x08, IO_DATA_PORT);
}
/* lock the SuperIO chip */
- outb(0xAA,0x370);
+ outb_p(LOCK_DATA, IO_INDEX_PORT);
+ spin_unlock_irqrestore(&spinlock, flags);
printk(KERN_INFO PFX "activated.\n");
return 0;
@@ -106,35 +125,39 @@ static int wdt977_start(void)
static int wdt977_stop(void)
{
+ unsigned long flags;
+ spin_lock_irqsave(&spinlock, flags);
+
/* unlock the SuperIO chip */
- outb(0x87,0x370);
- outb(0x87,0x370);
+ outb_p(UNLOCK_DATA, IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA, IO_INDEX_PORT);
/* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
* F3 is reset to its default state
* F4 can clear the TIMEOUT'ed state (bit 0) - back to default
* We can not use GP17 as a PowerLed, as we use its usage as a RedLed
*/
- outb(0x07,0x370);
- outb(0x08,0x371);
- outb(0xF2,0x370);
- outb(0xFF,0x371);
- outb(0xF3,0x370);
- outb(0x00,0x371);
- outb(0xF4,0x370);
- outb(0x00,0x371);
- outb(0xF2,0x370);
- outb(0x00,0x371);
+ outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+ outb_p(0x08, IO_DATA_PORT);
+ outb_p(0xF2, IO_INDEX_PORT);
+ outb_p(0xFF, IO_DATA_PORT);
+ outb_p(0xF3, IO_INDEX_PORT);
+ outb_p(0x00, IO_DATA_PORT);
+ outb_p(0xF4, IO_INDEX_PORT);
+ outb_p(0x00, IO_DATA_PORT);
+ outb_p(0xF2, IO_INDEX_PORT);
+ outb_p(0x00, IO_DATA_PORT);
/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
- outb(0x07,0x370);
- outb(0x07,0x371);
- outb(0xE6,0x370);
- outb(0x08,0x371);
+ outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+ outb_p(0x07, IO_DATA_PORT);
+ outb_p(0xE6, IO_INDEX_PORT);
+ outb_p(0x08, IO_DATA_PORT);
/* lock the SuperIO chip */
- outb(0xAA,0x370);
+ outb_p(LOCK_DATA, IO_INDEX_PORT);
+ spin_unlock_irqrestore(&spinlock, flags);
printk(KERN_INFO PFX "shutdown.\n");
return 0;
@@ -147,19 +170,23 @@ static int wdt977_stop(void)
static int wdt977_keepalive(void)
{
+ unsigned long flags;
+ spin_lock_irqsave(&spinlock, flags);
+
/* unlock the SuperIO chip */
- outb(0x87,0x370);
- outb(0x87,0x370);
+ outb_p(UNLOCK_DATA, IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA, IO_INDEX_PORT);
/* select device Aux2 (device=8) and kicks watchdog reg F2 */
/* F2 has the timeout in minutes */
- outb(0x07,0x370);
- outb(0x08,0x371);
- outb(0xF2,0x370);
- outb(timeoutM,0x371);
+ outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+ outb_p(0x08, IO_DATA_PORT);
+ outb_p(0xF2, IO_INDEX_PORT);
+ outb_p(timeoutM, IO_DATA_PORT);
/* lock the SuperIO chip */
- outb(0xAA,0x370);
+ outb_p(LOCK_DATA, IO_INDEX_PORT);
+ spin_unlock_irqrestore(&spinlock, flags);
return 0;
}
@@ -198,22 +225,26 @@ static int wdt977_set_timeout(int t)
static int wdt977_get_status(int *status)
{
int new_status;
+ unsigned long flags;
- *status=0;
+ spin_lock_irqsave(&spinlock, flags);
/* unlock the SuperIO chip */
- outb(0x87,0x370);
- outb(0x87,0x370);
+ outb_p(UNLOCK_DATA, IO_INDEX_PORT);
+ outb_p(UNLOCK_DATA, IO_INDEX_PORT);
/* select device Aux2 (device=8) and read watchdog reg F4 */
- outb(0x07,0x370);
- outb(0x08,0x371);
- outb(0xF4,0x370);
- new_status = inb(0x371);
+ outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
+ outb_p(0x08, IO_DATA_PORT);
+ outb_p(0xF4, IO_INDEX_PORT);
+ new_status = inb_p(IO_DATA_PORT);
/* lock the SuperIO chip */
- outb(0xAA,0x370);
+ outb_p(LOCK_DATA, IO_INDEX_PORT);
+ spin_unlock_irqrestore(&spinlock, flags);
+
+ *status=0;
if (new_status & 1)
*status |= WDIOF_CARDRESET;
@@ -249,8 +280,8 @@ static int wdt977_release(struct inode *inode, struct file *file)
wdt977_stop();
clear_bit(0,&timer_alive);
} else {
- printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
wdt977_keepalive();
+ printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
}
expect_close = 0;
return 0;
@@ -271,14 +302,17 @@ static int wdt977_release(struct inode *inode, struct file *file)
static ssize_t wdt977_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- if (count) {
- if (!nowayout) {
+ if (count)
+ {
+ if (!nowayout)
+ {
size_t i;
/* In case it was set long ago */
expect_close = 0;
- for (i = 0; i != count; i++) {
+ for (i = 0; i != count; i++)
+ {
char c;
if (get_user(c, buf + i))
return -EFAULT;
@@ -287,6 +321,7 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf,
}
}
+ /* someone wrote to us, we should restart timer */
wdt977_keepalive();
}
return count;
@@ -308,7 +343,7 @@ static struct watchdog_info ident = {
WDIOF_MAGICCLOSE |
WDIOF_KEEPALIVEPING,
.firmware_version = 1,
- .identity = "Winbond 83977",
+ .identity = WATCHDOG_NAME,
};
static int wdt977_ioctl(struct inode *inode, struct file *file,
@@ -405,50 +440,81 @@ static struct notifier_block wdt977_notifier = {
.notifier_call = wdt977_notify_sys,
};
-static int __init nwwatchdog_init(void)
+static int __init wd977_init(void)
{
- int retval;
- if (!machine_is_netwinder())
- return -ENODEV;
+ int rc;
+
+ //if (!machine_is_netwinder())
+ // return -ENODEV;
+
+ printk(KERN_INFO PFX DRIVER_VERSION);
+
+ spin_lock_init(&spinlock);
/* Check that the timeout value is within it's range ; if not reset to the default */
- if (wdt977_set_timeout(timeout)) {
+ if (wdt977_set_timeout(timeout))
+ {
wdt977_set_timeout(DEFAULT_TIMEOUT);
printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n",
DEFAULT_TIMEOUT);
}
- retval = register_reboot_notifier(&wdt977_notifier);
- if (retval) {
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- retval);
- return retval;
+ /* on Netwinder the IOports are already reserved by
+ * arch/arm/mach-footbridge/netwinder-hw.c
+ */
+ if (!machine_is_netwinder())
+ {
+ if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
+ {
+ printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+ IO_INDEX_PORT);
+ rc = -EIO;
+ goto err_out;
+ }
}
- retval = misc_register(&wdt977_miscdev);
- if (retval) {
+ rc = misc_register(&wdt977_miscdev);
+ if (rc)
+ {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, retval);
- unregister_reboot_notifier(&wdt977_notifier);
- return retval;
+ wdt977_miscdev.minor, rc);
+ goto err_out_region;
+ }
+
+ rc = register_reboot_notifier(&wdt977_notifier);
+ if (rc)
+ {
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ rc);
+ goto err_out_miscdev;
}
- printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode = %i)\n",
+ printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
timeout, nowayout, testmode);
return 0;
+
+err_out_miscdev:
+ misc_deregister(&wdt977_miscdev);
+err_out_region:
+ if (!machine_is_netwinder())
+ release_region(IO_INDEX_PORT,2);
+err_out:
+ return rc;
}
-static void __exit nwwatchdog_exit(void)
+static void __exit wd977_exit(void)
{
+ wdt977_stop();
misc_deregister(&wdt977_miscdev);
unregister_reboot_notifier(&wdt977_notifier);
+ release_region(IO_INDEX_PORT,2);
}
-module_init(nwwatchdog_init);
-module_exit(nwwatchdog_exit);
+module_init(wd977_init);
+module_exit(wd977_exit);
-MODULE_AUTHOR("Woody Suwalski <woody@netwinder.org>");
+MODULE_AUTHOR("Woody Suwalski <woodys@xandros.com>");
MODULE_DESCRIPTION("W83977AF Watchdog driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);