diff options
Diffstat (limited to 'drivers/char')
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(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->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, ®s[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(¤t->mm->mmap_sem); + down_write(¤t->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(¤t->mm->mmap_sem); + up_write(¤t->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(¤t->mm->mmap_sem); + down_write(¤t->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(¤t->mm->mmap_sem); + up_write(¤t->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(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, MAP_SHARED, (unsigned long)map->offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } else { - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->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(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, MAP_SHARED, (unsigned long)map->offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } else { - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->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(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, MAP_SHARED, (unsigned long)map->offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } else { - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->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, |