summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Config.in4
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/advantechwdt.c241
-rw-r--r--drivers/char/agp/Makefile2
-rw-r--r--drivers/char/agp/agpgart_fe.c3
-rw-r--r--drivers/char/drm/Makefile7
-rw-r--r--drivers/char/drm/bufs.c4
-rw-r--r--drivers/char/drm/drmP.h1
-rw-r--r--drivers/char/drm/ffb_drv.c89
-rw-r--r--drivers/char/drm/i810_dma.c8
-rw-r--r--drivers/char/drm/mga_bufs.c8
-rw-r--r--drivers/char/drm/r128_bufs.c8
-rw-r--r--drivers/char/drm/r128_drv.h5
-rw-r--r--drivers/char/drm/radeon_bufs.c8
-rw-r--r--drivers/char/dsp56k.c40
-rw-r--r--drivers/char/dz.c6
-rw-r--r--drivers/char/i810_rng.c718
-rw-r--r--drivers/char/istallion.c8
-rw-r--r--drivers/char/lp.c27
-rw-r--r--drivers/char/machzwd.c545
-rw-r--r--drivers/char/mem.c11
-rw-r--r--drivers/char/misc.c4
-rw-r--r--drivers/char/mxser.c27
-rw-r--r--drivers/char/pc_keyb.c2
-rw-r--r--drivers/char/pcmcia/Config.in30
-rw-r--r--drivers/char/pcmcia/Makefile1
-rw-r--r--drivers/char/pcmcia/serial_cb.c163
-rw-r--r--drivers/char/rocket.c22
-rw-r--r--drivers/char/serial.c304
-rw-r--r--drivers/char/stallion.c8
-rw-r--r--drivers/char/sx.c2
-rw-r--r--drivers/char/synclink.c10
-rw-r--r--drivers/char/tpqic02.c22
-rw-r--r--drivers/char/tty_io.c66
34 files changed, 1268 insertions, 1138 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 2bb1d4318..a7a6933f7 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -145,6 +145,7 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
fi
tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
+ tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD
tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO
@@ -154,6 +155,7 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
tristate ' NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG
fi
fi
+ tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT
fi
endmenu
@@ -188,7 +190,7 @@ if [ "$CONFIG_FTAPE" != "n" ]; then
fi
endmenu
-tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
+dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
if [ "$CONFIG_AGP" != "n" ]; then
bool ' Intel 440LX/BX/GX and I815/I840/I850 support' CONFIG_AGP_INTEL
bool ' Intel I810/I815 (on-board) support' CONFIG_AGP_I810
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index db50f23f0..0d19b8f39 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -194,6 +194,7 @@ obj-$(CONFIG_NWFLASH) += nwflash.o
obj-$(CONFIG_PCWATCHDOG) += pcwd.o
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
+obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
obj-$(CONFIG_WDT) += wdt.o
@@ -201,6 +202,7 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_I810_TCO) += i810-tco.o
+obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/advantechwdt.c b/drivers/char/advantechwdt.c
new file mode 100644
index 000000000..efe9796cd
--- /dev/null
+++ b/drivers/char/advantechwdt.c
@@ -0,0 +1,241 @@
+/*
+ * Advantech Single Board Computer WDT driver for Linux 2.4.x
+ *
+ * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ * Based on acquirewdt.c which is based on wdt.c.
+ * Original copyright messages:
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ * http://www.redhat.com
+ *
+ * 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.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 1995 Alan Cox <alan@redhat.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+static int advwdt_is_open;
+static spinlock_t advwdt_lock;
+
+/*
+ * You must set these - there is no sane way to probe for this board.
+ *
+ * To enable or restart, write the timeout value in seconds (1 to 63)
+ * to I/O port WDT_START. To disable, read I/O port WDT_STOP.
+ * Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
+ * check your manual (at least the PCA-6159 seems to be different -
+ * the manual says WDT_STOP is 0x43, not 0x443).
+ * (0x43 is also a write-only control register for the 8254 timer!)
+ *
+ * TODO: module parameters to set the I/O port addresses and NOWAYOUT
+ * option at load time.
+ */
+
+#define WDT_STOP 0x443
+#define WDT_START 0x443
+
+#define WD_TIMO 60 /* 1 minute */
+
+/*
+ * Kernel methods.
+ */
+
+static void
+advwdt_ping(void)
+{
+ /* Write a watchdog value */
+ outb_p(WD_TIMO, WDT_START);
+}
+
+static ssize_t
+advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ if (count) {
+ advwdt_ping();
+ return 1;
+ }
+ return 0;
+}
+
+static ssize_t
+advwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static int
+advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ static struct watchdog_info ident = {
+ WDIOF_KEEPALIVEPING, 1, "Advantech WDT"
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ if (copy_to_user((int *)arg, &advwdt_is_open, sizeof(int)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_KEEPALIVE:
+ advwdt_ping();
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int
+advwdt_open(struct inode *inode, struct file *file)
+{
+ switch (MINOR(inode->i_rdev)) {
+ case WATCHDOG_MINOR:
+ spin_lock(&advwdt_lock);
+ if (advwdt_is_open) {
+ spin_unlock(&advwdt_lock);
+ return -EBUSY;
+ }
+ /*
+ * Activate
+ */
+
+ advwdt_is_open = 1;
+ advwdt_ping();
+ spin_unlock(&advwdt_lock);
+ return 0;
+ default:
+ return -ENODEV;
+ }
+}
+
+static int
+advwdt_close(struct inode *inode, struct file *file)
+{
+ lock_kernel();
+ if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+ spin_lock(&advwdt_lock);
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ inb_p(WDT_STOP);
+#endif
+ advwdt_is_open = 0;
+ spin_unlock(&advwdt_lock);
+ }
+ unlock_kernel();
+ return 0;
+}
+
+/*
+ * Notifier for system down
+ */
+
+static int
+advwdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT) {
+ /* Turn the WDT off */
+ inb_p(WDT_STOP);
+ }
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static struct file_operations advwdt_fops = {
+ owner: THIS_MODULE,
+ read: advwdt_read,
+ write: advwdt_write,
+ ioctl: advwdt_ioctl,
+ open: advwdt_open,
+ release: advwdt_close,
+};
+
+static struct miscdevice advwdt_miscdev = {
+ WATCHDOG_MINOR,
+ "watchdog",
+ &advwdt_fops
+};
+
+/*
+ * The WDT needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block advwdt_notifier = {
+ advwdt_notify_sys,
+ NULL,
+ 0
+};
+
+static int __init
+advwdt_init(void)
+{
+ printk("WDT driver for Advantech single board computer initialising.\n");
+
+ spin_lock_init(&advwdt_lock);
+ misc_register(&advwdt_miscdev);
+#if WDT_START != WDT_STOP
+ request_region(WDT_STOP, 1, "Advantech WDT");
+#endif
+ request_region(WDT_START, 1, "Advantech WDT");
+ register_reboot_notifier(&advwdt_notifier);
+ return 0;
+}
+
+static void __exit
+advwdt_exit(void)
+{
+ misc_deregister(&advwdt_miscdev);
+ unregister_reboot_notifier(&advwdt_notifier);
+#if WDT_START != WDT_STOP
+ release_region(WDT_STOP,1);
+#endif
+ release_region(WDT_START,1);
+}
+
+module_init(advwdt_init);
+module_exit(advwdt_exit);
+
+/* end of advantechwdt.c */
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index 3e726b314..42b4053ca 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -7,7 +7,7 @@ O_TARGET := agp.o
export-objs := agpgart_be.o
-multi-objs := agpgart.o
+list-multi := agpgart.o
agpgart-objs := agpgart_fe.o agpgart_be.o
obj-$(CONFIG_AGP) += agpgart.o
diff --git a/drivers/char/agp/agpgart_fe.c b/drivers/char/agp/agpgart_fe.c
index 59f505b96..c9e4c5e78 100644
--- a/drivers/char/agp/agpgart_fe.c
+++ b/drivers/char/agp/agpgart_fe.c
@@ -1105,7 +1105,8 @@ int __init agp_frontend_initialize(void)
return 0;
}
-static void __exit agp_frontend_cleanup(void)
+void __exit agp_frontend_cleanup(void)
{
misc_deregister(&agp_miscdev);
}
+
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
index 6af6e509c..eae8e75f0 100644
--- a/drivers/char/drm/Makefile
+++ b/drivers/char/drm/Makefile
@@ -3,12 +3,10 @@
# the Direct Rendering Infrastructure (DRI) in XFree86 4.x.
#
-# drm.o is a fake target -- it is never built
-# The real targets are in the module-list
O_TARGET := drm.o
-module-list := gamma.o tdfx.o r128.o ffb.o mga.o i810.o
-export-objs := $(patsubst %.o,%_drv.o,$(module-list))
+export-objs := gamma_drv.o tdfx_drv.o r128_drv.o ffb_drv.o mga_drv.o \
+ i810_drv.o
# lib-objs are included in every module so that radical changes to the
# architecture of the DRM support library can be made at a later time.
@@ -42,6 +40,7 @@ else
endif
endif
+list-multi := gamma.o tdfx.o r128.o ffb.o mga.o i810.o
gamma-objs := gamma_drv.o gamma_dma.o
tdfx-objs := tdfx_drv.o tdfx_context.o
r128-objs := r128_drv.o r128_cce.o r128_context.o r128_bufs.o r128_state.o
diff --git a/drivers/char/drm/bufs.c b/drivers/char/drm/bufs.c
index 28e0eb5f1..7cb9dd52b 100644
--- a/drivers/char/drm/bufs.c
+++ b/drivers/char/drm/bufs.c
@@ -485,10 +485,10 @@ int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
return -EFAULT;
if (request.count >= dma->buf_count) {
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, dma->byte_count,
PROT_READ|PROT_WRITE, MAP_SHARED, 0);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
if (virtual > -1024UL) {
/* Real error */
retcode = (signed long)virtual;
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index affeae705..1c0596df7 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -43,6 +43,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
+#include <linux/major.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c
index cf9a9f5d9..1f1c3d1a4 100644
--- a/drivers/char/drm/ffb_drv.c
+++ b/drivers/char/drm/ffb_drv.c
@@ -1,4 +1,4 @@
-/* $Id: ffb_drv.c,v 1.7 2000/11/12 10:01:41 davem Exp $
+/* $Id: ffb_drv.c,v 1.9 2001/03/23 07:58:39 davem Exp $
* ffb_drv.c: Creator/Creator3D direct rendering driver.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -244,7 +244,37 @@ static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance)
};
}
-static int __init ffb_init_one(int prom_node, int instance)
+static void __init ffb_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs)
+{
+ struct linux_prom64_ranges ranges[PROMREG_MAX];
+ char name[128];
+ int len, i;
+
+ prom_getproperty(parent, "name", name, sizeof(name));
+ if (strcmp(name, "upa") != 0)
+ return;
+
+ len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
+ if (len <= 0)
+ return;
+
+ len /= sizeof(struct linux_prom64_ranges);
+ for (i = 0; i < len; i++) {
+ struct linux_prom64_ranges *rng = &ranges[i];
+ u64 phys_addr = regs->phys_addr;
+
+ if (phys_addr >= rng->ot_child_base &&
+ phys_addr < (rng->ot_child_base + rng->or_size)) {
+ regs->phys_addr -= rng->ot_child_base;
+ regs->phys_addr += rng->ot_parent_base;
+ return;
+ }
+ }
+
+ return;
+}
+
+static int __init ffb_init_one(int prom_node, int parent_node, int instance)
{
struct linux_prom64_registers regs[2*PROMREG_MAX];
drm_device_t *dev;
@@ -266,6 +296,7 @@ static int __init ffb_init_one(int prom_node, int instance)
kfree(dev);
return -EINVAL;
}
+ ffb_apply_upa_parent_ranges(parent_node, &regs[0]);
ffb_priv->card_phys_base = regs[0].phys_addr;
ffb_priv->regs = (ffb_fbcPtr)
(regs[0].phys_addr + 0x00600000UL);
@@ -305,15 +336,30 @@ static int __init ffb_init_one(int prom_node, int instance)
return 0;
}
+static int __init ffb_count_siblings(int root)
+{
+ int node, child, count = 0;
+
+ child = prom_getchild(root);
+ for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
+ node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
+ count++;
+
+ return count;
+}
+
static int __init ffb_init_dev_table(void)
{
- int root, node;
- int total = 0;
+ int root, total;
+ total = ffb_count_siblings(prom_root_node);
root = prom_getchild(prom_root_node);
- for (node = prom_searchsiblings(root, "SUNW,ffb"); node;
- node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
- total++;
+ for (root = prom_searchsiblings(root, "upa"); root;
+ root = prom_searchsiblings(prom_getsibling(root), "upa"))
+ total += ffb_count_siblings(root);
+
+ if (!total)
+ return -ENODEV;
ffb_dev_table = kmalloc(sizeof(drm_device_t *) * total, GFP_KERNEL);
if (!ffb_dev_table)
@@ -324,23 +370,34 @@ static int __init ffb_init_dev_table(void)
return 0;
}
+static int __init ffb_scan_siblings(int root, int instance)
+{
+ int node, child;
+
+ child = prom_getchild(root);
+ for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
+ node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) {
+ ffb_init_one(node, root, instance);
+ instance++;
+ }
+
+ return instance;
+}
+
int __init ffb_init(void)
{
- int root, node, instance, ret;
+ int root, instance, ret;
ret = ffb_init_dev_table();
if (ret)
return ret;
- instance = 0;
+ instance = ffb_scan_siblings(prom_root_node, 0);
+
root = prom_getchild(prom_root_node);
- for (node = prom_searchsiblings(root, "SUNW,ffb"); node;
- node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) {
- ret = ffb_init_one(node, instance);
- if (ret)
- return ret;
- instance++;
- }
+ for (root = prom_searchsiblings(root, "upa"); root;
+ root = prom_searchsiblings(prom_getsibling(root), "upa"))
+ instance = ffb_scan_siblings(root, instance);
return 0;
}
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index aa824a79c..427194b87 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -192,7 +192,7 @@ static int i810_map_buffer(drm_buf_t *buf, struct file *filp)
if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL;
if(VM_DONTCOPY != 0) {
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
old_fops = filp->f_op;
filp->f_op = &i810_buffer_fops;
dev_priv->mmap_buffer = buf;
@@ -208,7 +208,7 @@ static int i810_map_buffer(drm_buf_t *buf, struct file *filp)
retcode = (signed int)buf_priv->virtual;
buf_priv->virtual = 0;
}
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
} else {
buf_priv->virtual = buf_priv->kernel_virtual;
buf_priv->currently_mapped = I810_BUF_MAPPED;
@@ -224,7 +224,7 @@ static int i810_unmap_buffer(drm_buf_t *buf)
if(VM_DONTCOPY != 0) {
if(buf_priv->currently_mapped != I810_BUF_MAPPED)
return -EINVAL;
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
#if LINUX_VERSION_CODE < 0x020399
retcode = do_munmap((unsigned long)buf_priv->virtual,
(size_t) buf->total);
@@ -233,7 +233,7 @@ static int i810_unmap_buffer(drm_buf_t *buf)
(unsigned long)buf_priv->virtual,
(size_t) buf->total);
#endif
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
}
buf_priv->currently_mapped = I810_BUF_UNMAPPED;
buf_priv->virtual = 0;
diff --git a/drivers/char/drm/mga_bufs.c b/drivers/char/drm/mga_bufs.c
index 05d941b4c..fe74ce0e8 100644
--- a/drivers/char/drm/mga_bufs.c
+++ b/drivers/char/drm/mga_bufs.c
@@ -549,17 +549,17 @@ int mga_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_DEBUG("map->flags : %x\n", map->flags);
DRM_DEBUG("map->handle : %p\n", map->handle);
DRM_DEBUG("map->mtrr : %d\n", map->mtrr);
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, map->size,
PROT_READ|PROT_WRITE,
MAP_SHARED,
(unsigned long)map->offset);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
} else {
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, dma->byte_count,
PROT_READ|PROT_WRITE, MAP_SHARED, 0);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
}
if (virtual > -1024UL) {
/* Real error */
diff --git a/drivers/char/drm/r128_bufs.c b/drivers/char/drm/r128_bufs.c
index a060749e3..5b35752b5 100644
--- a/drivers/char/drm/r128_bufs.c
+++ b/drivers/char/drm/r128_bufs.c
@@ -249,17 +249,17 @@ int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
goto done;
}
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, map->size,
PROT_READ|PROT_WRITE,
MAP_SHARED,
(unsigned long)map->offset);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
} else {
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, dma->byte_count,
PROT_READ|PROT_WRITE, MAP_SHARED, 0);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
}
if (virtual > -1024UL) {
/* Real error */
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index cffd08002..901b4f1ec 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -447,6 +447,11 @@ extern int R128_READ_PLL(drm_device_t *dev, int addr);
DRM_INFO( "ADVANCE_RING() tail=0x%06x wr=0x%06x\n", \
write, dev_priv->ring.tail ); \
} \
+ if ( write < 32 ) { \
+ memcpy( dev_priv->ring.end, \
+ dev_priv->ring.start, \
+ write * sizeof(u32) ); \
+ } \
r128_flush_write_combine(); \
dev_priv->ring.tail = write; \
R128_WRITE( R128_PM4_BUFFER_DL_WPTR, write ); \
diff --git a/drivers/char/drm/radeon_bufs.c b/drivers/char/drm/radeon_bufs.c
index 9a3093eb1..320bd4c30 100644
--- a/drivers/char/drm/radeon_bufs.c
+++ b/drivers/char/drm/radeon_bufs.c
@@ -240,17 +240,17 @@ int radeon_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
goto done;
}
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, map->size,
PROT_READ|PROT_WRITE,
MAP_SHARED,
(unsigned long)map->offset);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
} else {
- down(&current->mm->mmap_sem);
+ down_write(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, dma->byte_count,
PROT_READ|PROT_WRITE, MAP_SHARED, 0);
- up(&current->mm->mmap_sem);
+ up_write(&current->mm->mmap_sem);
}
if (virtual > -1024UL) {
/* Real error */
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 7de536f77..ee7b3f0b1 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -265,7 +265,7 @@ static ssize_t dsp56k_read(struct file *file, char *buf, size_t count,
}
default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
+ printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
return -ENXIO;
}
}
@@ -327,7 +327,7 @@ static ssize_t dsp56k_write(struct file *file, const char *buf, size_t count,
return -EFAULT;
}
default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
+ printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
return -ENXIO;
}
}
@@ -416,7 +416,7 @@ static int dsp56k_ioctl(struct inode *inode, struct file *file,
return 0;
default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
+ printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
return -ENXIO;
}
}
@@ -469,7 +469,7 @@ static int dsp56k_open(struct inode *inode, struct file *file)
break;
default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
+ printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
return -ENXIO;
}
@@ -490,7 +490,7 @@ static int dsp56k_release(struct inode *inode, struct file *file)
break;
default:
- printk("DSP56k driver: Unknown minor device: %d\n", dev);
+ printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
return -ENXIO;
}
@@ -511,7 +511,9 @@ static struct file_operations dsp56k_fops = {
static devfs_handle_t devfs_handle;
-int __init dsp56k_init(void)
+static const char banner[] __initdata = KERN_INFO "DSP56k driver installed\n";
+
+static int __init dsp56k_init_driver(void)
{
if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
printk("DSP56k driver: Hardware not present\n");
@@ -522,27 +524,19 @@ int __init dsp56k_init(void)
printk("DSP56k driver: Unable to register driver\n");
return -ENODEV;
}
- devfs_handle = devfs_register (NULL, "dsp56k", DEVFS_FL_DEFAULT,
- DSP56K_MAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR,
- &dsp56k_fops, NULL);
-
- dsp56k.in_use = 0;
-
- printk("DSP56k driver installed\n");
+ devfs_handle = devfs_register(NULL, "dsp56k", DEVFS_FL_DEFAULT,
+ DSP56K_MAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
+ &dsp56k_fops, NULL);
+ printk(banner);
return 0;
}
+module_init(dsp56k_init_driver);
-#ifdef MODULE
-int init_module(void)
-{
- return dsp56k_init();
-}
-
-void cleanup_module(void)
+static void __exit dsp56k_cleanup_driver(void)
{
devfs_unregister_chrdev(DSP56K_MAJOR, "dsp56k");
- devfs_unregister (devfs_handle);
+ devfs_unregister(devfs_handle);
}
-#endif /* MODULE */
+module_exit(dsp56k_cleanup_driver);
diff --git a/drivers/char/dz.c b/drivers/char/dz.c
index a97d8a694..47918ce4a 100644
--- a/drivers/char/dz.c
+++ b/drivers/char/dz.c
@@ -847,10 +847,12 @@ static int set_serial_info (struct dz_serial *info, struct serial_struct *new_in
if (!new_info)
return -EFAULT;
- copy_from_user (&new_serial, new_info, sizeof(new_serial));
+ if(copy_from_user (&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
+
old_info = *info;
- if (!suser())
+ if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (info->count > 1)
diff --git a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c
index 79dc5d56d..6661e76bf 100644
--- a/drivers/char/i810_rng.c
+++ b/drivers/char/i810_rng.c
@@ -1,184 +1,18 @@
/*
Hardware driver for Intel i810 Random Number Generator (RNG)
- Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
- Copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
Driver Web site: http://sourceforge.net/projects/gkernel/
-
-
- Based on:
- Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet
- May 1999 Order Number: 290658-002 R
-
- Intel 82802 Firmware Hub: Random Number Generator
- Programmer's Reference Manual
- December 1999 Order Number: 298029-001 R
-
- Intel 82802 Firmware HUB Random Number Generator Driver
- Copyright (c) 2000 Matt Sottek <msottek@quiknet.com>
-
- Special thanks to Matt Sottek. I did the "guts", he
- did the "brains" and all the testing. (Anybody wanna send
- me an i810 or i820?)
+ Please read Documentation/i810_rng.txt for details on use.
----------------------------------------------------------
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
- ----------------------------------------------------------
-
- From the firmware hub datasheet:
-
- The Firmware Hub integrates a Random Number Generator (RNG)
- using thermal noise generated from inherently random quantum
- mechanical properties of silicon. When not generating new random
- bits the RNG circuitry will enter a low power state. Intel will
- provide a binary software driver to give third party software
- access to our RNG for use as a security feature. At this time,
- the RNG is only to be used with a system in an OS-present state.
-
- ----------------------------------------------------------
-
- Theory of operation:
-
- This driver has TWO modes of operation:
-
- Mode 1
- ------
- Character driver. Using the standard open()
- and read() system calls, you can read random data from
- the i810 RNG device. This data is NOT CHECKED by any
- fitness tests, and could potentially be bogus (if the
- hardware is faulty or has been tampered with).
-
- /dev/intel_rng is char device major 10, minor 183.
-
-
- Mode 2
- ------
- Injection of entropy into the kernel entropy pool via a
- timer function.
-
- A timer is run at rng_timer_len intervals, reading 8 bits
- of data from the RNG. If the RNG has previously passed a
- FIPS test, then the data will be added to the /dev/random
- entropy pool. Then, those 8 bits are added to an internal
- test data pool. When that pool is full, a FIPS test is
- run to verify that the last N bytes read are decently random.
-
- Thus, the RNG will never be enabled until it passes a
- FIPS test. And, data will stop flowing into the system
- entropy pool if the data is determined to be non-random.
-
- Finally, note that the timer defaults to OFF. This ensures
- that the system entropy pool will not be polluted with
- RNG-originated data unless a conscious decision is made
- by the user.
-
- HOWEVER NOTE THAT UP TO 2499 BYTES OF DATA CAN BE BOGUS
- BEFORE THE SYSTEM WILL NOTICE VIA THE FIPS TEST.
-
- ----------------------------------------------------------
-
- Driver notes:
-
- * You may enable and disable the RNG timer via sysctl:
-
- # disable RNG
- echo 0 > /proc/sys/dev/i810_rng_timer
-
- # enable RNG
- echo 1 > /proc/sys/dev/i810_rng_timer
-
- * The default number of entropy bits added by default is
- the full 8 bits. If you wish to reduce this value for
- paranoia's sake, you can do so via sysctl as well:
-
- # Add only 4 bits of entropy to /dev/random
- echo 4 > /proc/sys/dev/i810_rng_entropy
-
- * The default number of entropy bits can also be set via
- a module parameter "rng_entropy" at module load time.
-
- * When the RNG timer is enabled, the driver reads 1 byte
- from the hardware RNG every N jiffies. By default, every
- half-second. If you would like to change the timer interval,
- do so via another sysctl:
-
- echo 200 > /proc/sys/dev/i810_rng_interval
-
- NOTE THIS VALUE IS IN JIFFIES, NOT SECONDS OR MILLISECONDS.
- Minimum interval is 1 jiffy, maximum interval is 24 hours.
-
- * In order to unload the i810_rng module, you must first
- disable the hardware via sysctl i810_hw_enabled, as shown above,
- and make sure all users of the character device have closed
-
- * The timer and the character device may be used simultaneously,
- if desired.
-
- * FIXME: support poll()
-
- * FIXME: should we be crazy and support mmap()?
-
- * FIXME: It is possible for the timer function to read,
- and shove into the kernel entropy pool, 2499 bytes of data
- before the internal FIPS test notices that the data is bad.
- The kernel should handle this (I think???), but we should use a
- 2500-byte array, and re-run the FIPS test for every byte read.
- This will slow things down but guarantee that bad data is
- never passed upstream.
-
- * FIXME: module unload is racy. To fix this, struct ctl_table
- needs an owner member a la struct file_operations.
-
- * Since the RNG is accessed from a timer as well as normal
- kernel code, but not from interrupts, we use spin_lock_bh
- in regular code, and spin_lock in the timer function, to
- serialize access to the RNG hardware area.
-
- ----------------------------------------------------------
-
- Change history:
-
- Version 0.6.2:
- * Clean up spinlocks. Since we don't have any interrupts
- to worry about, but we do have a timer to worry about,
- we use spin_lock_bh everywhere except the timer function
- itself.
- * Fix module load/unload.
- * Fix timer function and h/w enable/disable logic
- * New timer interval sysctl
- * Clean up sysctl names
-
- Version 0.9.0:
- * Don't register a pci_driver, because we are really
- using PCI bridge vendor/device ids, and someone
- may want to register a driver for the bridge. (bug fix)
- * Don't let the usage count go negative (bug fix)
- * Clean up spinlocks (bug fix)
- * Enable PCI device, if necessary (bug fix)
- * iounmap on module unload (bug fix)
- * If RNG chrdev is already in use when open(2) is called,
- sleep until it is available.
- * Remove redundant globals rng_allocated, rng_use_count
- * Convert numeric globals to unsigned
- * Module unload cleanup
-
- Version 0.9.1:
- * Support i815 chipsets too (Matt Sottek)
- * Fix reference counting when statically compiled (prumpf)
- * Rewrite rng_dev_read (prumpf)
- * Make module races less likely (prumpf)
- * Small miscellaneous bug fixes (prumpf)
- * Use pci table for PCI id list
-
- Version 0.9.2:
- * Simplify open blocking logic
-
*/
@@ -190,7 +24,6 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/random.h>
-#include <linux/sysctl.h>
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/mm.h>
@@ -202,7 +35,7 @@
/*
* core module and version information
*/
-#define RNG_VERSION "0.9.2"
+#define RNG_VERSION "0.9.5"
#define RNG_MODULE_NAME "i810_rng"
#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
#define PFX RNG_MODULE_NAME ": "
@@ -211,7 +44,7 @@
/*
* debugging macros
*/
-#undef RNG_DEBUG /* define to 1 to enable copious debugging info */
+#undef RNG_DEBUG /* define to enable copious debugging info */
#ifdef RNG_DEBUG
/* note: prints function name for you */
@@ -220,8 +53,8 @@
#define DPRINTK(fmt, args...)
#endif
-#define RNG_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */
-#if RNG_NDEBUG
+#undef RNG_NDEBUG /* define to disable lightweight runtime checks */
+#ifdef RNG_NDEBUG
#define assert(expr)
#else
#define assert(expr) \
@@ -233,13 +66,6 @@
/*
- * prototypes
- */
-static void rng_fips_test_store (int rng_data);
-static void rng_run_fips_test (void);
-
-
-/*
* RNG registers (offsets from rng_mem)
*/
#define RNG_HW_STATUS 0
@@ -249,6 +75,9 @@ static void rng_run_fips_test (void);
#define RNG_DATA_PRESENT 0x01
#define RNG_DATA 2
+/*
+ * Magic address at which Intel PCI bridges locate the RNG
+ */
#define RNG_ADDR 0xFFBC015F
#define RNG_ADDR_LEN 3
@@ -258,13 +87,6 @@ static void rng_run_fips_test (void);
/*
- * Frequency that data is added to kernel entropy pool
- * HZ>>1 == every half-second
- */
-#define RNG_DEF_TIMER_LEN (HZ >> 1)
-
-
-/*
* number of bytes required for a FIPS test.
* do not alter unless you really, I mean
* REALLY know what you are doing.
@@ -277,18 +99,7 @@ static void rng_run_fips_test (void);
* as we only support a single RNG device
*/
static int rng_hw_enabled; /* is the RNG h/w enabled? */
-static int rng_timer_enabled; /* is the RNG timer enabled? */
-static int rng_trusted; /* does FIPS trust out data? */
-static int rng_enabled_sysctl; /* sysctl for enabling/disabling RNG */
-static unsigned int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */
-static unsigned int rng_entropy_sysctl; /* sysctl for changing entropy bits */
-static unsigned int rng_interval_sysctl; /* sysctl for changing timer interval */
-static int rng_have_mem_region; /* did we grab RNG region via request_mem_region? */
-static unsigned int rng_fips_counter; /* size of internal FIPS test data pool */
-static unsigned int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */
static void *rng_mem; /* token to our ioremap'd RNG register area */
-static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */
-static struct timer_list rng_timer; /* kernel timer for RNG hardware reads and tests */
static struct pci_dev *rng_pdev; /* Firmware Hub PCI device found during PCI probe */
static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */
@@ -313,7 +124,7 @@ static inline void rng_hwstatus_set (u8 hw_status)
static inline int rng_data_present (void)
{
assert (rng_mem != NULL);
- assert (rng_hw_enabled == 1);
+ assert (rng_hw_enabled > 0);
return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0;
}
@@ -322,55 +133,13 @@ static inline int rng_data_present (void)
static inline int rng_data_read (void)
{
assert (rng_mem != NULL);
- assert (rng_hw_enabled == 1);
+ assert (rng_hw_enabled > 0);
return readb (rng_mem + RNG_DATA);
}
/*
- * rng_timer_ticker - executes every rng_timer_len jiffies,
- * adds a single byte to system entropy
- * and internal FIPS test pools
- */
-static void rng_timer_tick (unsigned long data)
-{
- int rng_data;
-
- spin_lock (&rng_lock);
-
- if (rng_data_present ()) {
- /* gimme some thermal noise, baby */
- rng_data = rng_data_read ();
-
- spin_unlock (&rng_lock);
-
- /*
- * if RNG has been verified in the past, add
- * data just read to the /dev/random pool,
- * with the entropy specified by the user
- * via sysctl (defaults to 8 bits)
- */
- if (rng_trusted)
- batch_entropy_store (rng_data, jiffies, rng_entropy);
-
- /* fitness testing via FIPS, if we have enough data */
- rng_fips_test_store (rng_data);
- if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD)
- rng_run_fips_test ();
- } else {
- spin_unlock (&rng_lock);
- }
-
- /* run the timer again, if enabled */
- if (rng_timer_enabled) {
- rng_timer.expires = jiffies + rng_timer_len;
- add_timer (&rng_timer);
- }
-}
-
-
-/*
* rng_enable - enable or disable the RNG hardware
*/
static int rng_enable (int enable)
@@ -380,8 +149,6 @@ static int rng_enable (int enable)
DPRINTK ("ENTER\n");
- spin_lock_bh (&rng_lock);
-
hw_status = rng_hwstatus ();
if (enable) {
@@ -406,18 +173,16 @@ static int rng_enable (int enable)
new_status = rng_hwstatus ();
- spin_unlock_bh (&rng_lock);
-
- if (action == 1)
- printk (KERN_INFO PFX "RNG h/w enabled\n");
- else if (action == 2)
- printk (KERN_INFO PFX "RNG h/w disabled\n");
-
- /* too bad C doesn't have ^^ */
- if ((!enable) != (!(new_status & RNG_ENABLED))) {
- printk (KERN_ERR PFX "Unable to %sable the RNG\n",
- enable ? "en" : "dis");
- rc = -EIO;
+ if (action == 1) {
+ if (new_status & RNG_ENABLED)
+ printk (KERN_INFO PFX "RNG h/w enabled\n");
+ else
+ printk (KERN_ERR PFX "Unable to enable the RNG\n");
+ } else if (action == 2) {
+ if ((new_status & RNG_ENABLED) == 0)
+ printk (KERN_INFO PFX "RNG h/w disabled\n");
+ else
+ printk (KERN_ERR PFX "Unable to disable the RNG\n");
}
DPRINTK ("EXIT, returning %d\n", rc);
@@ -425,209 +190,12 @@ static int rng_enable (int enable)
}
-/*
- * rng_handle_sysctl_enable - handle a read or write of our enable/disable sysctl
- */
-
-static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file *filp,
- void *buffer, size_t * lenp)
-{
- int enabled_save, rc;
-
- DPRINTK ("ENTER\n");
-
- MOD_INC_USE_COUNT;
- spin_lock_bh (&rng_lock);
- rng_enabled_sysctl = enabled_save = rng_timer_enabled;
- spin_unlock_bh (&rng_lock);
-
- rc = proc_dointvec (table, write, filp, buffer, lenp);
- if (rc)
- return rc;
-
- spin_lock_bh (&rng_lock);
- if (enabled_save != rng_enabled_sysctl) {
- rng_timer_enabled = rng_enabled_sysctl;
- spin_unlock_bh (&rng_lock);
-
- /* enable/disable hardware */
- rng_enable (rng_enabled_sysctl);
-
- /* enable/disable timer */
- if (rng_enabled_sysctl) {
- rng_timer.expires = jiffies + rng_timer_len;
- add_timer (&rng_timer);
- } else {
- del_timer_sync (&rng_timer);
- }
- } else {
- spin_unlock_bh (&rng_lock);
- }
-
- /* This needs to be in a higher layer */
- MOD_DEC_USE_COUNT;
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-/*
- * rng_handle_sysctl_entropy - handle a read or write of our entropy bits sysctl
- */
-
-static int rng_handle_sysctl_entropy (ctl_table * table, int write, struct file *filp,
- void *buffer, size_t * lenp)
-{
- int entropy_bits_save, rc;
-
- DPRINTK ("ENTER\n");
-
- spin_lock_bh (&rng_lock);
- rng_entropy_sysctl = entropy_bits_save = rng_entropy;
- spin_unlock_bh (&rng_lock);
-
- rc = proc_dointvec (table, write, filp, buffer, lenp);
- if (rc)
- return rc;
-
- if (entropy_bits_save == rng_entropy_sysctl)
- goto out;
-
- if ((rng_entropy_sysctl >= 0) &&
- (rng_entropy_sysctl <= 8)) {
- spin_lock_bh (&rng_lock);
- rng_entropy = rng_entropy_sysctl;
- spin_unlock_bh (&rng_lock);
-
- printk (KERN_INFO PFX "entropy bits now %d\n", rng_entropy_sysctl);
- } else {
- printk (KERN_INFO PFX "ignoring invalid entropy setting (%d)\n",
- rng_entropy_sysctl);
- }
-
-out:
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-/*
- * rng_handle_sysctl_interval - handle a read or write of our timer interval len sysctl
- */
-
-static int rng_handle_sysctl_interval (ctl_table * table, int write, struct file *filp,
- void *buffer, size_t * lenp)
-{
- int timer_len_save, rc;
-
- DPRINTK ("ENTER\n");
-
- spin_lock_bh (&rng_lock);
- rng_interval_sysctl = timer_len_save = rng_timer_len;
- spin_unlock_bh (&rng_lock);
-
- rc = proc_dointvec (table, write, filp, buffer, lenp);
- if (rc)
- return rc;
-
- if (timer_len_save == rng_interval_sysctl)
- goto out;
-
- if ((rng_interval_sysctl > 0) &&
- (rng_interval_sysctl < (HZ*86400))) {
- spin_lock_bh (&rng_lock);
- rng_timer_len = rng_interval_sysctl;
- spin_unlock_bh (&rng_lock);
-
- printk (KERN_INFO PFX "timer interval now %d\n", rng_interval_sysctl);
- } else {
- printk (KERN_INFO PFX "ignoring invalid timer interval (%d)\n",
- rng_interval_sysctl);
- }
-
-out:
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-/*
- * rng_sysctl - add or remove the rng sysctl
- */
-static void rng_sysctl (int add)
-{
-#define DEV_I810_TIMER 1
-#define DEV_I810_ENTROPY 2
-#define DEV_I810_INTERVAL 3
-
- /* Definition of the sysctl */
- /* FIXME: use new field:value style of struct initialization */
- static ctl_table rng_sysctls[] = {
- {DEV_I810_TIMER, /* ID */
- RNG_MODULE_NAME "_timer", /* name in /proc */
- &rng_enabled_sysctl,
- sizeof (rng_enabled_sysctl), /* data ptr, data size */
- 0644, /* mode */
- 0, /* child */
- rng_handle_sysctl_enable, /* proc handler */
- 0, /* strategy */
- 0, /* proc control block */
- 0, 0}
- ,
- {DEV_I810_ENTROPY, /* ID */
- RNG_MODULE_NAME "_entropy", /* name in /proc */
- &rng_entropy_sysctl,
- sizeof (rng_entropy_sysctl), /* data ptr, data size */
- 0644, /* mode */
- 0, /* child */
- rng_handle_sysctl_entropy, /* proc handler */
- 0, /* strategy */
- 0, /* proc control block */
- 0, 0}
- ,
- {DEV_I810_INTERVAL, /* ID */
- RNG_MODULE_NAME "_interval", /* name in /proc */
- &rng_interval_sysctl,
- sizeof (rng_interval_sysctl), /* data ptr, data size */
- 0644, /* mode */
- 0, /* child */
- rng_handle_sysctl_interval, /* proc handler */
- 0, /* strategy */
- 0, /* proc control block */
- 0, 0}
- ,
- {0}
- };
-
- /* Define the parent file : /proc/sys/dev */
- static ctl_table sysctls_root[] = {
- {CTL_DEV,
- "dev",
- NULL, 0,
- 0555,
- rng_sysctls},
- {0}
- };
- static struct ctl_table_header *sysctls_root_header = NULL;
-
- if (add) {
- if (!sysctls_root_header)
- sysctls_root_header = register_sysctl_table (sysctls_root, 0);
- } else if (sysctls_root_header) {
- unregister_sysctl_table (sysctls_root_header);
- sysctls_root_header = NULL;
- }
-}
-
-
static int rng_dev_open (struct inode *inode, struct file *filp)
{
- int rc = -EINVAL;
-
if ((filp->f_mode & FMODE_READ) == 0)
- return rc;
+ return -EINVAL;
if (filp->f_mode & FMODE_WRITE)
- return rc;
+ return -EINVAL;
/* wait for device to become free */
if (filp->f_flags & O_NONBLOCK) {
@@ -639,15 +207,11 @@ static int rng_dev_open (struct inode *inode, struct file *filp)
}
if (rng_enable (1)) {
- rc = -EIO;
- goto err_out;
+ up (&rng_open_sem);
+ return -EIO;
}
return 0;
-
-err_out:
- up (&rng_open_sem);
- return rc;
}
@@ -662,12 +226,13 @@ static int rng_dev_release (struct inode *inode, struct file *filp)
static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size,
loff_t * offp)
{
+ static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED;
int have_data;
u8 data = 0;
ssize_t ret = 0;
while (size) {
- spin_lock_bh (&rng_lock);
+ spin_lock (&rng_lock);
have_data = 0;
if (rng_data_present ()) {
@@ -675,7 +240,7 @@ static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size,
have_data = 1;
}
- spin_unlock_bh (&rng_lock);
+ spin_unlock (&rng_lock);
if (have_data) {
if (put_user (data, buf++)) {
@@ -686,20 +251,35 @@ static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size,
ret++;
}
- if (current->need_resched)
- schedule ();
+ if (filp->f_flags & O_NONBLOCK)
+ return ret ? : -EAGAIN;
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
if (signal_pending (current))
return ret ? : -ERESTARTSYS;
-
- if (filp->f_flags & O_NONBLOCK)
- return ret ? : -EAGAIN;
}
return ret;
}
+static struct file_operations rng_chrdev_ops = {
+ owner: THIS_MODULE,
+ open: rng_dev_open,
+ release: rng_dev_release,
+ read: rng_dev_read,
+};
+
+
+static struct miscdevice rng_miscdev = {
+ RNG_MISCDEV_MINOR,
+ RNG_MODULE_NAME,
+ &rng_chrdev_ops,
+};
+
+
/*
* rng_init_one - look for and attempt to init a single RNG
*/
@@ -710,19 +290,19 @@ static int __init rng_init_one (struct pci_dev *dev)
DPRINTK ("ENTER\n");
- if (pci_enable_device (dev))
- return -EIO;
-
- /* XXX currently fails, investigate who has our mem region */
- if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME))
- rng_have_mem_region = 1;
+ rc = misc_register (&rng_miscdev);
+ if (rc) {
+ printk (KERN_ERR PFX "cannot register misc device\n");
+ DPRINTK ("EXIT, returning %d\n", rc);
+ goto err_out;
+ }
rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN);
if (rng_mem == NULL) {
printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
DPRINTK ("EXIT, returning -EBUSY\n");
rc = -EBUSY;
- goto err_out_free_res;
+ goto err_out_free_miscdev;
}
/* Check for Intel 82802 */
@@ -734,13 +314,6 @@ static int __init rng_init_one (struct pci_dev *dev)
goto err_out_free_map;
}
- if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY)
- rng_entropy = RNG_MAX_ENTROPY;
-
- /* init core RNG timer, but do not add it */
- init_timer (&rng_timer);
- rng_timer.function = rng_timer_tick;
-
/* turn RNG h/w off, if it's on */
rc = rng_enable (0);
if (rc) {
@@ -748,17 +321,14 @@ static int __init rng_init_one (struct pci_dev *dev)
goto err_out_free_map;
}
- /* add sysctls */
- rng_sysctl (1);
-
DPRINTK ("EXIT, returning 0\n");
return 0;
err_out_free_map:
iounmap (rng_mem);
-err_out_free_res:
- if (rng_have_mem_region)
- release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
+err_out_free_miscdev:
+ misc_deregister (&rng_miscdev);
+err_out:
return rc;
}
@@ -771,7 +341,7 @@ err_out_free_res:
* register a pci_driver, because someone else might one day
* want to register another driver on the same PCI id.
*/
-const static struct pci_device_id rng_pci_tbl[] __initdata = {
+static struct pci_device_id rng_pci_tbl[] __initdata = {
{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x8086, 0x1130, PCI_ANY_ID, PCI_ANY_ID, },
@@ -780,25 +350,8 @@ const static struct pci_device_id rng_pci_tbl[] __initdata = {
MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
-MODULE_AUTHOR("Jeff Garzik, Matt Sottek");
+MODULE_AUTHOR("Jeff Garzik, Philipp Rumpf, Matt Sottek");
MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver");
-MODULE_PARM(rng_entropy, "1i");
-MODULE_PARM_DESC(rng_entropy, "Bits of entropy to add to random pool per RNG byte (range: 0-8, default 8)");
-
-
-static struct file_operations rng_chrdev_ops = {
- owner: THIS_MODULE,
- open: rng_dev_open,
- release: rng_dev_release,
- read: rng_dev_read,
-};
-
-
-static struct miscdevice rng_miscdev = {
- RNG_MISCDEV_MINOR,
- RNG_MODULE_NAME,
- &rng_chrdev_ops,
-};
/*
@@ -826,15 +379,6 @@ match:
if (rc)
return rc;
- rc = misc_register (&rng_miscdev);
- if (rc) {
- iounmap (rng_mem);
- if (rng_have_mem_region)
- release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
- }
-
printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
rng_pdev = pdev;
@@ -851,16 +395,13 @@ static void __exit rng_cleanup (void)
{
DPRINTK ("ENTER\n");
- assert (rng_timer_enabled == 0);
assert (rng_hw_enabled == 0);
misc_deregister (&rng_miscdev);
- rng_sysctl (0);
-
iounmap (rng_mem);
- if (rng_have_mem_region)
- release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
+
+ rng_pdev = NULL;
DPRINTK ("EXIT\n");
}
@@ -868,136 +409,3 @@ static void __exit rng_cleanup (void)
module_init (rng_init);
module_exit (rng_cleanup);
-
-
-
-
-/* These are the startup tests suggested by the FIPS 140-1 spec section
-* 4.11.1 (http://csrc.nist.gov/fips/fips1401.htm)
-* The Monobit, Poker, Runs, and Long Runs tests are implemented below.
-* This test is run at periodic intervals to verify
-* data is sufficiently random. If the tests are failed the RNG module
-* will no longer submit data to the entropy pool, but the tests will
-* continue to run at the given interval. If at a later time the RNG
-* passes all tests it will be re-enabled for the next period.
-* The reason for this is that it is not unlikely that at some time
-* during normal operation one of the tests will fail. This does not
-* necessarily mean the RNG is not operating properly, it is just a
-* statistically rare event. In that case we don't want to forever
-* disable the RNG, we will just leave it disabled for the period of
-* time until the tests are rerun and passed.
-*
-* For argument sake I tested /dev/urandom with these tests and it
-* took 142,095 tries before I got a failure, and urandom isn't as
-* random as random :)
-*/
-
-static int poker[16] = { 0, }, runs[12] = { 0, };
-static int ones = 0, rlength = -1, current_bit = 0, rng_test = 0;
-
-
-/*
- * rng_fips_test_store - store 8 bits of entropy in FIPS
- * internal test data pool
- */
-static void rng_fips_test_store (int rng_data)
-{
- int j;
- static int last_bit = 0;
-
- DPRINTK ("ENTER, rng_data = %d\n", rng_data);
-
- poker[rng_data >> 4]++;
- poker[rng_data & 15]++;
-
- /* Note in the loop below rlength is always one less than the actual
- run length. This makes things easier. */
- last_bit = (rng_data & 128) >> 7;
- for (j = 7; j >= 0; j--) {
- ones += current_bit = (rng_data & 1 << j) >> j;
- if (current_bit != last_bit) {
- /* If runlength is 1-6 count it in correct bucket. 0's go in
- runs[0-5] 1's go in runs[6-11] hence the 6*current_bit below */
- if (rlength < 5) {
- runs[rlength +
- (6 * current_bit)]++;
- } else {
- runs[5 + (6 * current_bit)]++;
- }
-
- /* Check if we just failed longrun test */
- if (rlength >= 33)
- rng_test &= 8;
- rlength = 0;
- /* flip the current run type */
- last_bit = current_bit;
- } else {
- rlength++;
- }
- }
-
- DPRINTK ("EXIT\n");
-}
-
-
-/*
- * now that we have some data, run a FIPS test
- */
-static void rng_run_fips_test (void)
-{
- int j, i;
-
- DPRINTK ("ENTER\n");
-
- /* add in the last (possibly incomplete) run */
- if (rlength < 5)
- runs[rlength + (6 * current_bit)]++;
- else {
- runs[5 + (6 * current_bit)]++;
- if (rlength >= 33)
- rng_test &= 8;
- }
- /* Ones test */
- if ((ones >= 10346) || (ones <= 9654))
- rng_test &= 1;
- /* Poker calcs */
- for (i = 0, j = 0; i < 16; i++)
- j += poker[i] * poker[i];
- if ((j >= 1580457) || (j <= 1562821))
- rng_test &= 2;
- if ((runs[0] < 2267) || (runs[0] > 2733) ||
- (runs[1] < 1079) || (runs[1] > 1421) ||
- (runs[2] < 502) || (runs[2] > 748) ||
- (runs[3] < 223) || (runs[3] > 402) ||
- (runs[4] < 90) || (runs[4] > 223) ||
- (runs[5] < 90) || (runs[5] > 223) ||
- (runs[6] < 2267) || (runs[6] > 2733) ||
- (runs[7] < 1079) || (runs[7] > 1421) ||
- (runs[8] < 502) || (runs[8] > 748) ||
- (runs[9] < 223) || (runs[9] > 402) ||
- (runs[10] < 90) || (runs[10] > 223) ||
- (runs[11] < 90) || (runs[11] > 223)) {
- rng_test &= 4;
- }
-
- rng_test = !rng_test;
- DPRINTK ("FIPS test %sed\n", rng_test ? "pass" : "fail");
-
- /* enable/disable RNG with results of the tests */
- if (rng_test && !rng_trusted)
- printk (KERN_WARNING PFX "FIPS test passed, enabling RNG\n");
- else if (!rng_test && rng_trusted)
- printk (KERN_WARNING PFX "FIPS test failed, disabling RNG\n");
-
- rng_trusted = rng_test;
-
- /* finally, clear out FIPS variables for start of next run */
- memset (poker, 0, sizeof (poker));
- memset (runs, 0, sizeof (runs));
- ones = 0;
- rlength = -1;
- current_bit = 0;
- rng_test = 0;
-
- DPRINTK ("EXIT\n");
-}
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index ea4686691..884ca6637 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -213,12 +213,8 @@ static struct tty_struct *stli_txcooktty;
* at 9600 baud, 8 data bits, no parity, 1 stop bit.
*/
static struct termios stli_deftermios = {
- 0,
- 0,
- (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
- 0,
- 0,
- INIT_C_CC
+ c_cflag: (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
+ c_cc: INIT_C_CC,
};
/*
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 1c8f76630..7092d6008 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -135,8 +135,8 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-/* if you have more than 3 printers, remember to increase LP_NO */
-#define LP_NO 3
+/* if you have more than 8 printers, remember to increase LP_NO */
+#define LP_NO 8
/* ROUND_UP macro from fs/select.c */
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
@@ -344,26 +344,7 @@ static ssize_t lp_read(struct file * file, char * buf,
return -EINTR;
parport_claim_or_block (lp_table[minor].dev);
-
- for (;;) {
- retval = parport_read (port, kbuf, count);
-
- if (retval)
- break;
-
- if (file->f_flags & O_NONBLOCK)
- break;
-
- /* Wait for an interrupt. */
- interruptible_sleep_on_timeout (&lp_table[minor].waitq,
- LP_TIMEOUT_POLLED);
-
- if (signal_pending (current)) {
- retval = -EINTR;
- break;
- }
- }
-
+ retval = parport_read (port, kbuf, count);
parport_release (lp_table[minor].dev);
if (retval > 0 && copy_to_user (buf, kbuf, retval))
@@ -500,7 +481,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
if (copy_to_user((int *) arg, &LP_STAT(minor),
sizeof(struct lp_stats)))
return -EFAULT;
- if (suser())
+ if (capable(CAP_SYS_ADMIN))
memset(&LP_STAT(minor), 0,
sizeof(struct lp_stats));
break;
diff --git a/drivers/char/machzwd.c b/drivers/char/machzwd.c
new file mode 100644
index 000000000..3ee9d4c5f
--- /dev/null
+++ b/drivers/char/machzwd.c
@@ -0,0 +1,545 @@
+/*
+ * MachZ ZF-Logic Watchdog Timer driver for Linux
+ *
+ *
+ * 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.
+ *
+ * The author does NOT admit liability nor provide warranty for
+ * any of this software. This material is provided "AS-IS" in
+ * the hope that it may be useful for others.
+ *
+ * Author: Fernando Fuganti <fuganti@conectiva.com.br>
+ *
+ * Based on sbc60xxwdt.c by Jakob Oestergaard
+ *
+ *
+ * We have two timers (wd#1, wd#2) driven by a 32 KHz clock with the
+ * following periods:
+ * wd#1 - 2 seconds;
+ * wd#2 - 7.2 ms;
+ * After the expiration of wd#1, it can generate a NMI, SCI, SMI, or
+ * a system RESET and it starts wd#2 that unconditionaly will RESET
+ * the system when the counter reaches zero.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+
+/* ports */
+#define ZF_IOBASE 0x218
+#define INDEX 0x218
+#define DATA_B 0x219
+#define DATA_W 0x21A
+#define DATA_D 0x21A
+
+/* indexes */ /* size */
+#define ZFL_VERSION 0x02 /* 16 */
+#define CONTROL 0x10 /* 16 */
+#define STATUS 0x12 /* 8 */
+#define COUNTER_1 0x0C /* 16 */
+#define COUNTER_2 0x0E /* 8 */
+#define PULSE_LEN 0x0F /* 8 */
+
+/* controls */
+#define ENABLE_WD1 0x0001
+#define ENABLE_WD2 0x0002
+#define RESET_WD1 0x0010
+#define RESET_WD2 0x0020
+#define GEN_SCI 0x0100
+#define GEN_NMI 0x0200
+#define GEN_SMI 0x0400
+#define GEN_RESET 0x0800
+
+
+/* utilities */
+
+#define WD1 0
+#define WD2 1
+
+#define zf_writew(port, data) { outb(port, INDEX); outw(data, DATA_W); }
+#define zf_writeb(port, data) { outb(port, INDEX); outb(data, DATA_B); }
+#define zf_get_ZFL_version() zf_readw(ZFL_VERSION)
+
+
+static unsigned short zf_readw(unsigned char port)
+{
+ outb(port, INDEX);
+ return inw(DATA_W);
+}
+
+static unsigned short zf_readb(unsigned char port)
+{
+ outb(port, INDEX);
+ return inb(DATA_B);
+}
+
+
+MODULE_AUTHOR("Fernando Fuganti <fuganti@conectiva.com.br>");
+MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver");
+MODULE_PARM(action, "i");
+MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI");
+
+#define PFX "machzwd"
+
+static struct watchdog_info zf_info = {
+ options: WDIOF_KEEPALIVEPING,
+ firmware_version: 1,
+ identity: "ZF-Logic watchdog"
+};
+
+
+/*
+ * action refers to action taken when watchdog resets
+ * 0 = GEN_RESET
+ * 1 = GEN_SMI
+ * 2 = GEN_NMI
+ * 3 = GEN_SCI
+ * defaults to GEN_RESET (0)
+ */
+static int action = 0;
+static int zf_action = GEN_RESET;
+static int zf_is_open = 0;
+static int zf_expect_close = 0;
+static spinlock_t zf_lock;
+static struct timer_list zf_timer;
+static unsigned long next_heartbeat = 0;
+
+
+/* timeout for user land heart beat (10 seconds) */
+#define ZF_USER_TIMEO (HZ*10)
+
+/* timeout for hardware watchdog (~500ms) */
+#define ZF_HW_TIMEO (HZ/2)
+
+/* number of ticks on WD#1 (driven by a 32KHz clock, 2s) */
+#define ZF_CTIMEOUT 0xffff
+
+#ifndef ZF_DEBUG
+# define dprintk(format, args...)
+#else
+# define dprintk(format, args...) printk(KERN_DEBUG PFX ":" __FUNCTION__ ":%d: " format, __LINE__ , ## args)
+#endif
+
+
+/* STATUS register functions */
+
+static inline unsigned char zf_get_status(void)
+{
+ return zf_readb(STATUS);
+}
+
+static inline void zf_set_status(unsigned char new)
+{
+ zf_writeb(STATUS, new);
+}
+
+
+/* CONTROL register functions */
+
+static inline unsigned short zf_get_control(void)
+{
+ return zf_readw(CONTROL);
+}
+
+static inline void zf_set_control(unsigned short new)
+{
+ zf_writew(CONTROL, new);
+}
+
+
+/* WD#? counter functions */
+/*
+ * Just get current counter value
+ */
+
+inline unsigned short zf_get_timer(unsigned char n)
+{
+ switch(n){
+ case WD1:
+ return zf_readw(COUNTER_1);
+ case WD2:
+ return zf_readb(COUNTER_2);
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Just set counter value
+ */
+
+static inline void zf_set_timer(unsigned short new, unsigned char n)
+{
+ switch(n){
+ case WD1:
+ zf_writew(COUNTER_1, new);
+ case WD2:
+ zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
+ default:
+ return;
+ }
+}
+
+/*
+ * stop hardware timer
+ */
+static void zf_timer_off(void)
+{
+ unsigned int ctrl_reg = 0;
+
+ /* stop internal ping */
+ del_timer(&zf_timer);
+
+ /* stop watchdog timer */
+ ctrl_reg = zf_get_control();
+ ctrl_reg |= (ENABLE_WD1|ENABLE_WD2); /* disable wd1 and wd2 */
+ ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2);
+ zf_set_control(ctrl_reg);
+
+ printk(PFX ": Watchdog timer is now disabled\n");
+}
+
+
+/*
+ * start hardware timer
+ */
+static void zf_timer_on(void)
+{
+ unsigned int ctrl_reg = 0;
+
+ zf_writeb(PULSE_LEN, 0xff);
+
+ zf_set_timer(ZF_CTIMEOUT, WD1);
+
+ /* user land ping */
+ next_heartbeat = jiffies + ZF_USER_TIMEO;
+
+ /* start the timer for internal ping */
+ zf_timer.expires = jiffies + ZF_HW_TIMEO;
+
+ add_timer(&zf_timer);
+
+ /* start watchdog timer */
+ ctrl_reg = zf_get_control();
+ ctrl_reg |= (ENABLE_WD1|zf_action);
+ zf_set_control(ctrl_reg);
+
+ printk(PFX ": Watchdog timer is now enabled\n");
+}
+
+
+static void zf_ping(unsigned long data)
+{
+ unsigned int ctrl_reg = 0;
+
+ zf_writeb(COUNTER_2, 0xff);
+
+ if(time_before(jiffies, next_heartbeat)){
+
+ dprintk("time_before: %ld\n", next_heartbeat - jiffies);
+
+ /*
+ * reset event is activated by transition from 0 to 1 on
+ * RESET_WD1 bit and we assume that it is already zero...
+ */
+ ctrl_reg = zf_get_control();
+ ctrl_reg |= RESET_WD1;
+ zf_set_control(ctrl_reg);
+
+ /* ...and nothing changes until here */
+ ctrl_reg &= ~(RESET_WD1);
+ zf_set_control(ctrl_reg);
+
+ zf_timer.expires = jiffies + ZF_HW_TIMEO;
+ add_timer(&zf_timer);
+ }else{
+ printk(PFX ": I will reset your machine\n");
+ }
+}
+
+static ssize_t zf_write(struct file *file, const char *buf, size_t count,
+ loff_t *ppos)
+{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ /* See if we got the magic character */
+ if(count){
+
+/*
+ * no need to check for close confirmation
+ * no way to disable watchdog ;)
+ */
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ size_t ofs;
+
+ /*
+ * note: just in case someone wrote the magic character
+ * five months ago...
+ */
+ zf_expect_close = 0;
+
+ /* now scan */
+ for(ofs = 0; ofs != count; ofs++){
+ if(buf[ofs] == 'V'){
+ zf_expect_close = 1;
+ dprintk("zf_expect_close 1\n");
+ }
+ }
+#endif
+ /*
+ * Well, anyhow someone wrote to us,
+ * we should return that favour
+ */
+ next_heartbeat = jiffies + ZF_USER_TIMEO;
+ dprintk("user ping at %ld\n", jiffies);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static ssize_t zf_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+
+
+static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ switch(cmd){
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg,
+ &zf_info, sizeof(zf_info));
+ if(ret)
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ ret = copy_to_user((int *)arg, &zf_is_open,
+ sizeof(int));
+ if(ret)
+ return -EFAULT;
+ break;
+
+ case WDIOC_KEEPALIVE:
+ zf_ping(0);
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int zf_open(struct inode *inode, struct file *file)
+{
+ switch(MINOR(inode->i_rdev)){
+ case WATCHDOG_MINOR:
+ spin_lock(&zf_lock);
+ if(zf_is_open){
+ spin_unlock(&zf_lock);
+ return -EBUSY;
+ }
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+ MOD_INC_USE_COUNT;
+#endif
+ zf_is_open = 1;
+
+ spin_unlock(&zf_lock);
+
+ zf_timer_on();
+
+ return 0;
+ default:
+ return -ENODEV;
+ }
+}
+
+static int zf_close(struct inode *inode, struct file *file)
+{
+ if(MINOR(inode->i_rdev) == WATCHDOG_MINOR){
+
+ if(zf_expect_close){
+ zf_timer_off();
+ } else {
+ del_timer(&zf_timer);
+ printk(PFX ": device file closed unexpectedly. Will not stop the WDT!\n");
+ }
+
+ spin_lock(&zf_lock);
+ zf_is_open = 0;
+ spin_unlock(&zf_lock);
+
+ zf_expect_close = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Notifier for system down
+ */
+
+static int zf_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if(code == SYS_DOWN || code == SYS_HALT){
+ zf_timer_off();
+ }
+
+ return NOTIFY_DONE;
+}
+
+
+
+
+static struct file_operations zf_fops = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,34)
+ owner: THIS_MODULE,
+#endif
+ read: zf_read,
+ write: zf_write,
+ ioctl: zf_ioctl,
+ open: zf_open,
+ release: zf_close,
+};
+
+static struct miscdevice zf_miscdev = {
+ WATCHDOG_MINOR,
+ "watchdog",
+ &zf_fops
+};
+
+
+/*
+ * The device needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+static struct notifier_block zf_notifier = {
+ zf_notify_sys,
+ NULL,
+ 0
+};
+
+static void __init zf_show_action(int act)
+{
+ char *str[] = { "RESET", "SMI", "NMI", "SCI" };
+
+ printk(PFX ": Watchdog using action = %s\n", str[act]);
+}
+
+int __init zf_init(void)
+{
+ int ret;
+
+ printk(PFX ": MachZ ZF-Logic Watchdog driver initializing.\n");
+
+ ret = zf_get_ZFL_version();
+ printk("%#x\n", ret);
+ if((!ret) || (ret != 0xffff)){
+ printk(PFX ": no ZF-Logic found\n");
+ return -ENODEV;
+ }
+
+ if((action <= 3) && (action >= 0)){
+ zf_action = zf_action>>action;
+ } else
+ action = 0;
+
+ zf_show_action(action);
+
+ spin_lock_init(&zf_lock);
+
+ ret = misc_register(&zf_miscdev);
+ if (ret){
+ printk(KERN_ERR "can't misc_register on minor=%d\n",
+ WATCHDOG_MINOR);
+ goto out;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3)
+ if(check_region(ZF_IOBASE, 3)){
+#else
+ if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
+#endif
+
+ printk(KERN_ERR "cannot reserve I/O ports at %d\n",
+ ZF_IOBASE);
+ ret = -EBUSY;
+ goto no_region;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3)
+ request_region(ZF_IOBASE, 3, "MachZ ZFL WDT");
+#define __exit
+#endif
+
+ ret = register_reboot_notifier(&zf_notifier);
+ if(ret){
+ printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
+ ret);
+ goto no_reboot;
+ }
+
+ zf_set_status(0);
+ zf_set_control(0);
+
+ /* this is the timer that will do the hard work */
+ init_timer(&zf_timer);
+ zf_timer.function = zf_ping;
+ zf_timer.data = 0;
+
+ return 0;
+
+no_reboot:
+ release_region(ZF_IOBASE, 3);
+no_region:
+ misc_deregister(&zf_miscdev);
+out:
+ return ret;
+}
+
+
+void __exit zf_exit(void)
+{
+ zf_timer_off();
+
+ misc_deregister(&zf_miscdev);
+ unregister_reboot_notifier(&zf_notifier);
+ release_region(ZF_IOBASE, 3);
+}
+
+module_init(zf_init);
+module_exit(zf_exit);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index d0c5eefe3..11bd66115 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -353,7 +353,7 @@ static inline size_t read_zero_pagealigned(char * buf, size_t size)
mm = current->mm;
/* Oops, this was forgotten before. -ben */
- down(&mm->mmap_sem);
+ down_read(&mm->mmap_sem);
/* For private mappings, just map in zero pages. */
for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
@@ -367,10 +367,8 @@ static inline size_t read_zero_pagealigned(char * buf, size_t size)
if (count > size)
count = size;
- flush_cache_range(mm, addr, addr + count);
zap_page_range(mm, addr, count);
zeromap_page_range(addr, count, PAGE_COPY);
- flush_tlb_range(mm, addr, addr + count);
size -= count;
buf += count;
@@ -379,7 +377,7 @@ static inline size_t read_zero_pagealigned(char * buf, size_t size)
goto out_up;
}
- up(&mm->mmap_sem);
+ up_read(&mm->mmap_sem);
/* The shared case is hard. Let's do the conventional zeroing. */
do {
@@ -394,7 +392,7 @@ static inline size_t read_zero_pagealigned(char * buf, size_t size)
return size;
out_up:
- up(&mm->mmap_sem);
+ up_read(&mm->mmap_sem);
return size;
}
@@ -644,6 +642,9 @@ int __init chr_dev_init(void)
#ifdef CONFIG_FTAPE
ftape_init();
#endif
+#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
+ tapechar_init();
+#endif
#if defined(CONFIG_ADB)
adbdev_init();
#endif
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 8dc9ef350..89931b06d 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -75,7 +75,6 @@ extern int rtc_MK48T08_init(void);
extern int ds1286_init(void);
extern int dsp56k_init(void);
extern int radio_init(void);
-extern int pc110pad_init(void);
extern int pmu_device_init(void);
extern int qpmouse_init(void);
extern int tosh_init(void);
@@ -249,9 +248,6 @@ int __init misc_init(void)
#if defined CONFIG_82C710_MOUSE
qpmouse_init();
#endif
-#ifdef CONFIG_PC110_PAD
- pc110pad_init();
-#endif
#ifdef CONFIG_MVME16x
rtc_MK48T08_init();
#endif
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index c0eeab2f0..e0cb1c74e 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -120,7 +120,7 @@
#define CI104J_ASIC_ID 5
enum {
- MXSER_BOARD_C168_ISA = 0,
+ MXSER_BOARD_C168_ISA = 1,
MXSER_BOARD_C104_ISA,
MXSER_BOARD_CI104J,
MXSER_BOARD_C168_PCI,
@@ -617,16 +617,18 @@ int mxser_init(void)
pdev = pci_find_device(mxser_pcibrds[b].vendor_id,
mxser_pcibrds[b].device_id, pdev);
if (!pdev)
- break;
+ {
+ b++;
+ continue;
+ }
if (pci_enable_device(pdev))
continue;
- b++;
hwconf.pdev = pdev;
printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
mxser_brdname[mxser_pcibrds[b].board_type - 1],
pdev->bus->number, PCI_SLOT(pdev->devfn >> 3));
if (m >= MXSER_BOARDS) {
- printk("Too many Smartio family boards find (maximum %d),board not configured\n", MXSER_BOARDS);
+ printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS);
} else {
retval = mxser_get_PCI_conf(pdev,
mxser_pcibrds[b].board_type, &hwconf);
@@ -1457,7 +1459,9 @@ static inline void mxser_transmit_chars(struct mxser_struct *info)
if (info->xmit_cnt < WAKEUP_CHARS) {
set_bit(MXSER_EVENT_TXLOW, &info->event);
- schedule_task(&info->tqueue);
+ MOD_INC_USE_COUNT;
+ if (schedule_task(&info->tqueue) == 0)
+ MOD_DEC_USE_COUNT;
}
if (info->xmit_cnt <= 0) {
info->IER &= ~UART_IER_THRI;
@@ -1486,8 +1490,9 @@ static inline void mxser_check_modem_status(struct mxser_struct *info,
else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
(info->flags & ASYNC_CALLOUT_NOHUP)))
set_bit(MXSER_EVENT_HANGUP, &info->event);
- schedule_task(&info->tqueue);
-
+ MOD_INC_USE_COUNT;
+ if (schedule_task(&info->tqueue) == 0)
+ MOD_DEC_USE_COUNT;
}
if (info->flags & ASYNC_CTS_FLOW) {
if (info->tty->hw_stopped) {
@@ -1671,7 +1676,7 @@ static int mxser_startup(struct mxser_struct *info)
*/
if (inb(info->base + UART_LSR) == 0xff) {
restore_flags(flags);
- if (suser()) {
+ if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
return (0);
@@ -2188,8 +2193,7 @@ static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int *value)
status = inb(info->base + UART_LSR);
restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- put_user(result, value);
- return (0);
+ return put_user(result, value);
}
/*
@@ -2229,8 +2233,7 @@ static int mxser_get_modem_info(struct mxser_struct *info,
((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
- put_user(result, value);
- return (0);
+ return put_user(result, value);
}
static int mxser_set_modem_info(struct mxser_struct *info, unsigned int cmd,
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index 35e4e1328..8ad17d5b7 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -908,6 +908,8 @@ static int open_aux(struct inode * inode, struct file * file)
controller. */
aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
+
+ mdelay(2); /* Ensure we follow the kbc access delay rules.. */
send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */
diff --git a/drivers/char/pcmcia/Config.in b/drivers/char/pcmcia/Config.in
index 8baf1932e..9226893ed 100644
--- a/drivers/char/pcmcia/Config.in
+++ b/drivers/char/pcmcia/Config.in
@@ -2,29 +2,13 @@
# PCMCIA character device configuration
#
-if [ "$CONFIG_SERIAL" = "n" ]; then
- define_tristate CONFIG_PCMCIA_SERIAL n
-else
- if [ "$CONFIG_SERIAL" = "m" -o "$CONFIG_PCMCIA" = "m" ]; then
- define_tristate CONFIG_PCMCIA_SERIAL m
- else
- define_tristate CONFIG_PCMCIA_SERIAL y
- fi
-fi
-
-if [ "$CONFIG_PCMCIA_SERIAL" != "n" ]; then
- mainmenu_option next_comment
- comment 'PCMCIA character device support'
+mainmenu_option next_comment
+comment 'PCMCIA character devices'
- dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA_SERIAL
- if [ "$CONFIG_CARDBUS" = "y" ]; then
- dep_tristate 'CardBus serial device support' CONFIG_PCMCIA_SERIAL_CB $CONFIG_PCMCIA_SERIAL
- fi
+dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_SERIAL
+if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" ]; then
+ define_bool CONFIG_PCMCIA_CHRDEV y
+fi
- if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" -o \
- "$CONFIG_PCMCIA_SERIAL_CB" = "y" ]; then
- define_bool CONFIG_PCMCIA_CHRDEV y
- fi
+endmenu
- endmenu
-fi
diff --git a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile
index 897469fec..dd6e68397 100644
--- a/drivers/char/pcmcia/Makefile
+++ b/drivers/char/pcmcia/Makefile
@@ -16,6 +16,5 @@ obj-n :=
obj- :=
obj-$(CONFIG_PCMCIA_SERIAL_CS) += serial_cs.o
-obj-$(CONFIG_PCMCIA_SERIAL_CB) += serial_cb.o
include $(TOPDIR)/Rules.make
diff --git a/drivers/char/pcmcia/serial_cb.c b/drivers/char/pcmcia/serial_cb.c
deleted file mode 100644
index 2dadac4ad..000000000
--- a/drivers/char/pcmcia/serial_cb.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*======================================================================
-
- A driver for CardBus serial devices
-
- serial_cb.c 1.20 2000/08/07 19:02:03
-
- Copyright 1998, 1999 by Donald Becker and David Hinds
-
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
- All other rights reserved.
-
- This driver is an activator for CardBus serial cards, as
- found on multifunction (e.g. Ethernet and Modem) CardBus cards.
-
- Donald Becker may be reached as becker@CESDIS.edu, or C/O
- USRA Center of Excellence in Space Data and Information Sciences
- Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
- David Hinds may be reached at dahinds@users.sourceforge.net
-
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/major.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include <pcmcia/driver_ops.h>
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"serial_cb.c 1.20 2000/08/07 19:02:03 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-/*======================================================================
-
- Card-specific configuration hacks
-
-======================================================================*/
-
-static void device_setup(struct pci_dev *pdev, u_int ioaddr)
-{
- u_short a, b;
-
- a = pdev->subsystem_vendor;
- b = pdev->subsystem_device;
- if (((a == 0x13a2) && (b == 0x8007)) ||
- ((a == 0x1420) && (b == 0x8003))) {
- /* Ositech, Psion 83c175-based cards */
- DEBUG(0, " 83c175 NVCTL_m = 0x%4.4x.\n", inl(ioaddr+0x80));
- outl(0x4C00, ioaddr + 0x80);
- outl(0x4C80, ioaddr + 0x80);
- }
- DEBUG(0, " modem registers are %2.2x %2.2x %2.2x "
- "%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x.\n",
- inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
- inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5),
- inb(ioaddr + 6), inb(ioaddr + 7), inb(ioaddr + 8));
-}
-
-/*======================================================================
-
- serial_attach() creates a serial device "instance" and registers
- it with the kernel serial driver, and serial_detach() unregisters
- an instance.
-
-======================================================================*/
-
-static dev_node_t *serial_attach(dev_locator_t *loc)
-{
- u_int io;
- u_char irq;
- int line;
- struct serial_struct serial;
- struct pci_dev *pdev;
- dev_node_t *node;
-
- MOD_INC_USE_COUNT;
-
- if (loc->bus != LOC_PCI) goto err_out;
- pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
- if (!pdev) goto err_out;
- if (pci_enable_device(pdev)) goto err_out;
-
- printk(KERN_INFO "serial_attach(bus %d, fn %d)\n", pdev->bus->number, pdev->devfn);
- io = pci_resource_start (pdev, 0);
- irq = pdev->irq;
- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
- printk(KERN_NOTICE "serial_cb: PCI base address 0 is not IO\n");
- goto err_out;
- }
- device_setup(pdev, io);
- memset(&serial, 0, sizeof(serial));
- serial.port = io; serial.irq = irq;
- serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
-
- /* Some devices seem to need extra time */
- __set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/50);
-
- line = register_serial(&serial);
- if (line < 0) {
- printk(KERN_NOTICE "serial_cb: register_serial() at 0x%04x, "
- "irq %d failed\n", serial.port, serial.irq);
- goto err_out;
- }
-
- node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
- if (!node)
- goto err_out_unregister;
- sprintf(node->dev_name, "ttyS%d", line);
- node->major = TTY_MAJOR; node->minor = 0x40 + line;
- node->next = NULL;
- return node;
-
-err_out_unregister:
- unregister_serial(line);
-err_out:
- MOD_DEC_USE_COUNT;
- return NULL;
-}
-
-static void serial_detach(dev_node_t *node)
-{
- DEBUG(0, "serial_detach(ttyS%02d)\n", node->minor - 0x40);
- unregister_serial(node->minor - 0x40);
- kfree(node);
- MOD_DEC_USE_COUNT;
-}
-
-/*====================================================================*/
-
-struct driver_operations serial_ops = {
- "serial_cb", serial_attach, NULL, NULL, serial_detach
-};
-
-static int __init init_serial_cb(void)
-{
- DEBUG(0, "%s\n", version);
- register_driver(&serial_ops);
- return 0;
-}
-
-static void __exit exit_serial_cb(void)
-{
- DEBUG(0, "serial_cb: unloading\n");
- unregister_driver(&serial_ops);
-}
-
-module_init(init_serial_cb);
-module_exit(exit_serial_cb);
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 8c950bf54..ae2b6ddee 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -46,21 +46,6 @@
#define ENABLE_PCI
#endif
-#define NEW_MODULES
-#ifdef LOCAL_ROCKET_H /* We're building standalone */
-#define MODULE
-#endif
-
-#if defined(NEW_MODULES) && defined(LOCAL_ROCKET_H)
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-#else /* !NEW_MODULES */
-#ifdef MODVERSIONS
-#define MODULE
-#endif
-#endif /* NEW_MODULES */
-
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/major.h>
@@ -138,13 +123,6 @@
#define _INLINE_ inline
-#ifndef NEW_MODULES
-/*
- * NB. we must include the kernel idenfication string in to install the module.
- */
-/*static*/ char kernel_version[] = UTS_RELEASE;
-#endif
-
static struct r_port *rp_table[MAX_RP_PORTS];
static struct tty_struct *rocket_table[MAX_RP_PORTS];
static unsigned int xmit_flags[NUM_BOARDS];
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 24e8b8e6a..b55873eb1 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -54,16 +54,18 @@
* 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
- * 10/00: add in optional hardware flow control for serial console.
- * Kanoj Sarcar <kanoj@sgi.com>
+ * 10/00: add in optional software flow control for serial console.
+ * Kanoj Sarcar <kanoj@sgi.com> (Modified by Theodore Ts'o)
*
- * This module exports the following rs232 io functions:
- *
- * int rs_init(void);
+ * 10/00: Added suport for MIPS Atlas board.
+ * 11/00: Hooks for serial kernel debug port support added.
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard,
+ * carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*/
-static char *serial_version = "5.02";
-static char *serial_revdate = "2000-08-09";
+static char *serial_version = "5.05";
+static char *serial_revdate = "2000-12-13";
/*
* Serial driver configuration section. Here are the various options:
@@ -89,16 +91,6 @@ static char *serial_revdate = "2000-08-09";
* Check the magic number for the async_structure where
* ever possible.
*/
-/**************************************************************************
- * 23 Oct, 2000.
- * Added suport for MIPS Atlas board.
- *
- * 23 Nov, 2000.
- * Hooks for serial kernel debug port support added.
- *
- * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
- *************************************************************************/
#include <linux/config.h>
#include <linux/version.h>
@@ -201,7 +193,7 @@ static char *serial_revdate = "2000-08-09";
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#if (LINUX_VERSION_CODE >= 131343)
#include <linux/init.h>
#endif
@@ -335,7 +327,6 @@ static struct serial_state rs_table[RS_TABLE_SIZE] = {
#define NR_PCI_BOARDS 8
static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
-static int serial_pci_board_idx;
#ifndef IS_PCI_REGION_IOPORT
#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
@@ -592,8 +583,8 @@ static _INLINE_ void receive_chars(struct async_struct *info,
{
struct tty_struct *tty = info->tty;
unsigned char ch;
- int ignored = 0;
struct async_icount *icount;
+ int max_count = 256;
icount = &info->state->icount;
do {
@@ -640,15 +631,8 @@ static _INLINE_ void receive_chars(struct async_struct *info,
icount->overrun++;
/*
- * Now check to see if character should be
- * ignored, and mask off conditions which
- * should be ignored.
+ * Mask off conditions which should be ignored.
*/
- if (*status & info->ignore_status_mask) {
- if (++ignored > 100)
- break;
- goto ignore_char;
- }
*status &= info->read_status_mask;
#ifdef CONFIG_SERIAL_CONSOLE
@@ -667,19 +651,6 @@ static _INLINE_ void receive_chars(struct async_struct *info,
*tty->flip.flag_buf_ptr = TTY_PARITY;
else if (*status & UART_LSR_FE)
*tty->flip.flag_buf_ptr = TTY_FRAME;
- if (*status & UART_LSR_OE) {
- /*
- * Overrun is special, since it's
- * reported immediately, and doesn't
- * affect the current character
- */
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- goto ignore_char;
- }
}
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
if (break_pressed && info->line == sercons.index) {
@@ -692,16 +663,30 @@ static _INLINE_ void receive_chars(struct async_struct *info,
break_pressed = 0;
}
#endif
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ if ((*status & info->ignore_status_mask) == 0) {
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ }
+ if ((*status & UART_LSR_OE) &&
+ (tty->flip.count < TTY_FLIPBUF_SIZE)) {
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character
+ */
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ tty->flip.count++;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ }
ignore_char:
*status = serial_inp(info, UART_LSR);
- } while (*status & UART_LSR_DR);
+ } while ((*status & UART_LSR_DR) && (max_count-- > 0));
#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
tty_flip_buffer_push(tty);
#else
- queue_task(&tty->flip.tqueue, &tq_timer);
+ queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
#endif
}
@@ -855,6 +840,9 @@ static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
end_mark = info;
goto next;
}
+#ifdef SERIAL_DEBUG_INTR
+ printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
end_mark = 0;
info->last_active = jiffies;
@@ -938,6 +926,9 @@ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
#endif
break;
}
+#ifdef SERIAL_DEBUG_INTR
+ printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
info->last_active = jiffies;
#ifdef CONFIG_SERIAL_MULTIPORT
@@ -1338,7 +1329,7 @@ static int startup(struct async_struct * info)
*/
if (!(info->flags & ASYNC_BUGGY_UART) &&
(serial_inp(info, UART_LSR) == 0xff)) {
- printk("LSR safety check engaged!\n");
+ printk("ttyS%d: LSR safety check engaged!\n", state->line);
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1582,7 +1573,10 @@ static void shutdown(struct async_struct * info)
/* Arrange to enter sleep mode */
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, UART_EFR_ECB);
+ serial_outp(info, UART_LCR, 0);
serial_outp(info, UART_IER, UART_IERX_SLEEP);
+ serial_outp(info, UART_LCR, 0xBF);
+ serial_outp(info, UART_EFR, 0);
serial_outp(info, UART_LCR, 0);
}
if (info->state->type == PORT_16750) {
@@ -2934,7 +2928,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
- set_current_state(TASK_RUNNING);
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
@@ -3282,6 +3275,10 @@ static inline int line_info(char *buf, struct serial_state *state)
info->magic = SERIAL_MAGIC;
info->port = state->port;
info->flags = state->flags;
+ info->hub6 = state->hub6;
+ info->io_type = state->io_type;
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
info->quot = 0;
info->tty = 0;
}
@@ -3837,7 +3834,7 @@ static struct symbol_table serial_syms = {
#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
-static void __init printk_pnp_dev_id(unsigned short vendor,
+static void __devinit printk_pnp_dev_id(unsigned short vendor,
unsigned short device)
{
printk("%c%c%c%x%x%x%x",
@@ -3929,7 +3926,7 @@ static _INLINE_ int get_pci_irq(struct pci_dev *dev,
/*
* Common enabler code shared by both PCI and ISAPNP probes
*/
-static void __init start_pci_pnp_board(struct pci_dev *dev,
+static void __devinit start_pci_pnp_board(struct pci_dev *dev,
struct pci_board *board)
{
int k, line;
@@ -3961,19 +3958,19 @@ static void __init start_pci_pnp_board(struct pci_dev *dev,
if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
return;
-#ifdef MODULE
/*
* Register the serial board in the array if we need to
- * shutdown the board on a module unload.
+ * shutdown the board on a module unload or card removal
*/
if (DEACTIVATE_FUNC(dev) || board->init_fn) {
- if (serial_pci_board_idx >= NR_PCI_BOARDS)
+ for (k=0; k < NR_PCI_BOARDS; k++)
+ if (serial_pci_board[k].dev == 0)
+ break;
+ if (k >= NR_PCI_BOARDS)
return;
- serial_pci_board[serial_pci_board_idx].board = *board;
- serial_pci_board[serial_pci_board_idx].dev = dev;
- serial_pci_board_idx++;
+ serial_pci_board[k].board = *board;
+ serial_pci_board[k].dev = dev;
}
-#endif
base_baud = board->base_baud;
if (!base_baud)
@@ -3993,6 +3990,7 @@ static void __init start_pci_pnp_board(struct pci_dev *dev,
if (line < 0)
break;
rs_table[line].baud_base = base_baud;
+ rs_table[line].dev = dev;
}
}
#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
@@ -4006,7 +4004,7 @@ static void __init start_pci_pnp_board(struct pci_dev *dev,
*/
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4073,7 +4071,7 @@ pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4105,7 +4103,7 @@ pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4129,7 +4127,7 @@ pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
/* Added for EKF Intel i960 serial boards */
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_inteli960ni_fn(struct pci_dev *dev,
struct pci_board *board,
@@ -4190,7 +4188,7 @@ static struct timedia_struct {
static int
#ifndef MODULE
-__init
+__devinit
#endif
pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
@@ -4592,9 +4590,11 @@ static struct pci_board pci_boards[] __devinitdata = {
{ PCI_VENDOR_ID_ROCKWELL, 0x1004,
0x1048, 0x1500,
SPCI_FL_BASE1, 1, 115200 },
+#if 0
{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
0xFF00, 0, SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,
1, 458333, 0, 0, 0, 0x20178 },
+#endif
#if CONFIG_DDB5074
/*
* NEC Vrc-5074 (Nile 4) builtin UART.
@@ -4605,6 +4605,12 @@ static struct pci_board pci_boards[] __devinitdata = {
SPCI_FL_BASE0, 1, 520833,
64, 3, NULL, 0x300 },
#endif
+#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */
+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE3, 8, 115200,
+ 8 },
+#endif
/* Generic serial board */
{ 0, 0,
0, 0,
@@ -4654,6 +4660,93 @@ static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev,
return 1;
}
+static int __devinit serial_init_one(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ struct pci_board *board, tmp;
+
+ for (board = pci_boards; board->vendor; board++) {
+ if (board->vendor != (unsigned short) PCI_ANY_ID &&
+ dev->vendor != board->vendor)
+ continue;
+ if (board->device != (unsigned short) PCI_ANY_ID &&
+ dev->device != board->device)
+ continue;
+ if (board->subvendor != (unsigned short) PCI_ANY_ID &&
+ pci_get_subvendor(dev) != board->subvendor)
+ continue;
+ if (board->subdevice != (unsigned short) PCI_ANY_ID &&
+ pci_get_subdevice(dev) != board->subdevice)
+ continue;
+ break;
+ }
+
+ if (board->vendor == 0 && serial_pci_guess_board(dev, board))
+ return -ENODEV;
+ else if (serial_pci_guess_board(dev, &tmp) == 0) {
+ printk(KERN_INFO "Redundant entry in serial pci_table. "
+ "Please send the output of\n"
+ "lspci -vv, this message (%d,%d,%d,%d)\n"
+ "and the manufacturer and name of "
+ "serial board or modem board\n"
+ "to serial-pci-info@lists.sourceforge.net.\n",
+ dev->vendor, dev->device,
+ pci_get_subvendor(dev), pci_get_subdevice(dev));
+ }
+
+ start_pci_pnp_board(dev, board);
+
+ return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+ int i;
+
+ /*
+ * Iterate through all of the ports finding those that belong
+ * to this PCI device.
+ */
+ for(i = 0; i < NR_PORTS; i++) {
+ if (rs_table[i].dev != dev)
+ continue;
+ unregister_serial(i);
+ rs_table[i].dev = 0;
+ }
+ /*
+ * Now execute any board-specific shutdown procedure
+ */
+ for (i=0; i < NR_PCI_BOARDS; i++) {
+ struct pci_board_inst *brd = &serial_pci_board[i];
+
+ if (serial_pci_board[i].dev != dev)
+ continue;
+ if (brd->board.init_fn)
+ (brd->board.init_fn)(brd->dev, &brd->board, 0);
+ if (DEACTIVATE_FUNC(brd->dev))
+ (DEACTIVATE_FUNC(brd->dev))(brd->dev);
+ serial_pci_board[i].dev = 0;
+ }
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
+
+static struct pci_driver serial_pci_driver = {
+ name: "serial",
+ probe: serial_init_one,
+ remove: serial_remove_one,
+ id_table: serial_pci_tbl,
+// id_table: NULL,
+};
/*
@@ -4663,38 +4756,19 @@ static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev,
* Accept a maximum of eight boards
*
*/
-static void __init probe_serial_pci(void)
+static void __devinit probe_serial_pci(void)
{
- struct pci_dev *dev = NULL;
- struct pci_board *board;
-
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Entered probe_serial_pci()\n");
#endif
-
- pci_for_each_dev(dev) {
- for (board = pci_boards; board->vendor; board++) {
- if (board->vendor != (unsigned short) PCI_ANY_ID &&
- dev->vendor != board->vendor)
- continue;
- if (board->device != (unsigned short) PCI_ANY_ID &&
- dev->device != board->device)
- continue;
- if (board->subvendor != (unsigned short) PCI_ANY_ID &&
- pci_get_subvendor(dev) != board->subvendor)
- continue;
- if (board->subdevice != (unsigned short) PCI_ANY_ID &&
- pci_get_subdevice(dev) != board->subdevice)
- continue;
- break;
- }
-
- if (board->vendor == 0 && serial_pci_guess_board(dev, board))
- continue;
-
- start_pci_pnp_board(dev, board);
- }
-
+
+ /* Register call PCI serial devices. Null out
+ * the driver name upon failure, as a signal
+ * not to attempt to unregister the driver later
+ */
+ if (pci_module_init (&serial_pci_driver) != 0)
+ serial_pci_driver.name[0] = 0;
+
#ifdef SERIAL_DEBUG_PCI
printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
#endif
@@ -4710,7 +4784,7 @@ struct pnp_board {
unsigned short device;
};
-static struct pnp_board pnp_devices[] __initdata = {
+static struct pnp_board pnp_devices[] __devinitdata = {
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
@@ -5000,14 +5074,14 @@ static void inline avoid_irq_share(struct pci_dev *dev)
irq->map = map;
}
-static char *modem_names[] __initdata = {
+static char *modem_names[] __devinitdata = {
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
"56K", "56k", "K56", "33.6", "28.8", "14.4",
"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
"33600", "28800", "14400", "V.90", "V.34", "V.32", 0
};
-static int __init check_name(char *name)
+static int __devinit check_name(char *name)
{
char **tmp = modem_names;
@@ -5069,7 +5143,7 @@ static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev,
return 1;
}
-static void __init probe_serial_pnp(void)
+static void __devinit probe_serial_pnp(void)
{
struct pci_dev *dev = NULL;
struct pnp_board *pnp_board;
@@ -5280,7 +5354,7 @@ static int __init rs_init(void)
}
/*
- * This is for use by architectures that know their serial port
+ * This is for use by architectures that know their serial console
* attributes only at run time. Not to be invoked after rs_init().
*/
int __init early_serial_setup(struct serial_struct *req)
@@ -5346,6 +5420,14 @@ int register_serial(struct serial_struct *req)
(rs_table[i].iomem_base == req->iomem_base))
break;
}
+#ifdef __i386__
+ if (i == NR_PORTS) {
+ for (i = 4; i < NR_PORTS; i++)
+ if ((rs_table[i].type == PORT_UNKNOWN) &&
+ (rs_table[i].count == 0))
+ break;
+ }
+#endif
if (i == NR_PORTS) {
for (i = 0; i < NR_PORTS; i++)
if ((rs_table[i].type == PORT_UNKNOWN) &&
@@ -5469,12 +5551,13 @@ static void __exit rs_fini(void)
#endif
}
#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
- for (i=0; i < serial_pci_board_idx; i++) {
+ for (i=0; i < NR_PCI_BOARDS; i++) {
struct pci_board_inst *brd = &serial_pci_board[i];
-
+
+ if (serial_pci_board[i].dev == 0)
+ continue;
if (brd->board.init_fn)
(brd->board.init_fn)(brd->dev, &brd->board, 0);
-
if (DEACTIVATE_FUNC(brd->dev))
(DEACTIVATE_FUNC(brd->dev))(brd->dev);
}
@@ -5484,6 +5567,11 @@ static void __exit rs_fini(void)
tmp_buf = NULL;
free_page(pg);
}
+
+#ifdef ENABLE_SERIAL_PCI
+ if (serial_pci_driver.name[0])
+ pci_unregister_driver (&serial_pci_driver);
+#endif
}
module_init(rs_init);
@@ -5519,10 +5607,13 @@ static inline void wait_for_xmitr(struct async_struct *info)
if (--tmout == 0)
break;
} while((status & BOTH_EMPTY) != BOTH_EMPTY);
- if (info->flags & ASYNC_NO_FLOW)
- return;
- tmout = 1000000;
- while (--tmout && ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+
+ /* Wait for flow control if necessary */
+ if (info->flags & ASYNC_CONS_FLOW) {
+ tmout = 1000000;
+ while (--tmout &&
+ ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+ }
}
@@ -5605,7 +5696,7 @@ static kdev_t serial_console_device(struct console *c)
}
/*
- * Setup initial baud/bits/parity/flow. We do two things here:
+ * Setup initial baud/bits/parity/flow control. We do two things here:
* - construct a cflag setting for the first rs_open()
* - initialize the serial port
* Return non-zero if we didn't find a serial port.
@@ -5630,8 +5721,7 @@ static int __init serial_console_setup(struct console *co, char *options)
s++;
if (*s) parity = *s++;
if (*s) bits = *s++ - '0';
- if ((*s) && (!strcmp(s, "rtscts")))
- doflow = 1;
+ if (*s) doflow = (*s++ == 'r');
}
/*
@@ -5687,8 +5777,8 @@ static int __init serial_console_setup(struct console *co, char *options)
* Divisor, bytesize and parity
*/
state = rs_table + co->index;
- if (doflow == 0)
- state->flags |= ASYNC_NO_FLOW;
+ if (doflow)
+ state->flags |= ASYNC_CONS_FLOW;
info = &async_sercons;
info->magic = SERIAL_MAGIC;
info->state = state;
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 6628f9d05..021559dd4 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -165,12 +165,8 @@ static DECLARE_MUTEX(stl_tmpwritesem);
* at 9600, 8 data bits, 1 stop bit.
*/
static struct termios stl_deftermios = {
- 0,
- 0,
- (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
- 0,
- 0,
- INIT_C_CC
+ c_cflag: (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
+ c_cc: INIT_C_CC,
};
/*
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 024bada51..399f0102e 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -1647,7 +1647,7 @@ static int sx_fw_ioctl (struct inode *inode, struct file *filp,
#if 0
/* Removed superuser check: Sysops can use the permissions on the device
file to restrict access. Recommendation: Root only. (root.root 600) */
- if (!suser ()) {
+ if (!capable(CAP_SYS_ADMIN)) {
return -EPERM;
}
#endif
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index da09b33a6..95e712f6a 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -54,7 +54,11 @@
*/
#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
-#define BREAKPOINT() asm(" int $3");
+#if defined(__i386__)
+# define BREAKPOINT() asm(" int $3");
+#else
+# define BREAKPOINT() { }
+#endif
#define MAX_ISA_DEVICES 10
#define MAX_PCI_DEVICES 10
@@ -103,7 +107,7 @@
#endif
#ifdef CONFIG_SYNCLINK_SYNCPPP
-#include "../net/wan/syncppp.h"
+#include <net/syncppp.h>
#endif
#include <asm/segment.h>
@@ -6994,7 +6998,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
status = info->rx_buffer_list[0].status;
if ( status & (BIT8 + BIT3 + BIT1) ) {
- /* receive error has occured */
+ /* receive error has occurred */
rc = FALSE;
} else {
if ( memcmp( info->tx_buffer_list[0].virt_addr ,
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 0f9be7ac5..bdfeb7413 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -30,6 +30,8 @@
*
* You are not allowed to change this line nor the text above.
*
+ * 2001/02/26 Minor s/suser/capable/
+ *
* 1996/10/10 Emerald changes
*
* 1996/05/21 Misc changes+merges+cleanups + I/O reservations
@@ -208,7 +210,7 @@ static void qic02_release_resources(void);
* must ensure that a large enough buffer is passed to the kernel, in order
* to reduce tape repositioning wear and tear.
*/
-static unsigned long buffaddr; /* physical address of buffer */
+static void *buffaddr; /* virtual address of buffer */
/* This translates minor numbers to the corresponding recording format: */
static const char *format_names[] = {
@@ -1376,7 +1378,7 @@ static inline void dma_transfer(void)
flags=claim_dma_lock();
clear_dma_ff(QIC02_TAPE_DMA);
set_dma_mode(QIC02_TAPE_DMA, dma_mode);
- set_dma_addr(QIC02_TAPE_DMA, buffaddr+dma_bytes_done); /* full address */
+ set_dma_addr(QIC02_TAPE_DMA, virt_to_bus(buffaddr) + dma_bytes_done);
set_dma_count(QIC02_TAPE_DMA, TAPE_BLKSIZE);
/* start tape DMA controller */
@@ -1921,7 +1923,7 @@ static ssize_t qic02_tape_read(struct file * filp, char * buf, size_t count, lof
/* copy buffer to user-space in one go */
if (bytes_done>0)
{
- err = copy_to_user( (void *) buf, (void *) bus_to_virt(buffaddr), bytes_done);
+ err = copy_to_user(buf, buffaddr, bytes_done);
if (err)
{
return -EFAULT;
@@ -2074,7 +2076,7 @@ static ssize_t qic02_tape_write( struct file * filp, const char * buf,
/* copy from user to DMA buffer and initiate transfer. */
if (bytes_todo>0)
{
- err = copy_from_user( (void *) bus_to_virt(buffaddr), (const void *) buf, bytes_todo);
+ err = copy_from_user(buffaddr, buf, bytes_todo);
if (err)
{
return -EFAULT;
@@ -2198,7 +2200,7 @@ static int qic02_tape_open_no_use_count(struct inode * inode, struct file * filp
if (MINOR(dev)==255) /* special case for resetting */
{
- if (suser())
+ if (capable(CAP_SYS_ADMIN))
{
return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO;
}
@@ -2607,7 +2609,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
CHECK_IOC_SIZE(mtconfiginfo);
- if (!suser())
+ if (!capable(CAP_SYS_ADMIN))
{
return -EPERM;
}
@@ -2780,7 +2782,7 @@ static void qic02_release_resources(void)
release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
if (buffaddr)
{
- free_pages(buffaddr, get_order(TPQBUF_SIZE));
+ free_pages((unsigned long)buffaddr, get_order(TPQBUF_SIZE));
}
buffaddr = 0; /* Better to cause a panic than overwite someone else */
status_zombie = YES;
@@ -2830,9 +2832,7 @@ static int qic02_get_resources(void)
request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, TPQIC02_NAME);
/* Setup the page-address for the dma transfer. */
-
- /*** TODO: does _get_dma_pages() really return the physical address?? ****/
- buffaddr = __get_dma_pages(GFP_KERNEL,get_order(TPQBUF_SIZE));
+ buffaddr = (void *)__get_dma_pages(GFP_KERNEL, get_order(TPQBUF_SIZE));
if (!buffaddr)
{
@@ -2840,7 +2840,7 @@ static int qic02_get_resources(void)
return -EBUSY; /* Not ideal, EAGAIN perhaps? */
}
- memset( (void*) buffaddr, 0, TPQBUF_SIZE );
+ memset(buffaddr, 0, TPQBUF_SIZE);
printk(TPQIC02_NAME ": Settings: IRQ %d, DMA %d, IO 0x%x, IFC %s\n",
QIC02_TAPE_IRQ, QIC02_TAPE_DMA,
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index a2c98fc2a..218aa7681 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -60,6 +60,9 @@
*
* Reduced memory usage for older ARM systems
* -- Russell King <rmk@arm.linux.org.uk>
+ *
+ * Move do_SAK() into process context. Less stack use in devfs functions.
+ * alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
*/
#include <linux/config.h>
@@ -161,26 +164,19 @@ extern void tx3912_rs_init(void);
#define MAX(a,b) ((a) < (b) ? (b) : (a))
#endif
-static inline struct tty_struct *alloc_tty_struct(void)
+static struct tty_struct *alloc_tty_struct(void)
{
struct tty_struct *tty;
- if (PAGE_SIZE > 8192) {
- tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
- if (tty)
- memset(tty, 0, sizeof(struct tty_struct));
- } else
- tty = (struct tty_struct *)get_zeroed_page(GFP_KERNEL);
-
+ tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
+ if (tty)
+ memset(tty, 0, sizeof(struct tty_struct));
return tty;
}
static inline void free_tty_struct(struct tty_struct *tty)
{
- if (PAGE_SIZE > 8192)
- kfree(tty);
- else
- free_page((unsigned long) tty);
+ kfree(tty);
}
/*
@@ -1816,12 +1812,16 @@ int tty_ioctl(struct inode * inode, struct file * file,
* Now, if it would be correct ;-/ The current code has a nasty hole -
* it doesn't catch files in flight. We may send the descriptor to ourselves
* via AF_UNIX socket, close it and later fetch from socket. FIXME.
+ *
+ * Nasty bug: do_SAK is being called in interrupt context. This can
+ * deadlock. We punt it up to process context. AKPM - 16Mar2001
*/
-void do_SAK( struct tty_struct *tty)
+static void __do_SAK(void *arg)
{
#ifdef TTY_SOFT_SAK
tty_hangup(tty);
#else
+ struct tty_struct *tty = arg;
struct task_struct *p;
int session;
int i;
@@ -1844,7 +1844,6 @@ void do_SAK( struct tty_struct *tty)
task_lock(p);
if (p->files) {
read_lock(&p->files->file_lock);
- /* FIXME: p->files could change */
for (i=0; i < p->files->max_fds; i++) {
filp = fcheck_files(p->files, i);
if (filp && (filp->f_op == &tty_fops) &&
@@ -1862,6 +1861,19 @@ void do_SAK( struct tty_struct *tty)
}
/*
+ * The tq handling here is a little racy - tty->SAK_tq may already be queued.
+ * But there's no mechanism to fix that without futzing with tqueue_lock.
+ * Fortunately we don't need to worry, because if ->SAK_tq is already queued,
+ * the values which we write to it will be identical to the values which it
+ * already has. --akpm
+ */
+void do_SAK(struct tty_struct *tty)
+{
+ PREPARE_TQUEUE(&tty->SAK_tq, __do_SAK, tty);
+ schedule_task(&tty->SAK_tq);
+}
+
+/*
* This routine is called out of the software interrupt to flush data
* from the flip buffer to the line discipline.
*/
@@ -1975,6 +1987,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
sema_init(&tty->atomic_write, 1);
spin_lock_init(&tty->read_lock);
INIT_LIST_HEAD(&tty->tty_files);
+ INIT_TQUEUE(&tty->SAK_tq, 0, 0);
}
/*
@@ -1988,17 +2001,15 @@ void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
/*
* Register a tty device described by <driver>, with minor number <minor>.
*/
-void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
- unsigned int minor)
+void tty_register_devfs (struct tty_driver *driver, unsigned int flags, unsigned minor)
{
#ifdef CONFIG_DEVFS_FS
umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
- struct tty_struct tty;
+ kdev_t device = MKDEV (driver->major, minor);
+ int idx = minor - driver->minor_start;
char buf[32];
- tty.driver = *driver;
- tty.device = MKDEV (driver->major, minor);
- switch (tty.device) {
+ switch (device) {
case TTY_DEV:
case PTMX_DEV:
mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
@@ -2019,7 +2030,8 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
(driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) )
flags |= DEVFS_FL_CURRENT_OWNER;
# endif
- devfs_register (NULL, tty_name (&tty, buf), flags | DEVFS_FL_DEFAULT,
+ sprintf(buf, driver->name, idx + driver->name_base);
+ devfs_register (NULL, buf, flags | DEVFS_FL_DEFAULT,
driver->major, minor, mode, &tty_fops, NULL);
#endif /* CONFIG_DEVFS_FS */
}
@@ -2028,14 +2040,11 @@ void tty_unregister_devfs (struct tty_driver *driver, unsigned minor)
{
#ifdef CONFIG_DEVFS_FS
void * handle;
- struct tty_struct tty;
+ int idx = minor - driver->minor_start;
char buf[32];
- tty.driver = *driver;
- tty.device = MKDEV(driver->major, minor);
-
- handle = devfs_find_handle (NULL, tty_name (&tty, buf),
- driver->major, minor,
+ sprintf(buf, driver->name, idx + driver->name_base);
+ handle = devfs_find_handle (NULL, buf, driver->major, minor,
DEVFS_SPECIAL_CHR, 0);
devfs_unregister (handle);
#endif /* CONFIG_DEVFS_FS */
@@ -2226,9 +2235,6 @@ static struct tty_driver dev_console_driver;
*/
void __init tty_init(void)
{
- if (sizeof(struct tty_struct) > PAGE_SIZE)
- panic("size of tty structure > PAGE_SIZE!");
-
/*
* dev_tty_driver and dev_console_driver are actually magic
* devices which get redirected at open time. Nevertheless,