diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-07-03 21:46:06 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-07-03 21:46:06 +0000 |
commit | 3e414096429d55fbc8116171bba3487647bbe638 (patch) | |
tree | 2b5fcfd9d16fa3a32c829fc2076f6e3785b43374 /drivers/char | |
parent | 20b23bfcf36fcb2d16d8b844501072541970637c (diff) |
Merge with Linux 2.4.0-test3-pre2.
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/i810_rng.c | 386 | ||||
-rw-r--r-- | drivers/char/n_tty.c | 30 | ||||
-rw-r--r-- | drivers/char/ppdev.c | 1 | ||||
-rw-r--r-- | drivers/char/stallion.c | 2 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 71 |
5 files changed, 319 insertions, 171 deletions
diff --git a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c index 191ce5001..905d8e8cd 100644 --- a/drivers/char/i810_rng.c +++ b/drivers/char/i810_rng.c @@ -2,35 +2,35 @@ Hardware driver for Intel i810 Random Number Generator (RNG) Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com> - + Driver Web site: http://gtf.org/garzik/drivers/i810_rng/ - + 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?) - + ---------------------------------------------------------- - + This software may be used and distributed according to the terms of the GNU 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 @@ -44,7 +44,7 @@ Theory of operation: This driver has TWO modes of operation: - + Mode 1 ------ Character driver. Using the standard open() @@ -52,16 +52,16 @@ 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 + 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 @@ -71,12 +71,12 @@ 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. @@ -84,14 +84,13 @@ Driver notes: - * You may enable and disable the RNG hardware (and this - driver) via sysctl: + * You may enable and disable the RNG timer via sysctl: # disable RNG - echo 0 > /proc/sys/dev/i810_hw_enabled + echo 0 > /proc/sys/dev/i810_rng_timer # enable RNG - echo 1 > /proc/sys/dev/i810_hw_enabled + 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 @@ -103,10 +102,56 @@ * 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 - + and make sure all users of the character device have closed + + * The timer and the character device may be used simultaneously, + if desired. + + * FIXME: Currently only one open() of the character device is allowed. + If another user tries to open() the device, they will get an + -EBUSY error. Instead, this really should either support + multiple simultaneous users of the character device (not hard), + or simply block open() until the current user of the chrdev + calls close(). + + * 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. + + ---------------------------------------------------------- + + Change history: + + 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 + */ @@ -115,6 +160,7 @@ #include <linux/fs.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/random.h> #include <linux/sysctl.h> @@ -127,24 +173,24 @@ /* * core module and version information */ -#define RNG_VERSION "0.6.1" +#define RNG_VERSION "0.6.2" #define RNG_MODULE_NAME "i810_rng" #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION -#define PFX RNG_MODULE_NAME ": " +#define PFX RNG_MODULE_NAME ": " /* * debugging macros */ #undef RNG_DEBUG /* define to 1 to enable copious debugging info */ - + #ifdef RNG_DEBUG /* note: prints function name for you */ #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) #else #define DPRINTK(fmt, args...) #endif - + #define RNG_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ #if RNG_NDEBUG #define assert(expr) @@ -156,11 +202,11 @@ } #endif - + /* * misc helper macros */ -#define arraysize(x) (sizeof(x)/sizeof(*(x))) +#define arraysize(x) (sizeof(x)/sizeof(*(x))) /* * prototypes @@ -191,7 +237,7 @@ static void rng_run_fips_test (void); * Frequency that data is added to kernel entropy pool * HZ>>1 == every half-second */ -#define RNG_TIMER_LEN (HZ >> 1) +#define RNG_DEF_TIMER_LEN (HZ >> 1) /* @@ -206,18 +252,22 @@ static void rng_run_fips_test (void); * various RNG status variables. they are globals * as we only support a single RNG device */ -static int rng_allocated = 0; /* is someone using the RNG region? */ -static int rng_hw_enabled = 0; /* is the RNG h/w, and timer, enabled? */ -static int rng_trusted = 0; /* does FIPS trust out data? */ +static int rng_allocated; /* is someone using the RNG region? */ +static int rng_hw_enabled; /* is the RNG h/w enabled? */ +static int rng_timer_enabled; /* is the RNG timer enabled? */ +static int rng_use_count; /* number of times RNG has been enabled */ +static int rng_trusted; /* does FIPS trust out data? */ static int rng_enabled_sysctl; /* sysctl for enabling/disabling RNG */ -static int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */ -static int rng_entropy_sysctl; /* sysctl for changing entropy bits */ -static int rng_have_mem_region = 0; /* did we grab RNG region via request_mem_region? */ -static int rng_fips_counter = 0; /* size of internal FIPS test data pool */ -static void *rng_mem = NULL; /* token to our ioremap'd RNG register area */ +static int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */ +static int rng_entropy_sysctl; /* sysctl for changing entropy bits */ +static 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 int rng_fips_counter; /* size of internal FIPS test data pool */ +static 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 atomic_t rng_open; +static int rng_open; /* boolean, 0 (false) if chrdev is closed, 1 (true) if open */ /* * inlined helper functions for accessing RNG registers @@ -240,7 +290,7 @@ static inline int rng_data_present (void) { assert (rng_mem != NULL); assert (rng_hw_enabled == 1); - + return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0; } @@ -249,22 +299,21 @@ static inline int rng_data_read (void) { assert (rng_mem != NULL); assert (rng_hw_enabled == 1); - + return readb (rng_mem + RNG_DATA); } /* - * rng_timer_ticker - executes every RNG_TIMER_LEN jiffies, + * 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) { - unsigned long flags; int rng_data; - spin_lock_irqsave (&rng_lock, flags); + spin_lock (&rng_lock); if (rng_data_present ()) { /* gimme some thermal noise, baby */ @@ -285,11 +334,14 @@ static void rng_timer_tick (unsigned long data) rng_run_fips_test (); } - spin_unlock_irqrestore (&rng_lock, flags); + /* run the timer again, if enabled */ + if (rng_timer_enabled) { + rng_timer.expires = jiffies + rng_timer_len; + add_timer (&rng_timer); + } + + spin_unlock (&rng_lock); - /* run the timer again */ - rng_timer.expires = jiffies + RNG_TIMER_LEN; - add_timer (&rng_timer); } @@ -298,43 +350,44 @@ static void rng_timer_tick (unsigned long data) */ static int rng_enable (int enable) { - unsigned long flags; int rc = 0; u8 hw_status; - + DPRINTK ("ENTER\n"); - - spin_lock_irqsave (&rng_lock, flags); + + spin_lock_bh (&rng_lock); hw_status = rng_hwstatus (); - - if (enable && !rng_hw_enabled) { - rng_hwstatus_set (hw_status | RNG_ENABLED); - printk (KERN_INFO PFX "RNG h/w enabled\n"); + if (enable) { rng_hw_enabled = 1; + rng_use_count++; MOD_INC_USE_COUNT; + } else { + rng_use_count--; + if (rng_use_count == 0) + rng_hw_enabled = 0; + MOD_DEC_USE_COUNT; } - - else if (!enable && rng_hw_enabled) { - del_timer (&rng_timer); - rng_hwstatus_set (hw_status & ~RNG_ENABLED); + if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) { + rng_hwstatus_set (hw_status | RNG_ENABLED); + printk (KERN_INFO PFX "RNG h/w enabled\n"); + } + else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) { + rng_hwstatus_set (hw_status & ~RNG_ENABLED); printk (KERN_INFO PFX "RNG h/w disabled\n"); - rng_hw_enabled = 0; - MOD_DEC_USE_COUNT; } - - if (enable != (rng_hwstatus () & RNG_ENABLED) ) { - del_timer (&rng_timer); + + spin_unlock_bh (&rng_lock); + + if ((!!enable) != (!!(rng_hwstatus () & RNG_ENABLED))) { printk (KERN_ERR PFX "Unable to %sable the RNG\n", enable ? "en" : "dis"); rc = -EIO; } - spin_unlock_irqrestore (&rng_lock, flags); - DPRINTK ("EXIT, returning %d\n", rc); return rc; } @@ -343,26 +396,42 @@ 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) { - unsigned long flags; int enabled_save, rc; DPRINTK ("ENTER\n"); - - spin_lock_irqsave (&rng_lock, flags); - rng_enabled_sysctl = enabled_save = rng_hw_enabled; - spin_unlock_irqrestore (&rng_lock, flags); + + spin_lock_bh (&rng_lock); + + rng_enabled_sysctl = enabled_save = rng_timer_enabled; rc = proc_dointvec (table, write, filp, buffer, lenp); - if (rc) + if (rc) { + spin_unlock_bh (&rng_lock); return rc; - - if (enabled_save != rng_enabled_sysctl) + } + + 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); + } + DPRINTK ("EXIT, returning 0\n"); return 0; } @@ -371,31 +440,30 @@ static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file * /* * 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) { - unsigned long flags; int entropy_bits_save, rc; DPRINTK ("ENTER\n"); - - spin_lock_irqsave (&rng_lock, flags); + + spin_lock_bh (&rng_lock); rng_entropy_sysctl = entropy_bits_save = rng_entropy; - spin_unlock_irqrestore (&rng_lock, flags); + 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_irqsave (&rng_lock, flags); + spin_lock_bh (&rng_lock); rng_entropy = rng_entropy_sysctl; - spin_unlock_irqrestore (&rng_lock, flags); + spin_unlock_bh (&rng_lock); printk (KERN_INFO PFX "entropy bits now %d\n", rng_entropy_sysctl); } else { @@ -408,36 +476,89 @@ out: 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_RNG 1 -#define DEV_I810_RNG_ENTROPY 2 +#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_RNG, /* ID */ - RNG_MODULE_NAME "_enabled", /* name in /proc */ + {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 */ + 0644, /* mode */ + 0, /* child */ rng_handle_sysctl_enable, /* proc handler */ - 0, /* strategy */ - 0, /* proc control block */ + 0, /* strategy */ + 0, /* proc control block */ 0, 0} , - {DEV_I810_RNG_ENTROPY, /* ID */ + {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 */ + 0644, /* mode */ + 0, /* child */ rng_handle_sysctl_entropy, /* proc handler */ - 0, /* strategy */ - 0, /* proc control block */ + 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} @@ -467,35 +588,36 @@ static void rng_sysctl (int add) static int rng_dev_open (struct inode *inode, struct file *filp) { int rc = -EINVAL; - unsigned long flags; if ((filp->f_mode & FMODE_READ) == 0) goto err_out; if (filp->f_mode & FMODE_WRITE) goto err_out; - spin_lock_irqsave (&rng_lock, flags); - - if (atomic_read(&rng_open)) { - spin_unlock_irqrestore (&rng_lock, flags); + spin_lock_bh (&rng_lock); + + /* only allow one open of this device, exit with -EBUSY if already open */ + /* FIXME: we should sleep on a semaphore here, unless O_NONBLOCK */ + if (rng_open) { + spin_unlock_bh (&rng_lock); rc = -EBUSY; goto err_out; } - - atomic_set (&rng_open, 1); - spin_unlock_irqrestore (&rng_lock, flags); - + rng_open = 1; + + spin_unlock_bh (&rng_lock); + if (rng_enable(1) != 0) { - spin_lock_irqsave (&rng_lock, flags); - atomic_set (&rng_open, 0); - spin_unlock_irqrestore (&rng_lock, flags); + spin_lock_bh (&rng_lock); + rng_open = 0; + spin_unlock_bh (&rng_lock); rc = -EIO; goto err_out; } - + return 0; - + err_out: return rc; } @@ -503,14 +625,13 @@ err_out: static int rng_dev_release (struct inode *inode, struct file *filp) { - unsigned long flags; if (rng_enable(0) != 0) return -EIO; - spin_lock_irqsave (&rng_lock, flags); - atomic_set (&rng_open, 0); - spin_unlock_irqrestore (&rng_lock, flags); + spin_lock_bh (&rng_lock); + rng_open = 0; + spin_unlock_bh (&rng_lock); return 0; } @@ -520,14 +641,13 @@ static ssize_t rng_dev_read (struct file *filp, char * buf, size_t size, loff_t *offp) { int have_data, copied = 0; - unsigned long flags; u8 data=0; u8 *page; - + if (size < 1) return 0; - - page = (unsigned char *) get_zeroed_page (GFP_KERNEL); + + page = (unsigned char *) get_free_page (GFP_KERNEL); if (!page) return -ENOMEM; @@ -545,7 +665,7 @@ read_loop: return tmpsize; } - spin_lock_irqsave (&rng_lock, flags); + spin_lock_bh (&rng_lock); have_data = 0; if (rng_data_present ()) { @@ -553,8 +673,8 @@ read_loop: have_data = 1; } - spin_unlock_irqrestore (&rng_lock, flags); - + spin_unlock_bh (&rng_lock); + if (have_data) { page[copied] = data; copied++; @@ -567,12 +687,12 @@ read_loop: if (current->need_resched) schedule (); - + if (signal_pending (current)) { free_page ((long)page); return -ERESTARTSYS; } - + goto read_loop; } @@ -585,7 +705,7 @@ static int __init rng_init_one (struct pci_dev *dev, { int rc; u8 hw_status; - + DPRINTK ("ENTER\n"); if (rng_allocated) { @@ -619,7 +739,7 @@ static int __init rng_init_one (struct pci_dev *dev, 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; @@ -653,7 +773,7 @@ const static struct pci_device_id rng_pci_tbl[] __initdata = { { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, }; -MODULE_DEVICE_TABLE (pci, rng_pci_tbl); +MODULE_DEVICE_TABLE (pci, rng_pci_tbl); static struct pci_driver rng_driver = { name: RNG_MODULE_NAME, @@ -690,31 +810,21 @@ static int __init rng_init (void) int rc; DPRINTK ("ENTER\n"); - - MOD_INC_USE_COUNT; if (pci_register_driver (&rng_driver) < 1) { DPRINTK ("EXIT, returning -ENODEV\n"); - MOD_DEC_USE_COUNT; return -ENODEV; } - + rc = misc_register (&rng_miscdev); if (rc) { pci_unregister_driver (&rng_driver); DPRINTK ("EXIT, returning %d\n", rc); - MOD_DEC_USE_COUNT; return rc; } printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); - /* FIXME: verify module unload logic, then remove - * this additional MOD_INC_USE_COUNT */ - MOD_INC_USE_COUNT; - - MOD_DEC_USE_COUNT; /* init complete, unload allowed now */ - DPRINTK ("EXIT, returning 0\n"); return 0; } @@ -725,13 +835,9 @@ static int __init rng_init (void) */ static void __exit rng_cleanup (void) { - unsigned long flags; - DPRINTK ("ENTER\n"); - spin_lock_irqsave (&rng_lock, flags); - del_timer (&rng_timer); - spin_unlock_irqrestore (&rng_lock, flags); + del_timer_sync (&rng_timer); rng_sysctl (0); pci_unregister_driver (&rng_driver); diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index f488d9124..0e9d7b57f 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -18,6 +18,8 @@ * This file may be redistributed under the terms of the GNU Public * License. * + * Reduced memory usage for older ARM systems - Russell King. + * * 2000/01/20 Fixed SMP locking on put_tty_queue using bits of * the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu> * who actually finally proved there really was a race. @@ -61,6 +63,29 @@ #define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ #define TTY_THRESHOLD_UNTHROTTLE 128 +static inline unsigned char *alloc_buf(void) +{ + unsigned char *p; + int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + + if (PAGE_SIZE != N_TTY_BUF_SIZE) { + p = kmalloc(N_TTY_BUF_SIZE, prio); + if (p) + memset(p, 0, N_TTY_BUF_SIZE); + } else + p = (unsigned char *)get_zeroed_page(prio); + + return p; +} + +static inline void free_buf(unsigned char *buf) +{ + if (PAGE_SIZE != N_TTY_BUF_SIZE) + kfree(buf); + else + free_page((unsigned long) buf); +} + static inline void put_tty_queue(unsigned char c, struct tty_struct *tty) { unsigned long flags; @@ -827,7 +852,7 @@ static void n_tty_close(struct tty_struct *tty) { n_tty_flush_buffer(tty); if (tty->read_buf) { - free_page((unsigned long) tty->read_buf); + free_buf(tty->read_buf); tty->read_buf = 0; } } @@ -838,8 +863,7 @@ static int n_tty_open(struct tty_struct *tty) return -EINVAL; if (!tty->read_buf) { - tty->read_buf = (unsigned char *) - get_zeroed_page(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + tty->read_buf = alloc_buf(); if (!tty->read_buf) return -ENOMEM; } diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index af52cf98f..ae4b9e112 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -106,6 +106,7 @@ static void pp_attach (struct parport *port) } add->next = pp_port_list; + add->port = port; down (&pp_port_list_lock); pp_port_list = add; up (&pp_port_list_lock); diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index ba1b9caa9..235b0f131 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -780,7 +780,7 @@ void cleanup_module() stlpanel_t *panelp; stlport_t *portp; unsigned long flags; - int i, j, k, l; + int i, j, k; #if DEBUG printk("cleanup_module()\n"); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 613b2f967..4c0d29662 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -57,6 +57,9 @@ * * Added support for a Unix98-style ptmx device. * -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998 + * + * Reduced memory usage for older ARM systems + * -- Russell King <rmk@arm.linux.org.uk> */ #include <linux/config.h> @@ -111,7 +114,7 @@ extern void con_init_devfs (void); #define CHECK_TTY_COUNT 1 struct termios tty_std_termios; /* for the benefit of tty drivers */ -struct tty_driver *tty_drivers = NULL; /* linked list of tty drivers */ +struct tty_driver *tty_drivers; /* linked list of tty drivers */ struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ #ifdef CONFIG_UNIX98_PTYS @@ -123,7 +126,7 @@ extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */ * redirect is the pseudo-tty that console output * is redirected to if asked by TIOCCONS. */ -struct tty_struct * redirect = NULL; +struct tty_struct * redirect; static void initialize_tty_struct(struct tty_struct *tty); @@ -135,35 +138,49 @@ static int tty_release(struct inode *, struct file *); int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); static int tty_fasync(int fd, struct file * filp, int on); -#ifdef CONFIG_SX extern int sx_init (void); -#endif -#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC) extern int vme_scc_init (void); extern long vme_scc_console_init(void); -#endif -#ifdef CONFIG_SERIAL167 extern int serial167_init(void); extern long serial167_console_init(void); -#endif -#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) extern void console_8xx_init(void); extern int rs_8xx_init(void); -#endif /* CONFIG_8xx */ -#ifdef CONFIG_SGI_SERIAL -extern void sgi_serial_console_init(void); -#endif -#ifdef CONFIG_HWC extern void hwc_console_init(void); -#endif -#ifdef CONFIG_3215 extern void con3215_init(void); -#endif /* CONFIG_3215 */ - +extern void rs285_console_init(void); +extern void rs285_init(void); +extern void sa1100_rs_console_init(void); +extern void sa1100_rs_init(void); +extern void sgi_serial_console_init(void); #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +#ifndef MAX +#define MAX(a,b) ((a) < (b) ? (b) : (a)) +#endif + +static inline 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); + + return tty; +} + +static inline void free_tty_struct(struct tty_struct *tty) +{ + if (PAGE_SIZE > 8192) + kfree(tty); + else + free_page((unsigned long) tty); +} /* * This routine returns the name of tty. @@ -695,7 +712,7 @@ static inline ssize_t do_tty_write( unlock_kernel(); } else { for (;;) { - unsigned long size = PAGE_SIZE*2; + unsigned long size = MAX(PAGE_SIZE*2,16384); if (size > count) size = count; lock_kernel(); @@ -826,7 +843,7 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty) tp = o_tp = NULL; ltp = o_ltp = NULL; - tty = (struct tty_struct*) get_zeroed_page(GFP_KERNEL); + tty = alloc_tty_struct(); if(!tty) goto fail_no_mem; initialize_tty_struct(tty); @@ -852,7 +869,7 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty) } if (driver->type == TTY_DRIVER_TYPE_PTY) { - o_tty = (struct tty_struct *) get_zeroed_page(GFP_KERNEL); + o_tty = alloc_tty_struct(); if (!o_tty) goto free_mem_out; initialize_tty_struct(o_tty); @@ -972,12 +989,12 @@ free_mem_out: if (o_tp) kfree_s(o_tp, sizeof(struct termios)); if (o_tty) - free_page((unsigned long) o_tty); + free_tty_struct(o_tty); if (ltp) kfree_s(ltp, sizeof(struct termios)); if (tp) kfree_s(tp, sizeof(struct termios)); - free_page((unsigned long) tty); + free_tty_struct(tty); fail_no_mem: retval = -ENOMEM; @@ -1008,7 +1025,7 @@ static void release_mem(struct tty_struct *tty, int idx) } o_tty->magic = 0; (*o_tty->driver.refcount)--; - free_page((unsigned long) o_tty); + free_tty_struct(o_tty); } tty->driver.table[idx] = NULL; @@ -1019,7 +1036,7 @@ static void release_mem(struct tty_struct *tty, int idx) } tty->magic = 0; (*tty->driver.refcount)--; - free_page((unsigned long) tty); + free_tty_struct(tty); } /* @@ -1400,9 +1417,9 @@ init_dev_done: static int nr_warns = 0; if (nr_warns < 5) { printk(KERN_WARNING "tty_io.c: " - "process %d (%s) used obsolete /dev/%s - " + "process %d (%s) used obsolete /dev/%s - " "update software to use /dev/ttyS%d\n", - current->pid, current->comm, + current->pid, current->comm, tty_name(tty, buf), TTY_NUMBER(tty)); nr_warns++; } |