N: Rik Faith
E: faith@cs.unc.edu
-E: r.faith@ieee.org
+E: faith@acm.org
D: Author: Future Domain TMC-16x0 SCSI driver
D: Debugging: SCSI code; Cyclades serial driver; APM driver
D: Debugging: XFree86 Mach 32 server, accelerated server code
This is a brief list of all the files in ./linux/Documentation and what
they contain. If you add a documentation file, please list it here in
alphabetical order as well, or risk being hunted down like a rabid dog.
-Note that subdirectories have their own index files too.
+Note that subdirectories have their own index files too. Please try and
+keep the descriptions small enough to fit on one line.
Thanks -- Paul G.
00-INDEX
- info on the in-kernel binary support for Java(tm)
joystick.txt
- info on using joystick devices (and driver) with linux.
+kmod.txt
+ - - info on the kernel module loader/unloader (kerneld replacement)
locks.txt
- info on file locking implementations, flock() vs. fcntl(), etc.
logo.gif
- info on typical Linux memory problems.
modules.txt
- short guide on how to make kernel parts into loadable modules
+mtrr.txt
+ - how to use PPro Memory Type Range Registers to increase performance
nbd.txt
- info on a TCP implementation of a network block device.
networking/
00-INDEX
- this file (info on CD-ROMs and Linux)
+Makefile
+ - only used to generate TeX output from the documentation.
aztcd
- info on Aztech/Orchid/Okano/Wearnes/Conrad/CyCDROM driver.
-
cdrom-standard.tex
- LaTeX document on standardizing the CD-ROM programming interface.
cdu31a
coda.txt
- description of the CODA filesystem.
fat_cvf.txt
- - Description of the Compressed Volume Files extension to the FAT
- filesystem
+ - info on the Compressed Volume Files extension to the FAT filesystem
hpfs.txt
- info and mount options for the OS/2 HPFS.
isofs.txt
First, the "normal" root file system has to be prepared as follows:
-# mknod /dev/initrd b 0 250
+# mknod /dev/initrd b 1 250
# chmod 400 /dev/initrd
# mkdir /initrd
All necessary files can be found at
- ftp://ftp.uni-erlangen.de/pub/Linux/LOCAL/680x0/
+ ftp://ftp.uni-erlangen.de/pub/Linux/680x0/
and on its mirrors.
(BPF), so refering to the BSD bpf.4 manpage is very helpful in
creating filters.
-LSF is much simpler that BPF. One does not have to worry about
+LSF is much simpler than BPF. One does not have to worry about
devices or anything like that. You simply create your filter
code, send it to the kernel via the SO_ATTACH_FILTER ioctl and
if your filter code passes the kernel check on it, you then
Behaviour of cards under Multicast. This is how they currently
-behave not what the hardware can do. In particular all the 8390 based
-cards don't use the onboard hash filter, and the lance driver doesn't
+behave not what the hardware can do - i.e. the lance driver doesn't
use its filter, even though the code for loading it is in the DEC
lance based driver.
fflush(stderr);
for (i=1; i<6; i++) {
struct timeval tv = {5, 0}; /* 5 second timeout on select */
- struct fd_set readfds;
+ fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
modular, 'make' will notice that the foo.o was not compiled
with -DMODULE and will recompile foo.c.
- Flag dependencies also work with per-source-file flags such
- as those in drivers/net/CONFIG.
-
All .a and .o files made from C source or with 'ld' or 'ar'
have flag dependencies. .S files do not have flag dependencies.
Per-source-file Flags
+ Flag dependencies also work with per-source-file flags.
You can specify compilation flags for individual source files
like this:
'm' - Will dump current memory info to your console.
-'0'-'8' - Sets the console log level, controlling which kernel messages
+'0'-'9' - Sets the console log level, controlling which kernel messages
will be printed to your console. ('0', for example would make
it so that only emergency messages like PANICs or OOPSes would
make it to your console.)
and 'U'mount first.
'S'ync is great when your system is locked up, it allows you to sync your
-disks and will certainly lessen the chance of data loss and fscking.
+disks and will certainly lessen the chance of data loss and fscking. Note
+that the sync hasn't taken place until you see the "OK" and "Done" appear
+on the screen. (If the kernel is really in strife, you may not ever get the
+OK or Done message...)
'U'mount is basically useful in the same ways as 'S'ync. I generally 'S'ync,
'U'mount, then re'B'oot when my system locks. It's saved me many a fsck.
+Again, the unmount (remount read-only) hasn't taken place until you see the
+"OK" and "Done" message appear on the screen.
-The loglevel'0'-'8' is useful when your console is being flooded with
+The loglevel'0'-'9' is useful when your console is being flooded with
kernel messages you do not want to see. Setting '0' will prevent all but
the most urgent kernel messages from reaching your console. (They will
still be logged if syslogd/klogd are alive, though.)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
That happens to me, also. I've found that tapping shift, alt, and control
on both sides of the keyboard, and hitting an invalid sysrq sequence again
-will fix the problem. (ie, something like alt-sysrq-z).
+will fix the problem. (ie, something like alt-sysrq-z). Switching to another
+virtual console (ALT+Fn) and then back again should also help.
* I hit SysRQ, but nothing seems to happen, what's wrong?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
S: Maintained
APM DRIVER
-P: Rik Faith & Stephen Rothwell
-M: faith@cs.unc.edu, Stephen.Rothwell@canb.auug.org.au
+P: Stephen Rothwell
+M: Stephen.Rothwell@canb.auug.org.au
L: linux-laptop@vger.rutgers.edu
S: Maintained
#endif
#include "irq.h"
+spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
+
struct task_struct *last_task_used_math = NULL;
#ifdef __SMP__
#include "irq.h"
-spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
-
extern unsigned long start_kernel, _etext;
extern void update_one_process( struct task_struct *p,
unsigned long ticks, unsigned long user,
#define BLOCKMOVE
-#define NEW_INTR_FLOW
#define Z_WAKE
-#define NEW_PCI
static char rcsid[] =
-"$Revision: 2.2.1.1 $$Date: 1998/03/19 16:43:12 $";
+"$Revision: 2.2.1.3 $$Date: 1998/06/01 12:09:10 $";
/*
* linux/drivers/char/cyclades.c
* void cleanup_module(void);
*
* $Log: cyclades.c,v $
+ * Revision 2.2.1.3 1998/06/01 12:09:10 ivan
+ * General code review in order to comply with 2.1 kernel standards;
+ * data loss prevention for slow devices revisited (cy_wait_until_sent
+ * was created);
+ * removed conditional compilation for new/old PCI structure support
+ * (now the driver only supports the new PCI structure).
+ *
* Revision 2.2.1.1 1998/03/19 16:43:12 ivan
* added conditional compilation for new/old PCI structure support;
* removed kernel series (2.0.x / 2.1.x) conditional compilation.
* Revision 2.1.1.3 1998/03/16 18:01:12 ivan
* cleaned up the data loss fix;
* fixed XON/XOFF handling once more (Cyclades-Z);
- * general revision in the driver routines;
+ * general review of the driver routines;
* introduction of a mechanism to prevent data loss with slow
* printers, by forcing a delay before closing the port.
*
#define ZE_V1 2
#define SERIAL_PARANOIA_CHECK
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_DEBUG_OTHER
-#undef SERIAL_DEBUG_IO
-#undef SERIAL_DEBUG_COUNT
-#undef SERIAL_DEBUG_DTR
-#undef CYCLOM_16Y_HACK
-#undef CYCLOM_ENABLE_MONITORING
+#undef CY_DEBUG_OPEN
+#undef CY_DEBUG_THROTTLE
+#undef CY_DEBUG_OTHER
+#undef CY_DEBUG_IO
+#undef CY_DEBUG_COUNT
+#undef CY_DEBUG_DTR
+#undef CY_DEBUG_WAIT_UNTIL_SENT
+#undef CY_16Y_HACK
+#undef CY_ENABLE_MONITORING
#undef CY_PCI_DEBUG
#if 0
(cy_readl(&buf_ctrl->tx_bufsize) - 1))
#endif
+/*
+ * Include section
+ */
+#include <linux/config.h>
#include <linux/module.h>
-
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
+#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/serial.h>
-#include <linux/interrupt.h>
+#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/cyclades.h>
-#include <linux/delay.h>
-#include <linux/major.h>
#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#ifndef NEW_PCI
-#include <linux/bios32.h>
-#endif
#include <linux/pci.h>
-
#include <linux/version.h>
-#include <asm/uaccess.h>
-#include <linux/init.h>
#define cy_put_user put_user
#define STD_COM_FLAGS (0)
-#define SERIAL_TYPE_NORMAL 1
-#define SERIAL_TYPE_CALLOUT 2
-
static DECLARE_TASK_QUEUE(tq_cyclades);
static struct tty_driver cy_serial_driver, cy_callout_driver;
+static int serial_refcount;
static volatile int cy_irq_triggered;
static volatile int cy_triggered;
static int cy_wild_int_mask;
static volatile ucchar *intr_base_addr;
-
/* This is the address lookup table. The driver will probe for
Cyclom-Y/ISA boards at all addresses in here. If you want the
driver to probe addresses at a different address, add it to
static int cy_next_channel = 0; /* next minor available */
-static int serial_refcount;
-
static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
/* This is the per-irq data structure,
it maps an irq to the corresponding card */
-static struct cyclades_card *IRQ_cards[16];
-
+static struct cyclades_card *IRQ_cards[NR_IRQS];
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
* memory if large numbers of serial ports are open. This buffer is
* allocated when the first cy_open occurs.
*/
-static unsigned char *tmp_buf = 0;
+static unsigned char *tmp_buf;
static struct semaphore tmp_buf_sem = MUTEX;
/*
return 0;
} /* serial_paranoia_check */
-
-/* The following diagnostic routines allow the driver to spew
- information on the screen, even (especially!) during interrupts.
- */
-static void
-SP(char *data){
- unsigned long flags;
- save_flags(flags); cli();
- console_print(data);
- restore_flags(flags);
-}/* SP */
-
-static void
-CP(char data){
- unsigned long flags;
- char scrn[2];
- save_flags(flags); cli();
- scrn[0] = data;
- scrn[1] = '\0';
- console_print(scrn);
- restore_flags(flags);
-}/* CP */
-
-static void CP4(int data)
- { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP4 */
-static void CP8(int data)
- { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */
-#if 0
-static void CP16(int data)
- { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */
-static void CP32(long data)
- { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */
-#endif
-
-
/*
* This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver
if(cy_readb(intr_base_addr+(CySVRR<<index)) != 0) {
save_xir = (u_char) cy_readb(intr_base_addr+(CyTIR<<index));
save_car = cy_readb(intr_base_addr+(CyCAR<<index));
- if ((save_xir & 0x3) != 0){
- SP("channel ");
- CP8(save_xir);
- SP(" requesting unexpected interrupt\n");
- }
cy_writeb((u_long)intr_base_addr+(CyCAR<<index), (save_xir & 0x3));
cy_writeb((u_long)intr_base_addr+(CySRER<<index),
cy_readb(intr_base_addr+(CySRER<<index)) & ~CyTxMpty);
/* load # chars available from the chip */
char_count = cy_readb(base_addr+(CyRDCR<<index));
-#ifdef CYCLOM_ENABLE_MONITORING
+#ifdef CY_ENABLE_MONITORING
++info->mon.int_count;
info->mon.char_count += char_count;
if (char_count > info->mon.char_max)
data = cy_readb(base_addr+(CyRDSR<<index));
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
*tty->flip.char_buf_ptr++ = data;
-#ifdef CYCLOM_16Y_HACK
+#ifdef CY_16Y_HACK
udelay(10L);
#endif
}
info->x_break = 0;
}
-#ifdef NEW_INTR_FLOW
if (!info->xmit_cnt){
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
goto txdone;
}
if (info->xmit_buf == 0){
cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
goto txdone;
}
-#endif
while (char_count-- > 0){
-#ifdef NEW_INTR_FLOW
if (!info->xmit_cnt){
goto txdone;
}
-#else
- if (!info->xmit_cnt){
- cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- goto txdone;
- }
- if (info->xmit_buf == 0){
- cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- goto txdone;
- }
- if (info->tty->stopped || info->tty->hw_stopped){
- cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- }
-#endif
/* Because the Embedded Transmit Commands have
been enabled, we must check to see if the
escape character, NULL, is being sent. If it
if ((fw_ver > 241 ?
((u_long)param) :
cy_readl(&ch_ctrl[channel].rs_status)) & C_RS_DCD) {
- /* SP("Open Wakeup\n"); */
cy_sched_event(info,
Cy_EVENT_OPEN_WAKEUP);
}else if(!((info->flags
& ASYNC_CALLOUT_ACTIVE)
&&(info->flags
& ASYNC_CALLOUT_NOHUP))){
- /* SP("Hangup\n"); */
cy_sched_event(info,
Cy_EVENT_HANGUP);
}
if( cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD){
/* cy_start isn't used because...
HW flow is handled by the board */
- /* SP("Write Wakeup\n"); */
cy_sched_event(info,
Cy_EVENT_WRITE_WAKEUP);
}
if(!(cy_readl(&ch_ctrl[channel].rs_status) & C_RS_CTS)){
/* cy_stop isn't used because
HW flow is handled by the board */
- /* SP("Write stop\n"); */
}
}
}
info->last_active = jiffies;
info->jiffies[1] = jiffies;
-#ifdef CYCLOM_ENABLE_MONITORING
+#ifdef CY_ENABLE_MONITORING
info->mon.int_count++;
info->mon.char_count += char_count;
if (char_count > info->mon.char_max)
if( tty == 0){
/* flush received characters */
rx_get = (rx_get + char_count) & (rx_bufsize - 1);
- /* SP("-"); */
info->rflush_count++;
}else{
#ifdef BLOCKMOVE
base_addr = (unsigned char*)
(cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc startup card %d, chip %d, channel %d, base_addr %lx\n",
card, chip, channel, (long)base_addr);/**/
#endif
cy_writeb((ulong)base_addr+(CyMSVR1<<index), CyRTS);
cy_writeb((ulong)base_addr+(CyMSVR2<<index), CyDTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:startup raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
card, channel, (long)base_addr);/**/
#endif
if (retval != 0){
printk("cyc:startup(2) retval was %x\n", retval);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:startup raising Z DTR\n");
#endif
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk(" cyc startup done\n");
#endif
return 0;
(cy_card[card].base_addr
+ (cy_chip_offset[chip]<<index));
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc shutdown Y card %d, chip %d, channel %d, base_addr %lx\n",
card, chip, channel, (long)base_addr);
#endif
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc shutdown dropping DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
int retval;
base_addr = (unsigned char*) (cy_card[card].base_addr);
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
card, channel, (long)base_addr);
#endif
if (retval != 0){
printk("cyc:shutdown retval (2) was %x\n", retval);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:shutdown dropping Z DTR\n");
#endif
}
restore_flags(flags);
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk(" cyc shutdown done\n");
#endif
return;
if (info->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&info->close_wait);
}
- if (info->flags & ASYNC_HUP_NOTIFY){
- return -EAGAIN;
- }else{
- return -ERESTARTSYS;
- }
+ return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
}
/*
*/
retval = 0;
add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
if (!tty_hung_up_p(filp))
info->count--;
restore_flags(flags);
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc block_til_ready: (%d): decrementing count to %d\n",
current->pid, info->count);
#endif
while (1) {
save_flags(flags); cli();
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (tty->termios->c_cflag & CBAUD)){
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:block_til_ready raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp)
|| !(info->flags & ASYNC_INITIALIZED) ){
- if (info->flags & ASYNC_HUP_NOTIFY) {
- retval = -EAGAIN;
- }else{
- retval = -ERESTARTSYS;
- }
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
break;
}
save_flags(flags); cli();
retval = -ERESTARTSYS;
break;
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
if (retval != 0){
printk("cyc:block_til_ready retval was %x\n", retval);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:block_til_ready raising Z DTR\n");
#endif
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp)
|| !(info->flags & ASYNC_INITIALIZED) ){
- if (info->flags & ASYNC_HUP_NOTIFY) {
- retval = -EAGAIN;
- }else{
- retval = -ERESTARTSYS;
- }
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
break;
}
if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
retval = -ERESTARTSYS;
break;
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
remove_wait_queue(&info->open_wait, &wait);
if (!tty_hung_up_p(filp)){
info->count++;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:block_til_ready (%d): incrementing count to %d\n",
current->pid, info->count);
#endif
}
info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
* This routine is called whenever a serial port is opened. It
* performs the serial-specific initialization for the tty structure.
*/
-int
+static int
cy_open(struct tty_struct *tty, struct file * filp)
{
struct cyclades_port *info;
int retval, line;
+ unsigned long page;
line = MINOR(tty->device) - tty->driver.minor_start;
if ((line < 0) || (NR_PORTS <= line)){
(ZFIRM_HLT==cy_readl(&((struct FIRM_ID *)
((cy_card[info->card]).base_addr+ID_ADDRESS))->signature)))
{
- printk ("Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n");
+ printk ("cyc:Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n");
} else {
- printk("Cyclades-Z firmware not yet loaded\n");
+ printk("cyc:Cyclades-Z firmware not yet loaded\n");
}
return -ENODEV;
}
}
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_open ttyC%d\n", info->line); /* */
#endif
if (serial_paranoia_check(info, tty->device, "cy_open")){
return -ENODEV;
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc:cy_open ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
info->count++;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:cy_open (%d): incrementing count to %d\n",
current->pid, info->count);
#endif
tty->driver_data = info;
info->tty = tty;
- /* Some drivers have (incorrect/incomplete) code to test
- against a race condition. Should add good code here!!! */
if (!tmp_buf) {
- tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
- if (!tmp_buf){
- return -ENOMEM;
- }
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+ if (tmp_buf)
+ free_page(page);
+ else
+ tmp_buf = (unsigned char *) page;
}
- if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
- if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
- *tty->termios = info->normal_termios;
- else
- *tty->termios = info->callout_termios;
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+ return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
}
+
/*
* Start up serial port
*/
retval = block_til_ready(tty, filp, info);
if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc:cy_open returning after block_til_ready with %d\n",
retval);
#endif
return retval;
}
+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ }
+
info->session = current->session;
info->pgrp = current->pgrp;
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk(" cyc:cy_open done\n");/**/
#endif
} /* cy_open */
+/*
+ * cy_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+ unsigned char *base_addr;
+ int card,chip,channel,index;
+ unsigned long orig_jiffies, char_time;
+
+ if (serial_paranoia_check(info, tty->device, "cy_wait_until_sent"))
+ return;
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+ char_time = char_time / 5;
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout < 0)
+ timeout = 0;
+ if (timeout)
+ char_time = MIN(char_time, timeout);
+#ifdef CY_DEBUG_WAIT_UNTIL_SENT
+ printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
+ printk("jiff=%lu...", jiffies);
+#endif
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char *)
+ (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ while (cy_readb(base_addr+(CySRER<<index)) & CyTxMpty) {
+#ifdef CY_DEBUG_WAIT_UNTIL_SENT
+ printk("Not clean (jiff=%lu)...", jiffies);
+#endif
+ current->state = TASK_INTERRUPTIBLE;
+ current->counter = 0; /* make us low-priority */
+ current->timeout = jiffies + char_time;
+ schedule();
+ if (signal_pending(current))
+ break;
+ if (timeout && ((orig_jiffies + timeout) < jiffies))
+ break;
+ }
+ current->state = TASK_RUNNING;
+ } else {
+ // Nothing to do!
+ }
+ /* Run one more char cycle */
+ current->state = TASK_INTERRUPTIBLE;
+ current->counter = 0; /* make us low-priority */
+ current->timeout = jiffies + (char_time * 5);
+ schedule();
+ current->state = TASK_RUNNING;
+#ifdef CY_DEBUG_WAIT_UNTIL_SENT
+ printk("Clean (jiff=%lu)...done\n", jiffies);
+#endif
+}
+
/*
* This routine is called when a particular tty device is closed.
*/
struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_close ttyC%d\n", info->line);
#endif
|| serial_paranoia_check(info, tty->device, "cy_close")){
return;
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
#endif
/* If the TTY is being hung up, nothing to do */
if (tty_hung_up_p(filp)) {
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
"info->count is %d\n", info->count);
info->count = 1;
}
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:cy_close at (%d): decrementing count to %d\n",
current->pid, info->count - 1);
#endif
if (--info->count < 0) {
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:cyc_close setting count to 0\n");
#endif
info->count = 0;
}
if (info->count) {
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
- if (info->closing_wait2 != 0) { /* The port's being forced to wait,
- independent on the port settings */
- tty_wait_until_sent(tty, info->closing_wait2*HZ);
- } else {
- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait*HZ);
+ if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
+ tty_wait_until_sent(tty, info->closing_wait);
}
- /* Waiting for on-board buffers to be empty before closing the port */
if (!IS_CYC_Z(cy_card[info->card])) {
-#ifdef NEW_INTR_FLOW
unsigned char *base_addr = (unsigned char *)
cy_card[info->card].base_addr;
int index = cy_card[info->card].bus_index;
-
- if (cy_readb(base_addr+(CySRER<<index)) & CyTxMpty) {
- /* Interrupts are enabled, so go to sleep */
- interruptible_sleep_on(&info->shutdown_wait);
+ /* Stop accepting input */
+ cy_writeb((u_long)base_addr+(CySRER<<index),
+ cy_readb(base_addr+(CySRER<<index)) & ~CyRxData);
+ if (info->flags & ASYNC_INITIALIZED) {
+ /* Waiting for on-board buffers to be empty before closing
+ the port */
+ cy_wait_until_sent(tty, info->timeout);
}
-#endif
} else {
#ifdef Z_WAKE
+ /* Waiting for on-board buffers to be empty before closing the port */
unsigned char *base_addr = (unsigned char *)
cy_card[info->card].base_addr;
struct FIRM_ID *firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk(" cyc:cy_close done\n");
#endif
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
- int c, total = 0;
+ int c, ret = 0;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_write ttyC%d\n", info->line); /* */
#endif
return 0;
}
- if (from_user)
- down(&tmp_buf_sem);
save_flags(flags);
- while (1) {
- cli();
- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0)
- break;
- if (from_user) {
- copy_from_user(tmp_buf, buf, c);
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- } else
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- restore_flags(flags);
- buf += c;
- count -= c;
- total += c;
-#if 0
- SP("CW");
- CP16(c);
- SP(" ");
-#endif
- }
- if (from_user)
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!ret) {
+ ret = -EFAULT;
+ }
+ break;
+ }
+ cli();
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ restore_flags(flags);
+ break;
+ }
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ }
if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
start_xmit(info);
}
- restore_flags(flags);
- return total;
+ return ret;
} /* cy_write */
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_put_char ttyC%d\n", info->line);
#endif
info->xmit_head &= SERIAL_XMIT_SIZE - 1;
info->xmit_cnt++;
restore_flags(flags);
-#if 0
- SP("+");
-#endif
} /* cy_put_char */
unsigned char *base_addr;
int card,chip,channel,index;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
#endif
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
int ret;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
#endif
channel = (info->line) - (cy_card[card].first_line);
if (!IS_CYC_Z(cy_card[card])) {
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
info->line, info->xmit_cnt); /* */
#endif
char_count = tx_put - tx_get;
else
char_count = tx_put - tx_get + tx_bufsize;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
info->line, info->xmit_cnt + char_count); /* */
#endif
int card,chip,channel,index;
unsigned cflag, iflag;
unsigned short chip_number;
+ int baud;
int i;
index = cy_card[card].bus_index;
/* baud rate */
- i = cflag & CBAUD;
-
- if (i & CBAUDEX) {
- if (i == B57600)
- i = 16;
-#ifdef B76800
- else if(i == B76800)
- i = 17;
-#endif
- else if(i == B115200)
- i = 18;
- else if(i == B230400 && (info->chip_rev >= CD1400_REV_J)) {
- /* It is a CD1400 rev. J or later */
- i = 20;
+ baud = tty_get_baud_rate(info->tty);
+ if (baud > CD1400_MAX_SPEED) {
+ baud = CD1400_MAX_SPEED;
+ }
+ /* find the baud index */
+ for (i = 0; i < 20; i++) {
+ if (baud == baud_table[i]) {
+ break;
}
- else
- info->tty->termios->c_cflag &= ~CBAUDEX;
}
+ if (i == 20) {
+ i = 19; /* CD1400_MAX_SPEED */
+ }
+
- if (i == 15) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- i += 1;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- i += 3;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){
- switch(info->baud) {
- case 57600:
- i += 1; break;
-#ifdef B76800
- case 76800:
- i += 2; break;
-#endif
- case 115200:
- i += 3; break;
- case 230400:
- i += 5; break;
- default:
- break;
- }
- }
- }
if(info->chip_rev >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
info->tbpr = baud_bpr_60[i]; /* Tx BPR */
info->rco = baud_co_25[i]; /* Rx CO */
}
if (baud_table[i] == 134) {
- info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+ info->timeout = (info->xmit_fifo_size*HZ*15/269) + 2;
/* get it right for 134.5 baud */
} else if (baud_table[i]) {
info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_line_char dropping DTR\n");
printk(" status: 0x%x,
0x%x\n", cy_readb(base_addr+(CyMSVR1<<index)),
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_line_char raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
/* baud rate */
- switch(i = cflag & CBAUD){
- /*
- case B0: cy_writel(&ch_ctrl->comm_baud , 0); break;
- */
- case B50: cy_writel(&ch_ctrl->comm_baud , 50); break;
- case B75: cy_writel(&ch_ctrl->comm_baud , 75); break;
- case B110: cy_writel(&ch_ctrl->comm_baud , 110); break;
- case B134: cy_writel(&ch_ctrl->comm_baud , 134); break;
- case B150: cy_writel(&ch_ctrl->comm_baud , 150); break;
- case B200: cy_writel(&ch_ctrl->comm_baud , 200); break;
- case B300: cy_writel(&ch_ctrl->comm_baud , 300); break;
- case B600: cy_writel(&ch_ctrl->comm_baud , 600); break;
- case B1200: cy_writel(&ch_ctrl->comm_baud , 1200); break;
- case B1800: cy_writel(&ch_ctrl->comm_baud , 1800); break;
- case B2400: cy_writel(&ch_ctrl->comm_baud , 2400); break;
- case B4800: cy_writel(&ch_ctrl->comm_baud , 4800); break;
- case B9600: cy_writel(&ch_ctrl->comm_baud , 9600); break;
- case B19200: cy_writel(&ch_ctrl->comm_baud , 19200); break;
- case B38400:
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI){
- cy_writel(&ch_ctrl->comm_baud , 57600);
- }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI){
- cy_writel(&ch_ctrl->comm_baud , 115200);
- }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){
- cy_writel(&ch_ctrl->comm_baud , info->baud);
- }else{
- cy_writel(&ch_ctrl->comm_baud , 38400);
- }
- break;
- case B57600: cy_writel(&ch_ctrl->comm_baud , 57600); break;
-#ifdef B76800
- case B76800: cy_writel(&ch_ctrl->comm_baud , 76800); break;
-#endif
- case B115200: cy_writel(&ch_ctrl->comm_baud , 115200); break;
- case B230400: cy_writel(&ch_ctrl->comm_baud , 230400); break;
- case B460800: cy_writel(&ch_ctrl->comm_baud , 460800); break;
+ baud = tty_get_baud_rate(info->tty);
+ if (baud > CD1400_MAX_SPEED) {
+ baud = CD1400_MAX_SPEED;
}
+ cy_writel(&ch_ctrl->comm_baud , baud);
- if ((i = cy_readl(&ch_ctrl->comm_baud)) == 134) {
+ if (baud == 134) {
info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
/* get it right for 134.5 baud */
- } else if (i) {
- info->timeout = (info->xmit_fifo_size*HZ*15/i) + 2;
+ } else if (baud) {
+ info->timeout = (info->xmit_fifo_size*HZ*15/baud) + 2;
/* this needs to be propagated into the card info */
} else {
info->timeout = 0;
cy_readl(&ch_ctrl->sw_flow) & ~C_FL_OXX);
}
- if(i == 0){ /* baud rate is zero, turn off line */
+ if(baud == 0){ /* baud rate is zero, turn off line */
cy_writel(&ch_ctrl->rs_control,
cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_line_char dropping Z DTR\n");
#endif
}else{
cy_writel(&ch_ctrl->rs_control,
cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_line_char raising Z DTR\n");
#endif
}
}
}
+ /*
+ * Set up the tty->alt_speed kludge
+ */
+ if (info->tty) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
+ }
+
+
} /* set_line_char */
struct serial_struct new_serial;
struct cyclades_port old_info;
- 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 (!capable(CAP_SYS_ADMIN)) {
(new_serial.flags & ASYNC_FLAGS));
info->close_delay = new_serial.close_delay * HZ/100;
info->closing_wait = new_serial.closing_wait * HZ/100;
-
check_and_exit:
if (info->flags & ASYNC_INITIALIZED){
}
}
- cy_put_user(result,(unsigned long *) value);
- return 0;
+ return cy_put_user(result,(unsigned long *) value);
} /* get_modem_info */
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info dropping DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info dropping DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
if (arg & TIOCM_DTR){
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising Z DTR\n");
#endif
}
if (arg & TIOCM_DTR){
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info clearing Z DTR\n");
#endif
}
if (arg & TIOCM_DTR){
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising Z DTR\n");
#endif
}else{
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info clearing Z DTR\n");
#endif
}
return 0;
} /* set_modem_info */
-
static void
send_break( struct cyclades_port * info, int duration)
{
}
} /* send_break */
-
static int
get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
{
+ (cy_chip_offset[chip]<<index));
tmp = cy_readb(base_addr+(CyCOR3<<index)) & CyREC_FIFO;
- cy_put_user(tmp,value);
+ return cy_put_user(tmp,value);
} else {
// Nothing to do!
+ return 0;
}
- return 0;
}/* get_threshold */
static int
get_default_threshold(struct cyclades_port * info, unsigned long *value)
{
- cy_put_user(info->default_threshold,value);
- return 0;
+ return cy_put_user(info->default_threshold,value);
}/* get_default_threshold */
+ (cy_chip_offset[chip]<<index));
tmp = cy_readb(base_addr+(CyRTPR<<index));
- cy_put_user(tmp,value);
+ return cy_put_user(tmp,value);
} else {
// Nothing to do!
+ return 0;
}
- return 0;
}/* get_timeout */
static int
get_default_timeout(struct cyclades_port * info, unsigned long *value)
{
- cy_put_user(info->default_timeout,value);
- return 0;
+ return cy_put_user(info->default_timeout,value);
}/* get_default_timeout */
/*
cy_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int error;
struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
int ret_val = 0;
-#ifdef SERIAL_DEBUG_OTHER
+ if (serial_paranoia_check(info, tty->device, "cy_ioctl"))
+ return -ENODEV;
+
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
info->line, cmd, arg); /* */
#endif
switch (cmd) {
case CYGETMON:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(struct cyclades_monitor));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_mon_info(info, (struct cyclades_monitor *)arg);
break;
case CYGETTHRESH:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned long));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_threshold(info, (unsigned long *)arg);
break;
case CYSETTHRESH:
ret_val = set_threshold(info, (unsigned long)arg);
break;
case CYGETDEFTHRESH:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned long));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_default_threshold(info, (unsigned long *)arg);
break;
case CYSETDEFTHRESH:
ret_val = set_default_threshold(info, (unsigned long)arg);
break;
case CYGETTIMEOUT:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned long));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_timeout(info, (unsigned long *)arg);
break;
case CYSETTIMEOUT:
ret_val = set_timeout(info, (unsigned long)arg);
break;
case CYGETDEFTIMEOUT:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned long));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_default_timeout(info, (unsigned long *)arg);
break;
case CYSETDEFTIMEOUT:
ret_val = info->rtsdtr_inv;
break;
case CYGETCARDINFO:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(struct cyclades_card));
- if (error){
- ret_val = error;
- break;
- }
- copy_to_user((void *)arg, (void *)&cy_card[info->card],
- sizeof (struct cyclades_card));
+ if (copy_to_user((void *)arg, (void *)&cy_card[info->card],
+ sizeof (struct cyclades_card))) {
+ ret_val = -EFAULT;
+ }
ret_val = 0;
break;
case CYGETCD1400VER:
ret_val = 0;
break;
case CYSETWAIT:
- info->closing_wait2 = (unsigned short)arg;
+ info->closing_wait = (unsigned short)arg * HZ/100;
ret_val = 0;
break;
case CYGETWAIT:
- ret_val = info->closing_wait2;
+ ret_val = info->closing_wait / (HZ/100);
break;
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- ret_val = tty_check_change(tty);
- if (ret_val)
- return ret_val;
- tty_wait_until_sent(tty,0);
- if (!arg)
- send_break(info, HZ/4); /* 1/4 second */
- break;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- ret_val = tty_check_change(tty);
- if (ret_val)
- return ret_val;
- tty_wait_until_sent(tty,0);
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ return ret_val;
+ tty_wait_until_sent(tty,0);
+ if (!arg)
+ send_break(info, HZ/4); /* 1/4 second */
+ break;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ return ret_val;
+ tty_wait_until_sent(tty,0);
+ send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ break;
+ case TIOCMGET:
+ ret_val = get_modem_info(info, (unsigned int *) arg);
break;
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
ret_val = set_modem_info(info, cmd, (unsigned int *) arg);
break;
-
-/* The following commands are incompletely implemented!!! */
- case TIOCGSOFTCAR:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned int *));
- if (error){
- ret_val = error;
- break;
- }
- cy_put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long *) arg);
- break;
- case TIOCSSOFTCAR:
- error = verify_area(VERIFY_READ, (void *) arg
- ,sizeof(unsigned long *));
- if (error) {
- ret_val = error;
- break;
- }
-
- arg = cy_get_user((unsigned long *) arg);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- break;
- case TIOCMGET:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned int *));
- if (error){
- ret_val = error;
- break;
- }
- ret_val = get_modem_info(info, (unsigned int *) arg);
- break;
case TIOCGSERIAL:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(struct serial_struct));
- if (error){
- ret_val = error;
- break;
- }
- ret_val = get_serial_info(info,
- (struct serial_struct *) arg);
+ ret_val = get_serial_info(info, (struct serial_struct *) arg);
break;
case TIOCSSERIAL:
- error = verify_area(VERIFY_READ, (void *) arg
- ,sizeof(struct serial_struct));
- if (error){
- ret_val = error;
- break;
- }
- ret_val = set_serial_info(info,
- (struct serial_struct *) arg);
+ ret_val = set_serial_info(info, (struct serial_struct *) arg);
break;
default:
ret_val = -ENOIOCTLCMD;
}
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk(" cyc:cy_ioctl done\n");
#endif
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_set_termios ttyC%d\n", info->line);
#endif
unsigned char *base_addr;
int card,chip,channel,index;
-#ifdef SERIAL_DEBUG_THROTTLE
+#ifdef CY_DEBUG_THROTTLE
char buf[64];
printk("cyc:throttle %s: %d....ttyC%d\n",
unsigned char *base_addr;
int card,chip,channel,index;
-#ifdef SERIAL_DEBUG_THROTTLE
+#ifdef CY_DEBUG_THROTTLE
char buf[64];
printk("cyc:unthrottle %s: %d....ttyC%d\n",
int chip,channel,index;
unsigned long flags;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_stop ttyC%d\n", info->line); /* */
#endif
int chip,channel,index;
unsigned long flags;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_start ttyC%d\n", info->line); /* */
#endif
int card, channel;
unsigned long flags;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
#endif
{
struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
#endif
shutdown(info);
info->event = 0;
info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
#endif
info->tty = 0;
{
#ifdef CONFIG_PCI
-#ifdef NEW_PCI
struct pci_dev *pdev = NULL;
unsigned char cyy_rev_id;
-#else
- unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id;
-#endif
unsigned long pci_intr_ctrl;
- unsigned char cy_pci_irq;
+ unsigned char cy_pci_irq = 0;
uclong cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
unsigned short i,j,cy_pci_nchan;
unsigned short device_id,dev_index = 0;
-#ifndef NEW_PCI
- unsigned short board_index = 0;
-#endif
uclong mailbox;
uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
-#ifdef NEW_PCI
if(pci_present() == 0) { /* PCI bus not present */
-#else
- if(pcibios_present() == 0) { /* PCI bus not present */
-#endif
return(0);
}
for (i = 0; i < NR_CARDS; i++) {
/* look for a Cyclades card by vendor and device id */
while((device_id = cy_pci_dev_id[dev_index]) != 0) {
-#ifdef NEW_PCI
if((pdev = pci_find_device(PCI_VENDOR_ID_CYCLADES,
device_id, pdev)) == NULL) {
dev_index++; /* try next device id */
} else {
break; /* found a board */
}
-#else
- if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
- device_id,board_index,
- &cyy_bus, &cyy_dev_fn) != 0) {
- dev_index++; /* try next device id */
- board_index = 0;
- } else {
- board_index++;
- break; /* found a board */
- }
-#endif
}
if (device_id == 0)
break;
/* read PCI configuration area */
-#ifdef NEW_PCI
cy_pci_irq = pdev->irq;
cy_pci_addr0 = pdev->base_address[0];
cy_pci_addr1 = pdev->base_address[1];
cy_pci_addr2 = pdev->base_address[2];
pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
-#else
- pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
- PCI_INTERRUPT_LINE, &cy_pci_irq);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_0,
- (unsigned int *) &cy_pci_addr0);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_1,
- (unsigned int *) &cy_pci_addr1);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_2,
- (unsigned int *) &cy_pci_addr2);
- pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
- PCI_REVISION_ID, &cyy_rev_id);
-#endif
if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
|| (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
#ifdef CY_PCI_DEBUG
printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
-#ifdef NEW_PCI
pdev->bus->number, pdev->devfn);
-#else
- cyy_bus, cyy_dev_fn);
-#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclom-Y/PCI:found winaddr=0x%lx ioaddr=0x%lx\n",
#if defined(__alpha__)
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
-#ifdef NEW_PCI
pdev->bus->number, pdev->devfn);
-#else
- cyy_bus, cyy_dev_fn);
-#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclom-Y/PCI:found winaddr=0x%lx ioaddr=0x%lx\n",
}else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
/* print message */
printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
-#ifdef NEW_PCI
pdev->bus->number, pdev->devfn);
-#else
- cyy_bus, cyy_dev_fn);
-#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
}else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
#ifdef CY_PCI_DEBUG
printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
-#ifdef NEW_PCI
pdev->bus->number, pdev->devfn);
-#else
- cyy_bus, cyy_dev_fn);
-#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
memset(&cy_serial_driver, 0, sizeof(struct tty_driver));
cy_serial_driver.magic = TTY_DRIVER_MAGIC;
+ cy_serial_driver.name = "cyclades";
cy_serial_driver.name = "ttyC";
cy_serial_driver.major = CYCLADES_MAJOR;
cy_serial_driver.minor_start = 0;
cy_serial_driver.stop = cy_stop;
cy_serial_driver.start = cy_start;
cy_serial_driver.hangup = cy_hangup;
+ cy_serial_driver.wait_until_sent = cy_wait_until_sent;
/*
* The callout device is just like normal device except for
cy_callout_driver.name = "cub";
cy_callout_driver.major = CYCLADESAUX_MAJOR;
cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+ cy_callout_driver.read_proc = 0;
+ cy_callout_driver.proc_entry = 0;
+
if (tty_register_driver(&cy_serial_driver))
panic("Couldn't register Cyclades serial driver\n");
init_bh(CYCLADES_BH, do_cyclades_bh);
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < NR_IRQS; i++) {
IRQ_cards[i] = 0;
}
info->rco = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = CLOSING_WAIT_DELAY;
- info->closing_wait2 = 0;
info->x_char = 0;
info->event = 0;
info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
// printk("cyc:cy_init(1) setting Z count to 0\n");
#endif
info->blocked_open = 0;
info->cor5 = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = CLOSING_WAIT_DELAY;
- info->closing_wait2 = 0;
chip_number = (port - cinfo->first_line) / 4;
if ((info->chip_rev = cy_readb(cinfo->base_addr +
(cy_chip_offset[chip_number]<<index) +
info->x_char = 0;
info->event = 0;
info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
// printk("cyc:cy_init(2) setting Y count to 0\n");
#endif
info->blocked_open = 0;
register unsigned long int timeslip = (jiffies - dev->time);
if ((timeslip > dev->timeslice) && (dev->port->waithead != NULL)) {
lp_parport_release(minor);
+ lp_table[minor].irq_missed = 1;
schedule ();
lp_parport_claim(minor);
} else
/*
* random.c -- A strong random number generator
*
- * Version 1.03, last modified 26-Apr-97
+ * Version 1.04, last modified 26-Apr-98
*
- * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997. All rights reserved.
+ * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998. All rights
+ * reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* an *estimate* of how many bits of randomness have been stored into
* the random number generator's internal state.
*
- * When random bytes are desired, they are obtained by taking the MD5
- * hash of the contents of the "entropy pool". The MD5 hash avoids
+ * When random bytes are desired, they are obtained by taking the SHA
+ * hash of the contents of the "entropy pool". The SHA hash avoids
* exposing the internal state of the entropy pool. It is believed to
* be computationally infeasible to derive any useful information
- * about the input of MD5 from its output. Even if it is possible to
- * analyze MD5 in some clever way, as long as the amount of data
+ * about the input of SHA from its output. Even if it is possible to
+ * analyze SHA in some clever way, as long as the amount of data
* returned from the generator is less than the inherent entropy in
* the pool, the output data is totally unpredictable. For this
* reason, the routine decreases its internal estimate of how many
* If this estimate goes to zero, the routine can still generate
* random numbers; however, an attacker may (at least in theory) be
* able to infer the future output of the generator from prior
- * outputs. This requires successful cryptanalysis of MD5, which is
+ * outputs. This requires successful cryptanalysis of SHA, which is
* not believed to be feasible, but there is a remote possibility.
* Nonetheless, these numbers should be useful for the vast majority
* of purposes.
* sequence:
*
* echo "Initializing random number generator..."
+ * random_seed=/var/run/random-seed
* # Carry a random seed from start-up to start-up
* # Load and then save 512 bytes, which is the size of the entropy pool
- * if [ -f /etc/random-seed ]; then
- * cat /etc/random-seed >/dev/urandom
+ * if [ -f $random_seed ]; then
+ * cat $random_seed >/dev/urandom
* fi
- * dd if=/dev/urandom of=/etc/random-seed count=1
+ * dd if=/dev/urandom of=$random_seed count=1
+ * chmod 600 $random_seed
*
* and the following lines in an appropriate script which is run as
* the system is shutdown:
* # Carry a random seed from shut-down to start-up
* # Save 512 bytes, which is the size of the entropy pool
* echo "Saving random seed..."
- * dd if=/dev/urandom of=/etc/random-seed count=1
+ * random_seed=/var/run/random-seed
+ * dd if=/dev/urandom of=$random_seed count=1
+ * chmod 600 $random_seed
*
- * For example, on many Linux systems, the appropriate scripts are
- * usually /etc/rc.d/rc.local and /etc/rc.d/rc.0, respectively.
+ * For example, on most modern systems using the System V init
+ * scripts, such code fragments would be found in
+ * /etc/rc.d/init.d/random. On older Linux systems, the correct script
+ * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0.
*
* Effectively, these commands cause the contents of the entropy pool
* to be saved at shut-down time and reloaded into the entropy pool at
* =================
*
* Ideas for constructing this random number generator were derived
- * from the Pretty Good Privacy's random number generator, and from
- * private discussions with Phil Karn. Colin Plumb provided a faster
- * random number generator, which speed up the mixing function of the
- * entropy pool, taken from PGP 3.0 (under development). It has since
- * been modified by myself to provide better mixing in the case where
- * the input values to add_entropy_word() are mostly small numbers.
- * Dale Worley has also contributed many useful ideas and suggestions
- * to improve this driver.
+ * from Pretty Good Privacy's random number generator, and from private
+ * discussions with Phil Karn. Colin Plumb provided a faster random
+ * number generator, which speed up the mixing function of the entropy
+ * pool, taken from PGPfone. Dale Worley has also contributed many
+ * useful ideas and suggestions to improve this driver.
*
* Any flaws in the design are solely my responsibility, and should
* not be attributed to the Phil, Colin, or any of authors of PGP.
*
+ * The code for SHA transform was taken from Peter Gutmann's
+ * implementation, which has been placed in the public domain.
* The code for MD5 transform was taken from Colin Plumb's
* implementation, which has been placed in the public domain. The
* MD5 cryptographic checksum was devised by Ronald Rivest, and is
*/
#undef RANDOM_BENCHMARK
#undef BENCHMARK_NOINT
+#define ROTATE_PARANOIA
-/*
- * The pool is stirred with a primitive polynomial of degree 128
- * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
- * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
- */
#define POOLWORDS 128 /* Power of 2 - note that this is 32-bit words */
#define POOLBITS (POOLWORDS*32)
-#if POOLWORDS == 128
-#define TAP1 99 /* The polynomial taps */
-#define TAP2 59
-#define TAP3 31
-#define TAP4 9
-#define TAP5 7
-#elif POOLWORDS == 64
-#define TAP1 62 /* The polynomial taps */
-#define TAP2 38
-#define TAP3 10
-#define TAP4 6
-#define TAP5 1
+/*
+ * The pool is stirred with a primitive polynomial of degree POOLWORDS
+ * over GF(2). The taps for various sizes are defined below. They are
+ * chosen to be evenly spaced (minimum RMS distance from evenly spaced;
+ * the numbers in the comments are a scaled squared error sum) except
+ * for the last tap, which is 1 to get the twisting happening as fast
+ * as possible.
+ */
+#if POOLWORDS == 2048 /* 115 x^2048+x^1638+x^1231+x^819+x^411+x^1+1 */
+#define TAP1 1638
+#define TAP2 1231
+#define TAP3 819
+#define TAP4 411
+#define TAP5 1
+#elif POOLWORDS == 1024 /* 290 x^1024+x^817+x^615+x^412+x^204+x^1+1 */
+/* Alt: 115 x^1024+x^819+x^616+x^410+x^207+x^2+1 */
+#define TAP1 817
+#define TAP2 615
+#define TAP3 412
+#define TAP4 204
+#define TAP5 1
+#elif POOLWORDS == 512 /* 225 x^512+x^411+x^308+x^208+x^104+x+1 */
+/* Alt: 95 x^512+x^409+x^307+x^206+x^102+x^2+1
+ * 95 x^512+x^409+x^309+x^205+x^103+x^2+1 */
+#define TAP1 411
+#define TAP2 308
+#define TAP3 208
+#define TAP4 104
+#define TAP5 1
+#elif POOLWORDS == 256 /* 125 x^256+x^205+x^155+x^101+x^52+x+1 */
+#define TAP1 205
+#define TAP2 155
+#define TAP3 101
+#define TAP4 52
+#define TAP5 1
+#elif POOLWORDS == 128 /* 105 x^128+x^103+x^76+x^51+x^25+x+1 */
+/* Alt: 70 x^128+x^103+x^78+x^51+x^27+x^2+1 */
+#define TAP1 103
+#define TAP2 76
+#define TAP3 51
+#define TAP4 25
+#define TAP5 1
+#elif POOLWORDS == 64 /* 15 x^64+x^52+x^39+x^26+x^14+x+1 */
+#define TAP1 52
+#define TAP2 39
+#define TAP3 26
+#define TAP4 14
+#define TAP5 1
+#elif POOLWORDS == 32 /* 15 x^32+x^26+x^20+x^14+x^7+x^1+1 */
+#define TAP1 26
+#define TAP2 20
+#define TAP3 14
+#define TAP4 7
+#define TAP5 1
+#elif POOLWORDS & (POOLWORDS-1)
+#error POOLWORDS must be a power of 2
#else
#error No primitive polynomial available for chosen POOLWORDS
#endif
* Also see M. Matsumoto & Y. Kurita, 1994. Twisted GFSR generators
* II. ACM Transactions on Mdeling and Computer Simulation 4:254-266)
*
- * Thanks to Colin Plumb for suggesting this. (Note that the behavior
- * of the 1.0 version of the driver was equivalent to using a second
- * element of 0x80000000).
+ * Thanks to Colin Plumb for suggesting this.
+ * We have not analyzed the resultant polynomial to prove it primitive;
+ * in fact it almost certainly isn't. Nonetheless, the irreducible factors
+ * of a random large-degree polynomial over GF(2) are more than large enough
+ * that periodicity is not a concern.
+ *
+ * The input hash is much less sensitive than the output hash. All that
+ * we want of it is that it be a good non-cryptographic hash; i.e. it
+ * not produce collisions when fed "random" data of the sort we expect
+ * to see. As long as the pool state differs for different inputs, we
+ * have preserved the input entropy and done a good job. The fact that an
+ * intelligent attacker can construct inputs that will produce controlled
+ * alterations to the pool's state is not important because we don't
+ * consider such inputs to contribute any randomness.
+ * The only property we need with respect to them is
+ * that the attacker can't increase his/her knowledge of the pool's state.
+ * Since all additions are reversible (knowing the final state and the
+ * input, you can reconstruct the initial state), if an attacker has
+ * any uncertainty about the initial state, he/she can only shuffle that
+ * uncertainty about, but never cause any collisions (which would
+ * decrease the uncertainty).
+ *
+ * The chosen system lets the state of the pool be (essentially) the input
+ * modulo the generator polymnomial. Now, for random primitive polynomials,
+ * this is a universal class of hash functions, meaning that the chance
+ * of a collision is limited by the attacker's knowledge of the generator
+ * polynomail, so if it is chosen at random, an attacker can never force
+ * a collision. Here, we use a fixed polynomial, but we *can* assume that
+ * ###--> it is unknown to the processes generating the input entropy. <-###
+ * Because of this important property, this is a good, collision-resistant
+ * hash; hash collisions will occur no more often than chance.
*/
-static __u32 twist_table[2] = { 0, 0xEDB88320 };
/*
* The minimum number of bits to release a "wait on input". Should
struct random_bucket {
unsigned add_ptr;
unsigned entropy_count;
+#ifdef ROTATE_PARANOIA
int input_rotate;
+#endif
__u32 pool[POOLWORDS];
};
/* There is one of these per entropy source */
struct timer_rand_state {
- unsigned long last_time;
- int last_delta,last_delta2;
+ __u32 last_time;
+ __s32 last_delta,last_delta2;
int dont_count_entropy:1;
};
static int random_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
-static inline void fast_add_entropy_word(struct random_bucket *r,
- const __u32 input);
+static inline void fast_add_entropy_words(struct random_bucket *r,
+ __u32 x, __u32 y);
-static void add_entropy_word(struct random_bucket *r,
- const __u32 input);
+static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y);
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
* More asm magic....
*
* For entropy estimation, we need to do an integral base 2
- * logarithm. By default, use an open-coded C version, although we do
- * have a version which takes advantage of the Intel's x86's "bsr"
- * instruction.
+ * logarithm.
+ *
+ * Note the "12bits" suffix - this is used for numbers between
+ * 0 and 4095 only. This allows a few shortcuts.
*/
-#if (!defined (__i386__))
-static inline __u32 int_ln(__u32 word)
+#if 0 /* Slow but clear version */
+static inline __u32 int_ln_12bits(__u32 word)
{
__u32 nbits = 0;
- while (1) {
- word >>= 1;
- if (!word)
- break;
+ while (word >>= 1)
nbits++;
- }
return nbits;
}
-#else
-static inline __u32 int_ln(__u32 word)
+#else /* Faster (more clever) version, courtesy Colin Plumb */
+static inline __u32 int_ln_12bits(__u32 word)
{
- __asm__("bsrl %1,%0\n\t"
- "jnz 1f\n\t"
- "movl $0,%0\n"
- "1:"
- :"=r" (word)
- :"r" (word));
- return word;
+ /* Smear msbit right to make an n-bit mask */
+ word |= word >> 8;
+ word |= word >> 4;
+ word |= word >> 2;
+ word |= word >> 1;
+ /* Remove one bit to make this a logarithm */
+ word >>= 1;
+ /* Count the bits set in the word */
+ word -= (word >> 1) & 0x555;
+ word = (word & 0x333) + ((word >> 2) & 0x333);
+ word += (word >> 4);
+ word += (word >> 8);
+ return word & 15;
}
#endif
*/
static void init_std_data(struct random_bucket *r)
{
- __u32 word, *p;
+ __u32 words[2], *p;
int i;
struct timeval tv;
do_gettimeofday(&tv);
- add_entropy_word(r, tv.tv_sec);
- add_entropy_word(r, tv.tv_usec);
-
- for (p = (__u32 *) &system_utsname,
- i = sizeof(system_utsname) / sizeof(__u32);
- i ; i--, p++) {
- memcpy(&word, p, sizeof(__u32));
- add_entropy_word(r, word);
+ add_entropy_words(r, tv.tv_sec, tv.tv_usec);
+
+ p = (__u32 *)&system_utsname;
+ for (i = sizeof(system_utsname) / sizeof(words); i; i--) {
+ memcpy(words, p, sizeof(words));
+ add_entropy_words(r, words[0], words[1]);
+ p += sizeof(words)/sizeof(*words);
}
}
* This function adds a byte into the entropy "pool". It does not
* update the entropy estimate. The caller must do this if appropriate.
*
- * The pool is stirred with a primitive polynomial of degree 128
- * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
- * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
- *
- * We rotate the input word by a changing number of bits, to help
- * assure that all bits in the entropy get toggled. Otherwise, if we
- * consistently feed the entropy pool small numbers (like jiffies and
- * scancodes, for example), the upper bits of the entropy pool don't
- * get affected. --- TYT, 10/11/95
+ * This function is tuned for speed above most other considerations.
+ *
+ * The pool is stirred with a primitive polynomial of the appropriate degree,
+ * and then twisted. We twist by three bits at a time because it's
+ * cheap to do so and helps slightly in the expected case where the
+ * entropy is concentrated in the low-order bits.
*/
-static inline void fast_add_entropy_word(struct random_bucket *r,
- const __u32 input)
+#define MASK(x) ((x) & (POOLWORDS-1)) /* Convenient abreviation */
+static inline void fast_add_entropy_words(struct random_bucket *r,
+ __u32 x, __u32 y)
{
- unsigned i;
- int new_rotate;
- __u32 w;
+ static __u32 const twist_table[8] = {
+ 0, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+ 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
+ unsigned i, j;
+
+ i = MASK(r->add_ptr - 2); /* i is always even */
+ r->add_ptr = i;
+
+#ifdef ROTATE_PARANOIA
+ j = r->input_rotate + 14;
+ if (i)
+ j -= 7;
+ r->input_rotate = j & 31;
+
+ x = rotate_left(r->input_rotate, x);
+ y = rotate_left(r->input_rotate, y);
+#endif
/*
- * Normally, we add 7 bits of rotation to the pool. At the
- * beginning of the pool, add an extra 7 bits rotation, so
- * that successive passes spread the input bits across the
- * pool evenly.
+ * XOR in the various taps. Even though logically, we compute
+ * x and then compute y, we read in y then x order because most
+ * caches work slightly better with increasing read addresses.
+ * If a tap is even then we can use the fact that i is even to
+ * avoid a masking operation. Every polynomial has at least one
+ * even tap, so j is always used.
+ * (Is there a nicer way to arrange this code?)
*/
- new_rotate = r->input_rotate + 14;
- if ((i = r->add_ptr--))
- new_rotate -= 7;
- r->input_rotate = new_rotate & 31;
-
- w = rotate_left(r->input_rotate, input);
-
- /* XOR in the various taps */
- w ^= r->pool[(i+TAP1)&(POOLWORDS-1)];
- w ^= r->pool[(i+TAP2)&(POOLWORDS-1)];
- w ^= r->pool[(i+TAP3)&(POOLWORDS-1)];
- w ^= r->pool[(i+TAP4)&(POOLWORDS-1)];
- w ^= r->pool[(i+TAP5)&(POOLWORDS-1)];
- w ^= r->pool[i&(POOLWORDS-1)];
- /* Use a twisted GFSR for the mixing operation */
- r->pool[i&(POOLWORDS-1)] = (w >> 1) ^ twist_table[w & 1];
+#if TAP1 & 1
+ y ^= r->pool[MASK(i+TAP1)]; x ^= r->pool[MASK(i+TAP1+1)];
+#else
+ j = MASK(i+TAP1); y ^= r->pool[j]; x ^= r->pool[j+1];
+#endif
+#if TAP2 & 1
+ y ^= r->pool[MASK(i+TAP2)]; x ^= r->pool[MASK(i+TAP2+1)];
+#else
+ j = MASK(i+TAP2); y ^= r->pool[j]; x ^= r->pool[j+1];
+#endif
+#if TAP3 & 1
+ y ^= r->pool[MASK(i+TAP3)]; x ^= r->pool[MASK(i+TAP3+1)];
+#else
+ j = MASK(i+TAP3); y ^= r->pool[j]; x ^= r->pool[j+1];
+#endif
+#if TAP4 & 1
+ y ^= r->pool[MASK(i+TAP4)]; x ^= r->pool[MASK(i+TAP4+1)];
+#else
+ j = MASK(i+TAP4); y ^= r->pool[j]; x ^= r->pool[j+1];
+#endif
+#if TAP5 == 1
+ /* We need to pretend to write pool[i+1] before computing y */
+ y ^= r->pool[i];
+ x ^= r->pool[i+1];
+ x ^= r->pool[MASK(i+TAP5+1)];
+ y ^= r->pool[i+1] = x = (x >> 3) ^ twist_table[x & 7];
+ r->pool[i] = (y >> 3) ^ twist_table[y & 7];
+#else
+# if TAP5 & 1
+ y ^= r->pool[MASK(i+TAP5)]; x ^= r->pool[MASK(i+TAP5+1)];
+# else
+ j = MASK(i+TAP5); y ^= r->pool[j]; x ^= r->pool[j+1];
+# endif
+ y ^= r->pool[i];
+ x ^= r->pool[i+1];
+ r->pool[i] = (y >> 3) ^ twist_table[y & 7];
+ r->pool[i+1] = (x >> 3) ^ twist_table[x & 7];
+#endif
}
/*
* For places where we don't need the inlined version
*/
-static void add_entropy_word(struct random_bucket *r,
- const __u32 input)
+static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y)
{
- fast_add_entropy_word(r, input);
+ fast_add_entropy_words(r, x, y);
}
/*
static void add_timer_randomness(struct random_bucket *r,
struct timer_rand_state *state, unsigned num)
{
- int delta, delta2, delta3;
__u32 time;
+ __s32 delta, delta2, delta3;
#ifdef RANDOM_BENCHMARK
begin_benchmark(&timer_benchmark);
#endif
#if defined (__i386__)
if (boot_cpu_data.x86_capability & 16) {
- unsigned long low, high;
+ __u32 high;
__asm__(".byte 0x0f,0x31"
- :"=a" (low), "=d" (high));
- time = (__u32) low;
- num ^= (__u32) high;
+ :"=a" (time), "=d" (high));
+ num ^= high;
} else {
time = jiffies;
}
time = jiffies;
#endif
- fast_add_entropy_word(r, (__u32) num);
- fast_add_entropy_word(r, time);
+ fast_add_entropy_words(r, (__u32)num, time);
/*
- * Calculate number of bits of randomness we probably
- * added. We take into account the first and second order
- * deltas in order to make our estimate.
+ * Calculate number of bits of randomness we probably added.
+ * We take into account the first, second and third-order deltas
+ * in order to make our estimate.
*/
- if (!state->dont_count_entropy &&
- (r->entropy_count < POOLBITS)) {
+ if ((r->entropy_count < POOLBITS) && !state->dont_count_entropy) {
delta = time - state->last_time;
state->last_time = time;
- if (delta < 0) delta = -delta;
delta2 = delta - state->last_delta;
state->last_delta = delta;
- if (delta2 < 0) delta2 = -delta2;
delta3 = delta2 - state->last_delta2;
state->last_delta2 = delta2;
- if (delta3 < 0) delta3 = -delta3;
- delta = MIN(MIN(delta, delta2), delta3) >> 1;
- /* Limit entropy estimate to 12 bits */
+ if (delta < 0)
+ delta = -delta;
+ if (delta2 < 0)
+ delta2 = -delta2;
+ if (delta3 < 0)
+ delta3 = -delta3;
+ if (delta > delta2)
+ delta = delta2;
+ if (delta > delta3)
+ delta = delta3;
+
+ /*
+ * delta is now minimum absolute delta.
+ * Round down by 1 bit on general principles,
+ * and limit entropy entimate to 12 bits.
+ */
+ delta >>= 1;
delta &= (1 << 12) - 1;
- r->entropy_count += int_ln(delta);
+ r->entropy_count += int_ln_12bits(delta);
/* Prevent overflow */
if (r->entropy_count > POOLBITS)
r->entropy_count = POOLBITS;
+
+ /* Wake up waiting processes, if we have enough entropy. */
+ if (r->entropy_count >= WAIT_INPUT_BITS)
+ wake_up_interruptible(&random_read_wait);
}
- /* Wake up waiting processes, if we have enough entropy. */
- if (r->entropy_count >= WAIT_INPUT_BITS)
- wake_up_interruptible(&random_read_wait);
#ifdef RANDOM_BENCHMARK
end_benchmark(&timer_benchmark);
#endif
0x200+major);
}
+/*
+ * This chunk of code defines a function
+ * void HASH_TRANSFORM(__u32 digest[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE],
+ * __u32 const data[16])
+ *
+ * The function hashes the input data to produce a digest in the first
+ * HASH_BUFFER_SIZE words of the digest[] array, and uses HASH_EXTRA_SIZE
+ * more words for internal purposes. (This buffer is exported so the
+ * caller can wipe it once rather than this code doing it each call,
+ * and tacking it onto the end of the digest[] array is the quick and
+ * dirty way of doing it.)
+ *
+ * It so happens that MD5 and SHA share most of the initial vector
+ * used to initialize the digest[] array before the first call:
+ * 1) 0x67452301
+ * 2) 0xefcdab89
+ * 3) 0x98badcfe
+ * 4) 0x10325476
+ * 5) 0xc3d2e1f0 (SHA only)
+ *
+ * For /dev/random purposes, the length of the data being hashed is
+ * fixed in length (at POOLWORDS words), so appending a bit count in
+ * the usual way is not cryptographically necessary.
+ */
#define USE_SHA
#ifdef USE_SHA
-#define SMALL_VERSION /* Optimize for space over time */
-
#define HASH_BUFFER_SIZE 5
+#define HASH_EXTRA_SIZE 80
#define HASH_TRANSFORM SHATransform
+/* Various size/speed tradeoffs are available. Choose 0..3. */
+#define SHA_CODE_SIZE 0
+
/*
- * SHA transform algorithm, taken from code written by Peter Gutman,
- * and apparently in the public domain.
+ * SHA transform algorithm, taken from code written by Peter Gutmann,
+ * and placed in the public domain.
*/
/* The SHA f()-functions. */
-#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */
-#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */
-#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */
-#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */
+#define f1(x,y,z) ( z ^ (x & (y^z)) ) /* Rounds 0-19: x ? y : z */
+#define f2(x,y,z) (x ^ y ^ z) /* Rounds 20-39: XOR */
+#define f3(x,y,z) ( (x & y) + (z & (x ^ y)) ) /* Rounds 40-59: majority */
+#define f4(x,y,z) (x ^ y ^ z) /* Rounds 60-79: XOR */
/* The SHA Mysterious Constants */
-#define K1 0x5A827999L /* Rounds 0-19 */
-#define K2 0x6ED9EBA1L /* Rounds 20-39 */
-#define K3 0x8F1BBCDCL /* Rounds 40-59 */
-#define K4 0xCA62C1D6L /* Rounds 60-79 */
+#define K1 0x5A827999L /* Rounds 0-19: sqrt(2) * 2^30 */
+#define K2 0x6ED9EBA1L /* Rounds 20-39: sqrt(3) * 2^30 */
+#define K3 0x8F1BBCDCL /* Rounds 40-59: sqrt(5) * 2^30 */
+#define K4 0xCA62C1D6L /* Rounds 60-79: sqrt(10) * 2^30 */
#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
-#define expand(W,i) ( W[ i & 15 ] = \
- ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
- W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) )
-
#define subRound(a, b, c, d, e, f, k, data) \
( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )
-static void SHATransform(__u32 *digest, __u32 *data)
- {
+static void SHATransform(__u32 digest[85], __u32 const data[16])
+{
__u32 A, B, C, D, E; /* Local vars */
- __u32 eData[ 16 ]; /* Expanded data */
-#ifdef SMALL_VERSION
- int i;
__u32 TEMP;
-#endif
+ int i;
+#define W (digest + HASH_BUFFER_SIZE) /* Expanded data array */
+
+ /*
+ * Do the preliminary expansion of 16 to 80 words. Doing it
+ * out-of-line line this is faster than doing it in-line on
+ * register-starved machines like the x86, and not really any
+ * slower on real processors.
+ */
+ memcpy(W, data, 16*sizeof(__u32));
+ for (i = 0; i < 64; i++) {
+ TEMP = W[i] ^ W[i+2] ^ W[i+8] ^ W[i+13];
+ W[i+16] = ROTL(1, TEMP);
+ }
/* Set up first buffer and local data buffer */
A = digest[ 0 ];
C = digest[ 2 ];
D = digest[ 3 ];
E = digest[ 4 ];
- memcpy( eData, data, 16*sizeof(__u32));
-#ifdef SMALL_VERSION
+ /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
+#if SHA_CODE_SIZE == 0
/*
- * Approximately 50% of the speed of the optimized version, but
+ * Approximately 50% of the speed of the largest version, but
* takes up 1/16 the space. Saves about 6k on an i386 kernel.
*/
- for (i=0; i < 80; i++) {
+ for (i = 0; i < 80; i++) {
+ if (i < 40) {
if (i < 20)
- TEMP = f1(B, C, D) + K1;
- else if (i < 40)
- TEMP = f2(B, C, D) + K2;
- else if (i < 60)
- TEMP = f3(B, C, D) + K3;
+ TEMP = f1(B, C, D) + K1;
else
- TEMP = f4(B, C, D) + K4;
- TEMP += ROTL (5, A) + E +
- ((i > 15) ? expand(eData, i) : eData[i]);
- E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ TEMP = f2(B, C, D) + K2;
+ } else {
+ if (i < 60)
+ TEMP = f3(B, C, D) + K3;
+ else
+ TEMP = f4(B, C, D) + K4;
+ }
+ TEMP += ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ }
+#elif SHA_CODE_SIZE == 1
+ for (i = 0; i < 20; i++) {
+ TEMP = f1(B, C, D) + K1 + ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
}
+ for (; i < 40; i++) {
+ TEMP = f2(B, C, D) + K2 + ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ }
+ for (; i < 60; i++) {
+ TEMP = f3(B, C, D) + K3 + ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ }
+ for (; i < 80; i++) {
+ TEMP = f4(B, C, D) + K4 + ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ }
+#elif SHA_CODE_SIZE == 2
+ for (i = 0; i < 20; i += 5) {
+ subRound( A, B, C, D, E, f1, K1, W[ i ] );
+ subRound( E, A, B, C, D, f1, K1, W[ i+1 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ i+2 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ i+3 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ i+4 ] );
+ }
+ for (; i < 40; i += 5) {
+ subRound( A, B, C, D, E, f2, K2, W[ i ] );
+ subRound( E, A, B, C, D, f2, K2, W[ i+1 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ i+2 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ i+3 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ i+4 ] );
+ }
+ for (; i < 60; i += 5) {
+ subRound( A, B, C, D, E, f3, K3, W[ i ] );
+ subRound( E, A, B, C, D, f3, K3, W[ i+1 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ i+2 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ i+3 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ i+4 ] );
+ }
+ for (; i < 80; i += 5) {
+ subRound( A, B, C, D, E, f4, K4, W[ i ] );
+ subRound( E, A, B, C, D, f4, K4, W[ i+1 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ i+2 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ i+3 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ i+4 ] );
+ }
+#elif SHA_CODE_SIZE == 3 /* Really large version */
+ subRound( A, B, C, D, E, f1, K1, W[ 0 ] );
+ subRound( E, A, B, C, D, f1, K1, W[ 1 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ 2 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ 3 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ 4 ] );
+ subRound( A, B, C, D, E, f1, K1, W[ 5 ] );
+ subRound( E, A, B, C, D, f1, K1, W[ 6 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ 7 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ 8 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ 9 ] );
+ subRound( A, B, C, D, E, f1, K1, W[ 10 ] );
+ subRound( E, A, B, C, D, f1, K1, W[ 11 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ 12 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ 13 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ 14 ] );
+ subRound( A, B, C, D, E, f1, K1, W[ 15 ] );
+ subRound( E, A, B, C, D, f1, K1, W[ 16 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ 17 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ 18 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ 19 ] );
+
+ subRound( A, B, C, D, E, f2, K2, W[ 20 ] );
+ subRound( E, A, B, C, D, f2, K2, W[ 21 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ 22 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ 23 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ 24 ] );
+ subRound( A, B, C, D, E, f2, K2, W[ 25 ] );
+ subRound( E, A, B, C, D, f2, K2, W[ 26 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ 27 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ 28 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ 29 ] );
+ subRound( A, B, C, D, E, f2, K2, W[ 30 ] );
+ subRound( E, A, B, C, D, f2, K2, W[ 31 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ 32 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ 33 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ 34 ] );
+ subRound( A, B, C, D, E, f2, K2, W[ 35 ] );
+ subRound( E, A, B, C, D, f2, K2, W[ 36 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ 37 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ 38 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ 39 ] );
+
+ subRound( A, B, C, D, E, f3, K3, W[ 40 ] );
+ subRound( E, A, B, C, D, f3, K3, W[ 41 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ 42 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ 43 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ 44 ] );
+ subRound( A, B, C, D, E, f3, K3, W[ 45 ] );
+ subRound( E, A, B, C, D, f3, K3, W[ 46 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ 47 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ 48 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ 49 ] );
+ subRound( A, B, C, D, E, f3, K3, W[ 50 ] );
+ subRound( E, A, B, C, D, f3, K3, W[ 51 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ 52 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ 53 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ 54 ] );
+ subRound( A, B, C, D, E, f3, K3, W[ 55 ] );
+ subRound( E, A, B, C, D, f3, K3, W[ 56 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ 57 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ 58 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ 59 ] );
+
+ subRound( A, B, C, D, E, f4, K4, W[ 60 ] );
+ subRound( E, A, B, C, D, f4, K4, W[ 61 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ 62 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ 63 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ 64 ] );
+ subRound( A, B, C, D, E, f4, K4, W[ 65 ] );
+ subRound( E, A, B, C, D, f4, K4, W[ 66 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ 67 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ 68 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ 69 ] );
+ subRound( A, B, C, D, E, f4, K4, W[ 70 ] );
+ subRound( E, A, B, C, D, f4, K4, W[ 71 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ 72 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ 73 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ 74 ] );
+ subRound( A, B, C, D, E, f4, K4, W[ 75 ] );
+ subRound( E, A, B, C, D, f4, K4, W[ 76 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ 77 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ 78 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ 79 ] );
#else
- /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
- subRound( A, B, C, D, E, f1, K1, eData[ 0 ] );
- subRound( E, A, B, C, D, f1, K1, eData[ 1 ] );
- subRound( D, E, A, B, C, f1, K1, eData[ 2 ] );
- subRound( C, D, E, A, B, f1, K1, eData[ 3 ] );
- subRound( B, C, D, E, A, f1, K1, eData[ 4 ] );
- subRound( A, B, C, D, E, f1, K1, eData[ 5 ] );
- subRound( E, A, B, C, D, f1, K1, eData[ 6 ] );
- subRound( D, E, A, B, C, f1, K1, eData[ 7 ] );
- subRound( C, D, E, A, B, f1, K1, eData[ 8 ] );
- subRound( B, C, D, E, A, f1, K1, eData[ 9 ] );
- subRound( A, B, C, D, E, f1, K1, eData[ 10 ] );
- subRound( E, A, B, C, D, f1, K1, eData[ 11 ] );
- subRound( D, E, A, B, C, f1, K1, eData[ 12 ] );
- subRound( C, D, E, A, B, f1, K1, eData[ 13 ] );
- subRound( B, C, D, E, A, f1, K1, eData[ 14 ] );
- subRound( A, B, C, D, E, f1, K1, eData[ 15 ] );
- subRound( E, A, B, C, D, f1, K1, expand( eData, 16 ) );
- subRound( D, E, A, B, C, f1, K1, expand( eData, 17 ) );
- subRound( C, D, E, A, B, f1, K1, expand( eData, 18 ) );
- subRound( B, C, D, E, A, f1, K1, expand( eData, 19 ) );
-
- subRound( A, B, C, D, E, f2, K2, expand( eData, 20 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 21 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 22 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 23 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 24 ) );
- subRound( A, B, C, D, E, f2, K2, expand( eData, 25 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 26 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 27 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 28 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 29 ) );
- subRound( A, B, C, D, E, f2, K2, expand( eData, 30 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 31 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 32 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 33 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 34 ) );
- subRound( A, B, C, D, E, f2, K2, expand( eData, 35 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 36 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 37 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 38 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 39 ) );
-
- subRound( A, B, C, D, E, f3, K3, expand( eData, 40 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 41 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 42 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 43 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 44 ) );
- subRound( A, B, C, D, E, f3, K3, expand( eData, 45 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 46 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 47 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 48 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 49 ) );
- subRound( A, B, C, D, E, f3, K3, expand( eData, 50 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 51 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 52 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 53 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 54 ) );
- subRound( A, B, C, D, E, f3, K3, expand( eData, 55 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 56 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 57 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 58 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 59 ) );
-
- subRound( A, B, C, D, E, f4, K4, expand( eData, 60 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 61 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 62 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 63 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 64 ) );
- subRound( A, B, C, D, E, f4, K4, expand( eData, 65 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 66 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 67 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 68 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 69 ) );
- subRound( A, B, C, D, E, f4, K4, expand( eData, 70 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 71 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 72 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 73 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 74 ) );
- subRound( A, B, C, D, E, f4, K4, expand( eData, 75 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 76 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 77 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 78 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 79 ) );
-#endif /* SMALL_VERSION */
+#error Illegal SHA_CODE_SIZE
+#endif
/* Build message digest */
digest[ 0 ] += A;
digest[ 2 ] += C;
digest[ 3 ] += D;
digest[ 4 ] += E;
- }
+
+ /* W is wiped by the caller */
+#undef W
+}
#undef ROTL
#undef f1
#undef K2
#undef K3
#undef K4
-#undef expand
#undef subRound
-#else
+#else /* !USE_SHA - Use MD5 */
+
#define HASH_BUFFER_SIZE 4
+#define HASH_EXTRA_SIZE 0
#define HASH_TRANSFORM MD5Transform
/*
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
-static void MD5Transform(__u32 buf[4],
- __u32 const in[16])
+static void MD5Transform(__u32 buf[HASH_BUFFER_SIZE], __u32 const in[16])
{
__u32 a, b, c, d;
#undef F4
#undef MD5STEP
-#endif
+#endif /* !USE_SHA */
-#if POOLWORDS % 16
+#if POOLWORDS % 16 != 0
#error extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
#endif
/*
size_t nbytes, int to_user)
{
ssize_t ret, i;
- __u32 tmp[HASH_BUFFER_SIZE];
- char *cp,*dp;
+ __u32 tmp[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+ __u32 x;
add_timer_randomness(r, &extract_timer_state, nbytes);
#endif
for (i = 0; i < POOLWORDS; i += 16)
HASH_TRANSFORM(tmp, r->pool+i);
- /* Modify pool so next hash will produce different results */
- add_entropy_word(r, tmp[0]);
- add_entropy_word(r, tmp[1]);
- add_entropy_word(r, tmp[2]);
- add_entropy_word(r, tmp[3]);
-#ifdef USE_SHA
- add_entropy_word(r, tmp[4]);
-#endif
- /*
- * Run the hash transform one more time, since we want
- * to add at least minimal obscuring of the inputs to
- * add_entropy_word().
- */
- HASH_TRANSFORM(tmp, r->pool);
/*
- * In case the hash function has some recognizable
- * output pattern, we fold it in half.
+ * The following code does two separate things that happen
+ * to both work two words at a time, so are convenient
+ * to do together.
+ *
+ * First, this feeds the output back into the pool so
+ * that the next call will return different results.
+ * Any perturbation of the pool's state would do, even
+ * changing one bit, but this mixes the pool nicely.
+ *
+ * Second, this folds the output in half to hide the data
+ * fed back into the pool from the user and further mask
+ * any patterns in the hash output. (The exact folding
+ * pattern is not important; the one used here is quick.)
*/
- cp = (char *) tmp;
- dp = cp + (HASH_BUFFER_SIZE*sizeof(__u32)) - 1;
- for (i=0; i < HASH_BUFFER_SIZE*sizeof(__u32)/2; i++) {
- *cp ^= *dp;
- cp++; dp--;
+ for (i = 0; i < HASH_BUFFER_SIZE/2; i++) {
+ x = tmp[i + (HASH_BUFFER_SIZE+1)/2];
+ add_entropy_words(r, tmp[i], x);
+ tmp[i] ^= x;
}
+#if HASH_BUFFER_SIZE & 1 /* There's a middle word to deal with */
+ x = tmp[HASH_BUFFER_SIZE/2];
+ add_entropy_words(r, x, (__u32)buf);
+ x ^= (x >> 16); /* Fold it in half */
+ ((__u16 *)tmp)[HASH_BUFFER_SIZE-1] = (__u16)x;
+#endif
/* Copy data to destination buffer */
i = MIN(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2);
schedule();
}
- /* Wipe data from memory */
+ /* Wipe data just returned from memory */
memset(tmp, 0, sizeof(tmp));
return ret;
}
n = extract_entropy(&random_state, buf, n, 1);
if (n < 0) {
- if (count == 0)
- retval = n;
+ retval = n;
break;
}
count += n;
random_write(struct file * file, const char * buffer,
size_t count, loff_t *ppos)
{
- ssize_t i, bytes, ret = 0;
+ int ret = 0;
+ size_t bytes;
+ unsigned i;
__u32 buf[16];
const char *p = buffer;
- ssize_t c = count;
+ size_t c = count;
while (c > 0) {
bytes = MIN(c, sizeof(buf));
bytes -= copy_from_user(&buf, p, bytes);
if (!bytes) {
- if (!ret)
- ret = -EFAULT;
+ ret = -EFAULT;
break;
}
c -= bytes;
p += bytes;
- ret += bytes;
- i = (bytes+sizeof(__u32)-1) / sizeof(__u32);
- while (i--)
- add_entropy_word(&random_state, buf[i]);
+ i = (unsigned)((bytes-1) / (2 * sizeof(__u32)));
+ do {
+ add_entropy_words(&random_state, buf[2*i], buf[2*i+1]);
+ } while (i--);
}
- if (ret > 0) {
+ if (p == buffer) {
+ return (ssize_t)ret;
+ } else {
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
mark_inode_dirty(file->f_dentry->d_inode);
+ return (ssize_t)(p - buffer);
}
- return ret;
}
static int
#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
-
-/* FF, GG and HH are MD4 transformations for rounds 1, 2 and 3 */
-/* Rotation is separate from addition to prevent recomputation */
-#define FF(a, b, c, d, x, s) \
- {(a) += F ((b), (c), (d)) + (x); \
- (a) = ROTL ((s), (a));}
-#define GG(a, b, c, d, x, s) \
- {(a) += G ((b), (c), (d)) + (x) + 013240474631UL; \
- (a) = ROTL ((s), (a));}
-#define HH(a, b, c, d, x, s) \
- {(a) += H ((b), (c), (d)) + (x) + 015666365641UL; \
- (a) = ROTL ((s), (a));}
+/*
+ * The generic round function. The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s) \
+ (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
/*
* Basic cut-down MD4 transform. Returns only 32 bits of result.
__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
- FF (a, b, c, d, in[ 0], 3);
- FF (d, a, b, c, in[ 1], 7);
- FF (c, d, a, b, in[ 2], 11);
- FF (b, c, d, a, in[ 3], 19);
- FF (a, b, c, d, in[ 4], 3);
- FF (d, a, b, c, in[ 5], 7);
- FF (c, d, a, b, in[ 6], 11);
- FF (b, c, d, a, in[ 7], 19);
+ ROUND(F, a, b, c, d, in[0] + K1, 3);
+ ROUND(F, d, a, b, c, in[1] + K1, 7);
+ ROUND(F, c, d, a, b, in[2] + K1, 11);
+ ROUND(F, b, c, d, a, in[3] + K1, 19);
+ ROUND(F, a, b, c, d, in[4] + K1, 3);
+ ROUND(F, d, a, b, c, in[5] + K1, 7);
+ ROUND(F, c, d, a, b, in[6] + K1, 11);
+ ROUND(F, b, c, d, a, in[7] + K1, 19);
+
+ /* Round 2 */
+ ROUND(G, a, b, c, d, in[1] + K2, 3);
+ ROUND(G, d, a, b, c, in[3] + K2, 5);
+ ROUND(G, c, d, a, b, in[5] + K2, 9);
+ ROUND(G, b, c, d, a, in[7] + K2, 13);
+ ROUND(G, a, b, c, d, in[0] + K2, 3);
+ ROUND(G, d, a, b, c, in[2] + K2, 5);
+ ROUND(G, c, d, a, b, in[4] + K2, 9);
+ ROUND(G, b, c, d, a, in[6] + K2, 13);
+
+ /* Round 3 */
+ ROUND(H, a, b, c, d, in[3] + K3, 3);
+ ROUND(H, d, a, b, c, in[7] + K3, 9);
+ ROUND(H, c, d, a, b, in[2] + K3, 11);
+ ROUND(H, b, c, d, a, in[6] + K3, 15);
+ ROUND(H, a, b, c, d, in[1] + K3, 3);
+ ROUND(H, d, a, b, c, in[5] + K3, 9);
+ ROUND(H, c, d, a, b, in[0] + K3, 11);
+ ROUND(H, b, c, d, a, in[4] + K3, 15);
+
+ return buf[1] + b; /* "most hashed" word */
+ /* Alternative: return sum of all words? */
+}
+
+#if 0 /* May be needed for IPv6 */
+
+static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
+{
+ __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+ ROUND(F, a, b, c, d, in[ 0] + K1, 3);
+ ROUND(F, d, a, b, c, in[ 1] + K1, 7);
+ ROUND(F, c, d, a, b, in[ 2] + K1, 11);
+ ROUND(F, b, c, d, a, in[ 3] + K1, 19);
+ ROUND(F, a, b, c, d, in[ 4] + K1, 3);
+ ROUND(F, d, a, b, c, in[ 5] + K1, 7);
+ ROUND(F, c, d, a, b, in[ 6] + K1, 11);
+ ROUND(F, b, c, d, a, in[ 7] + K1, 19);
+ ROUND(F, a, b, c, d, in[ 8] + K1, 3);
+ ROUND(F, d, a, b, c, in[ 9] + K1, 7);
+ ROUND(F, c, d, a, b, in[10] + K1, 11);
+ ROUND(F, b, c, d, a, in[11] + K1, 19);
/* Round 2 */
- GG (a, b, c, d, in[ 0], 3);
- GG (d, a, b, c, in[ 4], 5);
- GG (c, d, a, b, in[ 1], 9);
- GG (b, c, d, a, in[ 5], 13);
- GG (a, b, c, d, in[ 2], 3);
- GG (d, a, b, c, in[ 6], 5);
- GG (c, d, a, b, in[ 3], 9);
- GG (b, c, d, a, in[ 7], 13);
+ ROUND(G, a, b, c, d, in[ 1] + K2, 3);
+ ROUND(G, d, a, b, c, in[ 3] + K2, 5);
+ ROUND(G, c, d, a, b, in[ 5] + K2, 9);
+ ROUND(G, b, c, d, a, in[ 7] + K2, 13);
+ ROUND(G, a, b, c, d, in[ 9] + K2, 3);
+ ROUND(G, d, a, b, c, in[11] + K2, 5);
+ ROUND(G, c, d, a, b, in[ 0] + K2, 9);
+ ROUND(G, b, c, d, a, in[ 2] + K2, 13);
+ ROUND(G, a, b, c, d, in[ 4] + K2, 3);
+ ROUND(G, d, a, b, c, in[ 6] + K2, 5);
+ ROUND(G, c, d, a, b, in[ 8] + K2, 9);
+ ROUND(G, b, c, d, a, in[10] + K2, 13);
/* Round 3 */
- HH (a, b, c, d, in[ 0], 3);
- HH (d, a, b, c, in[ 4], 9);
- HH (c, d, a, b, in[ 2], 11);
- HH (b, c, d, a, in[ 6], 15);
- HH (a, b, c, d, in[ 1], 3);
- HH (d, a, b, c, in[ 5], 9);
- HH (c, d, a, b, in[ 3], 11);
- HH (b, c, d, a, in[ 7], 15);
+ ROUND(H, a, b, c, d, in[ 3] + K3, 3);
+ ROUND(H, d, a, b, c, in[ 7] + K3, 9);
+ ROUND(H, c, d, a, b, in[11] + K3, 11);
+ ROUND(H, b, c, d, a, in[ 2] + K3, 15);
+ ROUND(H, a, b, c, d, in[ 6] + K3, 3);
+ ROUND(H, d, a, b, c, in[10] + K3, 9);
+ ROUND(H, c, d, a, b, in[ 1] + K3, 11);
+ ROUND(H, b, c, d, a, in[ 5] + K3, 15);
+ ROUND(H, a, b, c, d, in[ 9] + K3, 3);
+ ROUND(H, d, a, b, c, in[ 0] + K3, 9);
+ ROUND(H, c, d, a, b, in[ 4] + K3, 11);
+ ROUND(H, b, c, d, a, in[ 8] + K3, 15);
return buf[1] + b; /* "most hashed" word */
/* Alternative: return sum of all words? */
}
+#endif
+
+#undef ROUND
+#undef F
+#undef G
+#undef H
+#undef K1
+#undef K2
+#undef K3
/* This should not be decreased so low that ISNs wrap too fast. */
#define REKEY_INTERVAL 300
*/
do_gettimeofday(&tv); /* We need the usecs below... */
- if (!rekey_time ||
- (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
+ if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
rekey_time = tv.tv_sec;
/* First three words are overwritten below. */
get_random_bytes(&secret+3, sizeof(secret)-12);
secret[2]=(sport << 16) + dport;
seq = (halfMD4Transform(secret+8, secret) &
- ((1<<HASH_BITS)-1)) + (count << HASH_BITS);
+ ((1<<HASH_BITS)-1)) + count;
/*
* As close as possible to RFC 793, which
* Dan Bernstein and Eric Schenk.
*
* For linux I implement the 1 minute counter by looking at the jiffies clock.
- * The count is passed in as a parameter;
- *
+ * The count is passed in as a parameter, so this code doesn't much care.
*/
-__u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr,
- __u16 sport, __u16 dport, __u32 sseq, __u32 count)
+
+#define COOKIEBITS 24 /* Upper bits store count */
+#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+
+static int syncookie_init = 0;
+static __u32 syncookie_secret[2][16-3+HASH_BUFFER_SIZE];
+
+__u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport,
+ __u16 dport, __u32 sseq, __u32 count, __u32 data)
{
- static int is_init = 0;
- static __u32 secret[2][16];
- __u32 tmp[16];
- __u32 seq;
+ __u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+ __u32 seq;
/*
- * Pick two random secret the first time we open a TCP connection.
+ * Pick two random secrets the first time we need a cookie.
*/
- if (is_init == 0) {
- get_random_bytes(&secret[0], sizeof(secret[0]));
- get_random_bytes(&secret[1], sizeof(secret[1]));
- is_init = 1;
+ if (syncookie_init == 0) {
+ get_random_bytes(syncookie_secret, sizeof(syncookie_secret));
+ syncookie_init = 1;
}
/*
* Compute the secure sequence number.
* The output should be:
- * MD5(sec1,saddr,sport,daddr,dport,sec1) + their sequence number
- * + (count * 2^24)
- * + (MD5(sec2,saddr,sport,daddr,dport,count,sec2) % 2^24).
- * Where count increases every minute by 1.
+ * HASH(sec1,saddr,sport,daddr,dport,sec1) + sseq + (count * 2^24)
+ * + (HASH(sec2,saddr,sport,daddr,dport,count,sec2) % 2^24).
+ * Where sseq is their sequence number and count increases every
+ * minute by 1.
+ * As an extra hack, we add a small "data" value that encodes the
+ * MSS into the second hash value.
*/
- memcpy(tmp, secret[0], sizeof(tmp));
- tmp[8]=saddr;
- tmp[9]=daddr;
- tmp[10]=(sport << 16) + dport;
- HASH_TRANSFORM(tmp, tmp);
- seq = tmp[1];
-
- memcpy(tmp, secret[1], sizeof(tmp));
- tmp[8]=saddr;
- tmp[9]=daddr;
- tmp[10]=(sport << 16) + dport;
- tmp[11]=count; /* minute counter */
- HASH_TRANSFORM(tmp, tmp);
-
- seq += sseq + (count << 24) + (tmp[1] & 0x00ffffff);
+ memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0]));
+ tmp[0]=saddr;
+ tmp[1]=daddr;
+ tmp[2]=(sport << 16) + dport;
+ HASH_TRANSFORM(tmp+16, tmp);
+ seq = tmp[17] + sseq + (count << COOKIEBITS);
+
+ memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1]));
+ tmp[0]=saddr;
+ tmp[1]=daddr;
+ tmp[2]=(sport << 16) + dport;
+ tmp[3] = count; /* minute counter */
+ HASH_TRANSFORM(tmp+16, tmp);
+
+ /* Add in the second hash and the data */
+ return seq + ((tmp[17] + data) & COOKIEMASK);
+}
- /* Zap lower 3 bits to leave room for the MSS representation */
- return (seq & 0xfffff8);
+/*
+ * This retrieves the small "data" value from the syncookie.
+ * If the syncookie is bad, the data returned will be out of
+ * range. This must be checked by the caller.
+ *
+ * The count value used to generate the cookie must be within
+ * "maxdiff" if the current (passed-in) "count". The return value
+ * is (__u32)-1 if this test fails.
+ */
+__u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, __u16 sport,
+ __u16 dport, __u32 sseq, __u32 count, __u32 maxdiff)
+{
+ __u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+ __u32 diff;
+
+ if (syncookie_init == 0)
+ return (__u32)-1; /* Well, duh! */
+
+ /* Strip away the layers from the cookie */
+ memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0]));
+ tmp[0]=saddr;
+ tmp[1]=daddr;
+ tmp[2]=(sport << 16) + dport;
+ HASH_TRANSFORM(tmp+16, tmp);
+ cookie -= tmp[17] + sseq;
+ /* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */
+
+ diff = (count - (cookie >> COOKIEBITS)) & ((__u32)-1 >> COOKIEBITS);
+ if (diff >= maxdiff)
+ return (__u32)-1;
+
+ memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1]));
+ tmp[0] = saddr;
+ tmp[1] = daddr;
+ tmp[2] = (sport << 16) + dport;
+ tmp[3] = count - diff; /* minute counter */
+ HASH_TRANSFORM(tmp+16, tmp);
+
+ return (cookie - tmp[17]) & COOKIEMASK; /* Leaving the data behind */
}
#endif
{
unsigned long low, high;
__asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high));
- return (((unsigned long long) high << 31) | low);
+ return (((unsigned long long) high << 32) | low);
}
__initfunc(static void
#endif
static char *serial_name = "Serial driver";
-static char *serial_version = "4.25";
+static char *serial_version = "4.26";
static DECLARE_TASK_QUEUE(tq_serial);
static unsigned long last_strobe = 0;
struct async_struct *info;
unsigned int i;
+ unsigned long flags;
if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
for (i=1; i < NR_IRQS; i++) {
info = IRQ_ports[i];
if (!info)
continue;
- cli();
+ save_flags(flags); cli();
#ifdef CONFIG_SERIAL_SHARE_IRQ
if (info->next_port) {
do {
} else
#endif /* CONFIG_SERIAL_SHARE_IRQ */
rs_interrupt_single(i, NULL, NULL);
- sti();
+ restore_flags(flags);
}
}
last_strobe = jiffies;
timer_active |= 1 << RS_TIMER;
if (IRQ_ports[0]) {
- cli();
+ save_flags(flags); cli();
#ifdef CONFIG_SERIAL_SHARE_IRQ
rs_interrupt(0, NULL, NULL);
#else
rs_interrupt_single(0, NULL, NULL);
#endif
- sti();
+ restore_flags(flags);
timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
}
static void rs_flush_buffer(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
-
+ unsigned long flags;
+
if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
return;
- cli();
+ save_flags(flags); cli();
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- sti();
+ restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
static void rs_throttle(struct tty_struct * tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
if (tty->termios->c_cflag & CRTSCTS)
info->MCR &= ~UART_MCR_RTS;
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
}
static void rs_unthrottle(struct tty_struct * tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
}
if (tty->termios->c_cflag & CRTSCTS)
info->MCR |= UART_MCR_RTS;
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
}
/*
new_serial.irq = irq_cannonicalize(new_serial.irq);
if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
- (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
+ (new_serial.type < PORT_UNKNOWN) ||
+ (new_serial.type > PORT_MAX) ||
+ (new_serial.xmit_fifo_size == 0)) {
return -EINVAL;
}
{
unsigned char status;
unsigned int result;
+ unsigned long flags;
- cli();
+ save_flags(flags); cli();
status = serial_in(info, UART_LSR);
- sti();
+ restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
return put_user(result,value);
}
{
unsigned char control, status;
unsigned int result;
+ unsigned long flags;
control = info->MCR;
- cli();
+ save_flags(flags); cli();
status = serial_in(info, UART_MSR);
- sti();
+ restore_flags(flags);
result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
#ifdef TIOCM_OUT1
{
int error;
unsigned int arg;
+ unsigned long flags;
error = get_user(arg, value);
if (error)
default:
return -EINVAL;
}
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
return 0;
}
shutdown(info);
autoconfig(info->state);
- if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0))
+ if ((info->state->flags & ASYNC_AUTO_IRQ) &&
+ (info->state->port != 0) &&
+ (info->state->type != PORT_UNKNOWN))
info->state->irq = detect_uart_irq(info->state);
retval = startup(info);
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct *p_cuser; /* user space */
-
+ unsigned long flags;
+
if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
return -ENODEV;
* Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- cli();
+ save_flags(flags); cli();
/* note the counters on entry */
cprev = info->state->icount;
- sti();
+ restore_flags(flags);
while (1) {
interruptible_sleep_on(&info->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
- cli();
+ save_flags(flags); cli();
cnow = info->state->icount; /* atomic copy */
- sti();
+ restore_flags(flags);
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
return -EIO; /* no change => error */
* RI where only 0->1 is counted.
*/
case TIOCGICOUNT:
- cli();
+ save_flags(flags); cli();
cnow = info->state->icount;
- sti();
+ restore_flags(flags);
p_cuser = (struct serial_icounter_struct *) arg;
error = put_user(cnow.cts, &p_cuser->cts);
if (error) return error;
if (error) return error;
error = put_user(cnow.dcd, &p_cuser->dcd);
if (error) return error;
+ error = put_user(cnow.rx, &p_cuser->rx);
+ if (error) return error;
+ error = put_user(cnow.tx, &p_cuser->tx);
+ if (error) return error;
+ error = put_user(cnow.frame, &p_cuser->frame);
+ if (error) return error;
+ error = put_user(cnow.overrun, &p_cuser->overrun);
+ if (error) return error;
+ error = put_user(cnow.parity, &p_cuser->parity);
+ if (error) return error;
+ error = put_user(cnow.brk, &p_cuser->brk);
+ if (error) return error;
+ error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
+ if (error) return error;
+ return 0;
+
+ case TIOCSERGWILD:
+ case TIOCSERSWILD:
+ /* "setserial -W" is called in Debian boot */
+ printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
return 0;
default:
static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
-
+ unsigned long flags;
+
if ( (tty->termios->c_cflag == old_termios->c_cflag)
&& ( RELEVANT_IFLAG(tty->termios->c_iflag)
== RELEVANT_IFLAG(old_termios->c_iflag)))
if ((old_termios->c_cflag & CBAUD) &&
!(tty->termios->c_cflag & CBAUD)) {
info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
}
/* Handle transition away from B0 status */
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->MCR |= UART_MCR_RTS;
}
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
}
/* Handle turning off CRTSCTS */
if (info->state->type == PORT_UNKNOWN)
return;
+ if (info->xmit_fifo_size == 0)
+ return; /* Just in case.... */
+
orig_jiffies = jiffies;
/*
* Set the check interval to be 1/5 of the estimated time to
struct wait_queue wait = { current, NULL };
struct serial_state *state = info->state;
int retval;
- int do_clocal = 0;
+ int do_clocal = 0, extra_count = 0;
+ unsigned long flags;
/*
* If the device is in the middle of being closed, then block
printk("block_til_ready before block: ttys%d, count = %d\n",
state->line, state->count);
#endif
- cli();
- if (!tty_hung_up_p(filp))
+ save_flags(flags); cli();
+ if (!tty_hung_up_p(filp)) {
+ extra_count = 1;
state->count--;
- sti();
+ }
+ restore_flags(flags);
info->blocked_open++;
while (1) {
- cli();
+ save_flags(flags); cli();
if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
(tty->termios->c_cflag & CBAUD))
serial_out(info, UART_MCR,
serial_inp(info, UART_MCR) |
(UART_MCR_DTR | UART_MCR_RTS));
- sti();
+ restore_flags(flags);
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
}
current->state = TASK_RUNNING;
remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
+ if (extra_count)
state->count++;
info->blocked_open--;
#ifdef SERIAL_DEBUG_OPEN
struct async_struct *info = state->info, scr_info;
char stat_buf[30], control, status;
int ret;
+ unsigned long flags;
ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
state->line, uart_config[state->type].name,
info->quot = 0;
info->tty = 0;
}
- cli();
+ save_flags(flags); cli();
status = serial_in(info, UART_MSR);
control = info ? info->MCR : serial_in(info, UART_MCR);
- sti();
+ restore_flags(flags);
stat_buf[0] = 0;
stat_buf[1] = 0;
int rs_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
- int i, len = 0;
+ int i, len = 0, l;
off_t begin = 0;
len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
for (i = 0; i < NR_PORTS && len < 4000; i++) {
- len += line_info(page + len, &rs_table[i]);
+ l = line_info(page + len, &rs_table[i]);
+ len += l;
if (len+begin > off+count)
goto done;
if (len+begin < off) {
#endif
#ifdef CONFIG_SERIAL_SHARE_IRQ
printk(" SHARE_IRQ");
-#endif
#define SERIAL_OPT
+#endif
#ifdef CONFIG_SERIAL_DETECT_IRQ
printk(" DETECT_IRQ");
+#define SERIAL_OPT
#endif
#ifdef SERIAL_OPT
printk(" enabled\n");
{
int irq;
unsigned long irqs;
- unsigned char save_mcr;
+ unsigned char save_mcr, save_ier;
struct async_struct scr_info; /* serial_{in,out} because HUB6 */
#ifdef CONFIG_SERIAL_MANY_PORTS
/* forget possible initially masked and pending IRQ */
probe_irq_off(probe_irq_on());
save_mcr = serial_inp(&scr_info, UART_MCR);
-
+ save_ier = serial_inp(&scr_info, UART_IER);
serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+
irqs = probe_irq_on();
serial_outp(&scr_info, UART_MCR, 0);
- udelay (1);
+ udelay (10);
+ if (state->flags & ASYNC_FOURPORT) {
+ serial_outp(&scr_info, UART_MCR,
+ UART_MCR_DTR | UART_MCR_RTS);
+ } else {
+ serial_outp(&scr_info, UART_MCR,
+ UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+ }
+ serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */
+ (void)serial_inp(&scr_info, UART_LSR);
+ (void)serial_inp(&scr_info, UART_RX);
+ (void)serial_inp(&scr_info, UART_IIR);
+ (void)serial_inp(&scr_info, UART_MSR);
+ serial_outp(&scr_info, UART_TX, 0xFF);
+ udelay (20);
irq = probe_irq_off(irqs);
serial_outp(&scr_info, UART_MCR, save_mcr);
-
+ serial_outp(&scr_info, UART_IER, save_ier);
#ifdef CONFIG_SERIAL_MANY_PORTS
if (state->flags & ASYNC_FOURPORT)
outb_p(save_ICP, ICP);
if (!(state->flags & ASYNC_SKIP_TEST)) {
scratch = serial_inp(info, UART_MCR);
serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
- scratch2 = serial_inp(info, UART_MSR);
serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
status1 = serial_inp(info, UART_MSR) & 0xF0;
serial_outp(info, UART_MCR, scratch);
- serial_outp(info, UART_MSR, scratch2);
if (status1 != 0x90) {
restore_flags(flags);
return;
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
state->irq = irq_cannonicalize(state->irq);
- if (check_region(state->port,8)) {
- state->type = PORT_UNKNOWN;
+ if (check_region(state->port,8))
continue;
- }
- if ( (state->type == PORT_UNKNOWN)
- && (state->flags & ASYNC_BOOT_AUTOCONF))
+ if (state->flags & ASYNC_BOOT_AUTOCONF)
autoconfig(state);
}
/*
}
}
#endif
+
+ if (tty->driver.close)
+ tty->driver.close(tty, filp);
+
/*
* Sanity check: if tty->count is going to zero, there shouldn't be
* any waiters on tty->read_wait or tty->write_wait. We test the
* block, so it's safe to proceed with closing.
*/
- if (tty->driver.close)
- tty->driver.close(tty, filp);
-
if (pty_master) {
if (--o_tty->count < 0) {
printk("release_dev: bad pty slave count (%d) for %s\n",
performed, so there should be no Host Adapter state lost by a
Soft Reset in response to a Command Invalid condition.
*/
- mdelay(1);
+ udelay(1000);
StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
if (StatusRegister.Bits.CommandInvalid ||
StatusRegister.Bits.Reserved ||
StatusRegister.Bits.DiagnosticFailure)
{
BusLogic_SoftReset(HostAdapter);
- mdelay(1);
+ udelay(1000);
}
BusLogic_CommandFailureReason = "Command Invalid";
Result = -1;
Boot Command line options
------------------------------
- "aic7xxx=no_reset" - Eliminate the SCSI reset delay during startup.
- Some SCSI devices need some extra time to reset.
"aic7xxx=reverse_scan" - Have the driver register the SCSI cards in the
reverse of the normal order. This may help those people who have more
than one PCI Adaptec controller force the correct controller to be
outb(SRST|IRST/*|SCRST*/, CONTROL(bse));
- i = jiffies + 2;
- while (i>jiffies); /* Wait a little bit for things to settle down. */
+ mdelay(20); /* Wait a little bit for things to settle down. */
debug = 1;
/* Expect INIT and IDLE, any of the others are bad */
0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "5.0.17"
+#define AIC7XXX_C_VERSION "5.0.18"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
unsigned char dev_commands_sent[MAX_TARGETS];
/*
- * The next 64 (or 128 on 64 bit machines)....
+ * The next 128 (or 256 on 64 bit machines)....
*/
- Scsi_Cmnd *dev_negotiation_cmnd[MAX_TARGETS];
+ Scsi_Cmnd *dev_wdtr_cmnd[MAX_TARGETS];
+ Scsi_Cmnd *dev_sdtr_cmnd[MAX_TARGETS];
/*
* The next 64....
* 1 == Use the Channel B IRQ
*/
static unsigned int aic7xxx_extended = 0; /* extended translation on? */
-static unsigned int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
static int aic7xxx_irq_trigger = -1; /*
* -1 use board setting
* 0 use edge triggered
unsigned int *flag;
} options[] = {
{ "extended", &aic7xxx_extended },
- { "no_reset", &aic7xxx_no_reset },
{ "irq_trigger", &aic7xxx_irq_trigger },
{ "verbose", &aic7xxx_verbose },
{ "reverse_scan",&aic7xxx_reverse_scan },
scsi_conf |= p->scsi_id_b;
aic_outb(p, scsi_conf | (term) ? TERM_ENB : 0, SCSICONF + 1);
}
- if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+ if (scsi_conf & RESET_SCSI)
{
/* Reset SCSI bus B. */
if (aic7xxx_verbose & VERBOSE_PROBE)
}
- if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+ if (scsi_conf & RESET_SCSI)
{
/* Reset SCSI bus A. */
if (aic7xxx_verbose & VERBOSE_PROBE)
*/
for (i = 0; i < MAX_TARGETS; i++)
{
- if(p->dev_negotiation_cmnd[i])
- kfree(p->dev_negotiation_cmnd[i]);
+ if(p->dev_wdtr_cmnd[i])
+ kfree(p->dev_wdtr_cmnd[i]);
+ if(p->dev_sdtr_cmnd[i])
+ kfree(p->dev_sdtr_cmnd[i]);
}
/*
int tindex)
{
- if(p->dev_negotiation_cmnd[tindex] == NULL)
+ if ( (p->needwdtr & (1<<tindex)) && !(p->wdtr_pending & (1<<tindex)) )
{
- Scsi_Cmnd *cmd;
-
- if (!(p->dev_negotiation_cmnd[tindex] =
- kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+ if(p->dev_wdtr_cmnd[tindex] == NULL)
{
- return;
- }
- cmd = p->dev_negotiation_cmnd[tindex];
- memset(cmd, 0, sizeof(Scsi_Cmnd));
- memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
- memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
- memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
- cmd->lun = 0;
- cmd->request_bufflen = 0;
- cmd->request_buffer = NULL;
- cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
- cmd->bufflen = 0;
- cmd->buffer = NULL;
- cmd->underflow = 0;
- cmd->cmd_len = 6;
- }
- aic7xxx_queue(p->dev_negotiation_cmnd[tindex],
- aic7xxx_negotiation_complete);
+ Scsi_Cmnd *cmd;
+
+ if (!(p->dev_wdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+ {
+ return;
+ }
+ cmd = p->dev_wdtr_cmnd[tindex];
+ memset(cmd, 0, sizeof(Scsi_Cmnd));
+ memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
+ memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
+ memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
+ cmd->lun = 0;
+ cmd->request_bufflen = 0;
+ cmd->request_buffer = NULL;
+ cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
+ cmd->bufflen = 0;
+ cmd->buffer = NULL;
+ cmd->underflow = 0;
+ cmd->cmd_len = 6;
+ }
+ aic7xxx_queue(p->dev_wdtr_cmnd[tindex],
+ aic7xxx_negotiation_complete);
+ }
+ else if ( (p->needsdtr & (1<<tindex)) && !(p->sdtr_pending & (1<<tindex)) )
+ {
+ if(p->dev_sdtr_cmnd[tindex] == NULL)
+ {
+ Scsi_Cmnd *cmd;
+
+ if (!(p->dev_sdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+ {
+ return;
+ }
+ cmd = p->dev_sdtr_cmnd[tindex];
+ memset(cmd, 0, sizeof(Scsi_Cmnd));
+ memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
+ memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
+ memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
+ cmd->lun = 0;
+ cmd->request_bufflen = 0;
+ cmd->request_buffer = NULL;
+ cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
+ cmd->bufflen = 0;
+ cmd->buffer = NULL;
+ cmd->underflow = 0;
+ cmd->cmd_len = 6;
+ }
+ aic7xxx_queue(p->dev_sdtr_cmnd[tindex],
+ aic7xxx_negotiation_complete);
+ }
}
/*+F*************************************************************************
}
if (p->dev_flags[TARGET_INDEX(cmd)] & DEVICE_SCANNED)
{
- if ( ((p->needwdtr & mask) || (p->needsdtr & mask)) &&
- !((p->wdtr_pending & mask) || (p->sdtr_pending & mask)) )
+ if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) )
{
- if (cmd == p->dev_negotiation_cmnd[TARGET_INDEX(cmd)])
+ if (cmd == p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
{
- if (p->needwdtr & mask)
- {
- p->wdtr_pending |= mask;
- scb->flags |= SCB_MSGOUT_WDTR_16BIT;
- }
- else
- {
- p->sdtr_pending |= mask;
- scb->flags |= SCB_MSGOUT_SDTR;
- }
+ p->wdtr_pending |= mask;
+ scb->flags |= SCB_MSGOUT_WDTR_16BIT;
hscb->control &= DISCENB;
hscb->control |= MK_MESSAGE;
scb->tag_action = 0;
aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
}
}
+ if ( (p->needsdtr & mask) && !(p->sdtr_pending & mask) )
+ {
+ if (cmd == p->dev_sdtr_cmnd[TARGET_INDEX(cmd)])
+ {
+ p->sdtr_pending |= mask;
+ scb->flags |= SCB_MSGOUT_SDTR;
+ hscb->control &= DISCENB;
+ hscb->control |= MK_MESSAGE;
+ scb->tag_action = 0;
+ }
+ else if (cmd != p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
+ {
+ aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
+ }
+ }
}
hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
p->adapter_control);
size += sprintf(BLS, " Extended Translation: %sabled\n",
(p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
- size += sprintf(BLS, " SCSI Bus Reset: %sabled\n",
- aic7xxx_no_reset ? "Dis" : "En");
size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
if (p->type & AHC_ULTRA)
{
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
+ * 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
+ * Increased busy timeout from 10 msec. to 200 msec. while
+ * processing interrupts.
+ *
* 16 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
* Improved abort handling during the eh recovery process.
*
* abort and reset routines.
* Added command line options (eh:[y|n]) to choose between
* new_eh_code and the old scsi code.
- * If linux verion >= 2.1.101 the default is eh:y, while the eh
+ * If linux version >= 2.1.101 the default is eh:y, while the eh
* option is ignored for previous releases and the old scsi code
* is used.
*
HD(j)->iocount);
/* Check if this board is still busy */
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+ if (wait_on_busy(sh[j]->io_port, 20 * MAXLOOP)) {
reg = inb(sh[j]->io_port + REG_STATUS);
printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n",
BN(j), irq, reg, HD(j)->iocount);
int eata2x_reset(Scsi_Cmnd *);
int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
-#define EATA_VERSION "4.31.00"
+#define EATA_VERSION "4.32.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
/* fdomain.c -- Future Domain TMC-16x0 SCSI driver
* Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Wed Oct 2 11:10:55 1996 by r.faith@ieee.org
+ * Revised: Wed Oct 2 11:10:55 1996 by faith@acm.org
* Author: Rickard E. Faith, faith@cs.unc.edu
* Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith
*
if (retcode == -EINVAL) {
printk( "fdomain: IRQ %d is bad!\n", interrupt_level );
printk( " This shouldn't happen!\n" );
- printk( " Send mail to faith@cs.unc.edu\n" );
+ printk( " Send mail to faith@acm.org\n" );
} else if (retcode == -EBUSY) {
printk( "fdomain: IRQ %d is already in use!\n", interrupt_level );
printk( " Please use another IRQ!\n" );
} else {
printk( "fdomain: Error getting IRQ %d\n", interrupt_level );
printk( " This shouldn't happen!\n" );
- printk( " Send mail to faith@cs.unc.edu\n" );
+ printk( " Send mail to faith@acm.org\n" );
}
panic( "fdomain: Driver requires interruptions\n" );
}
/* fdomain.h -- Header for Future Domain TMC-16x0 driver
* Created: Sun May 3 18:47:33 1992 by faith@cs.unc.edu
- * Revised: Thu Oct 12 13:21:35 1995 by r.faith@ieee.org
+ * Revised: Thu Oct 12 13:21:35 1995 by faith@acm.org
* Author: Rickard E. Faith, faith@cs.unc.edu
* Copyright 1992, 1993, 1994, 1995 Rickard E. Faith
*
#include <asm/system.h>
#include <asm/page.h>
+#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
Scsi_Cmnd * SCpnt;
Scsi_Device * SDpnt;
+ spin_lock_irqsave(&io_request_lock, flags);
+
SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
SCpnt = scsi_allocate_device(NULL, dev, 1);
{
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
- spin_lock_irqsave(&io_request_lock, flags);
scsi_do_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries);
spin_unlock_irqrestore(&io_request_lock, flags);
down(&sem);
+ spin_lock_irqsave(&io_request_lock, flags);
SCpnt->request.sem = NULL;
}
(*SDpnt->scsi_request_fn)();
wake_up(&SDpnt->device_wait);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return result;
}
}
#ifndef DEBUG_NO_CMD
+
+ spin_lock_irqsave(&io_request_lock, flags);
SCpnt = scsi_allocate_device(NULL, dev, 1);
{
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
- spin_lock_irqsave(&io_request_lock, flags);
scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done,
timeout, retries);
spin_unlock_irqrestore(&io_request_lock, flags);
}
result = SCpnt->result;
+ spin_lock_irqsave(&io_request_lock, flags);
+
wake_up(&SCpnt->device->device_wait);
SDpnt = SCpnt->device;
scsi_release_command(SCpnt);
if(SDpnt->scsi_request_fn)
(*SDpnt->scsi_request_fn)();
+ spin_unlock_irqrestore(&io_request_lock, flags);
return result;
#else
{
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
+ * 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
+ * Increased busy timeout from 10 msec. to 200 msec. while
+ * processing interrupts.
+ *
* 18 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
* Improved abort handling during the eh recovery process.
*
* abort and reset routines.
* Added command line options (eh:[y|n]) to choose between
* new_eh_code and the old scsi code.
- * If linux verion >= 2.1.101 the default is eh:y, while the eh
+ * If linux version >= 2.1.101 the default is eh:y, while the eh
* option is ignored for previous releases and the old scsi code
* is used.
*
HD(j)->iocount);
/* Check if this board is still busy */
- if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+ if (wait_on_busy(sh[j]->io_port, 20 * MAXLOOP)) {
outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n",
BN(j), irq, reg, HD(j)->iocount);
int u14_34f_old_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
-#define U14_34F_VERSION "4.31.00"
+#define U14_34F_VERSION "4.32.00"
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
* data, of course), but instead letting the caller do it.
*/
-/* Some bdflush() changes for the dynamic ramdisk - Paul Gortmaker, 12/94 */
/* Start bdflush() with kernel_thread not syscall - Paul Gortmaker, 12/95 */
/* Removed a lot of unnecessary code and simplified things now that
* hash table, use SLAB cache for buffer heads. -DaveM
*/
+/* Added 32k buffer block sizes - these are required older ARM systems.
+ * - RMK
+ */
+
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <asm/io.h>
#include <asm/bitops.h>
-#define NR_SIZES 5
-static char buffersize_index[17] =
-{-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4};
+#define NR_SIZES 7
+static char buffersize_index[65] =
+{-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
+ 4, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,
+ 5, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1,-1, -1, -1, -1, -1, -1, -1,
+ 6};
#define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
if (!blksize_size[MAJOR(dev)])
return;
- if (size > PAGE_SIZE)
- size = 0;
-
- switch (size) {
- default: panic("Invalid blocksize passed to set_blocksize");
- case 512: case 1024: case 2048: case 4096: case 8192: ;
- }
+ /* Size must be a power of two, and between 512 and PAGE_SIZE */
+ if (size > PAGE_SIZE || size < 512 || (size & (size-1)))
+ panic("Invalid blocksize passed to set_blocksize");
if (blksize_size[MAJOR(dev)][MINOR(dev)] == 0 && size == BLOCK_SIZE) {
blksize_size[MAJOR(dev)][MINOR(dev)] = size;
while ( alias != &inode->i_dentry ) {
alias_de = list_entry(alias, struct dentry, d_alias);
if ( !alias_de ) {
- printk("Corrupt alias list for %*s\n",
- alias_de->d_name.len, alias_de->d_name.name);
+ printk("Null alias list for inode %ld\n", inode->i_ino);
return;
}
coda_flag_children(alias_de, flag);
/* cnode.c */
-static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr)
+static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
{
CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino);
ENTRY;
/*
- * We get inode numbers from Venus -- see venus source
- */
+ * We get inode numbers from Venus -- see venus source
+ */
error = venus_getattr(sb, fid, &attr);
if ( error ) {
INIT_LIST_HEAD(&(cnp->c_cnhead));
INIT_LIST_HEAD(&(cnp->c_volrootlist));
} else {
- printk("coda_cnode make on initialized inode %ld, %s!\n",
+ cnp->c_flags = 0;
+ CDEBUG(D_CNODE, "coda_cnode make on initialized"
+ "inode %ld, %s!\n",
(*inode)->i_ino, coda_f2s(&cnp->c_fid));
}
/* fill in the inode attributes */
- if ( coda_fid_is_volroot(fid) )
+ if ( coda_f2i(fid) != ino ) {
+ if ( !coda_fid_is_weird(fid) )
+ printk("Coda: unknown weird fid: ino %ld, fid %s."
+ "Tell Peter.", ino, coda_f2s(&cnp->c_fid));
list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead);
+ CDEBUG(D_CNODE, "Added %ld ,%s to volroothead\n",
+ ino, coda_f2s(&cnp->c_fid));
+ }
coda_fill_inode(*inode, &attr);
- CDEBUG(D_CNODE, "Done linking: ino %ld, at 0x%x with cnp 0x%x, cnp->c_vnode 0x%x\n", (*inode)->i_ino, (int) (*inode), (int) cnp, (int)cnp->c_vnode);
+ CDEBUG(D_CNODE, "Done linking: ino %ld, at 0x%x with cnp 0x%x,"
+ "cnp->c_vnode 0x%x\n", (*inode)->i_ino, (int) (*inode),
+ (int) cnp, (int)cnp->c_vnode);
EXIT;
return 0;
}
- if ( coda_fid_is_volroot(fid) ) {
+ if ( coda_fid_is_weird(fid) ) {
struct coda_inode_info *cii;
struct list_head *lh, *le;
struct coda_sb_info *sbi = coda_sbp(sb);
while ( (le = le->next) != lh ) {
cii = list_entry(le, struct coda_inode_info,
c_volrootlist);
- if ( cii->c_fid.Volume == fid->Volume) {
+ if ( coda_fideq(&cii->c_fid, fid) ) {
inode = cii->c_vnode;
CDEBUG(D_INODE, "volume root, found %ld\n", cii->c_vnode->i_ino);
return cii->c_vnode;
return NULL;
}
- /* fid is not volume root, hence ino is computable */
+ /* fid is not weird: ino should be computable */
nr = coda_f2i(fid);
inode = iget(sb, nr);
if ( !inode ) {
These have the same inode as the root of the volume they
mount, but the fid will be wrong.
*/
- if ( !coda_fideq(fid, &(cnp->c_fid)) &&
- !coda_fid_is_volroot(&(cnp->c_fid))) {
- printk("coda_fid2inode: bad cnode! Tell Peter.\n");
+ if ( !coda_fideq(fid, &(cnp->c_fid)) ) {
+ printk("coda_fid2inode: bad cnode (ino %ld, fid %s)"
+ "Tell Peter.\n", nr, coda_f2s(fid));
iput(inode);
return NULL;
}
{
return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
}
+
+int coda_fid_is_weird(struct ViceFid *fid)
+{
+ /* volume roots */
+ if ( (fid->Vnode == 1) && (fid->Unique == 1 ) )
+ return 1;
+ /* tmpfid unique (simulate.cc) */
+ if ( fid->Unique == 0xffffffff )
+ return 1;
+ /* LocalFakeVnode (local.h) */
+ if ( fid->Vnode == 0xfffffffd )
+ return 1;
+ /* LocalFileVnode (venus.private.h) */
+ if ( fid->Vnode == 0xfffffffe )
+ return 1;
+ /* local fake vid (local.h) */
+ if ( fid->Volume == 0xffffffff )
+ return 1;
+ /* local DirVnode (venus.private.h) */
+ if ( fid->Vnode == 0xffffffff )
+ return 1;
+ /* FakeVnode (venus.private.h) */
+ if ( fid->Vnode == 0xfffffffc )
+ return 1;
+
+ return 0;
+
+}
+
+
/* put the current process credentials in the cred */
void coda_load_creds(struct coda_cred *cred)
{
unsigned short coda_flags = 0;
- if ( flags & (O_RDONLY | O_RDWR) )
+ if ( (flags & 0xf) == O_RDONLY )
+ coda_flags |= C_O_READ;
+
+ if ( flags & O_RDWR )
coda_flags |= C_O_READ;
if ( flags & (O_WRONLY | O_RDWR) )
coda_flags |= C_O_WRITE;
- if ( flags & O_TRUNC )
+ if ( flags & O_TRUNC ) {
+ CDEBUG(D_FILE, "--> C_O_TRUNC added\n");
coda_flags |= C_O_TRUNC;
+ }
+ if ( flags & O_EXCL ) {
+ coda_flags |= C_O_EXCL;
+ CDEBUG(D_FILE, "--> C_O_EXCL added\n");
+ }
return coda_flags;
}
entry->d_time = 0;
entry->d_op = &coda_dentry_operations;
d_add(entry, res_inode);
- if ( dropme )
+ if ( dropme ) {
d_drop(entry);
+ ITOC(res_inode)->c_flags |= C_VATTR;
+ }
EXIT;
return 0;
}
}
/* invalidate the directory cnode's attributes */
- dircnp->c_flags &= ~C_VATTR;
+ dircnp->c_flags |= C_VATTR;
d_instantiate(de, result);
return 0;
}
}
/* invalidate the directory cnode's attributes */
- dircnp->c_flags &= ~C_VATTR;
+ dircnp->c_flags |= C_VATTR;
dir->i_nlink++;
d_instantiate(de, inode);
return 0;
(const char *)name, len);
if ( ! error ) {
- dir_cnp->c_flags &= ~C_VATTR;
+ dir_cnp->c_flags |= C_VATTR;
inode->i_nlink++;
d_instantiate(de, inode);
} else {
}
/* cache management */
- dircnp->c_flags &= ~C_VATTR;
+ dircnp->c_flags |= C_VATTR;
de->d_inode->i_nlink--;
d_delete(de);
if (is_bad_inode(inode))
return 0;
cii = ITOC(de->d_inode);
- if (cii->c_flags & C_PURGE)
+ if (cii->c_flags & (C_PURGE | C_VATTR))
valid = 0;
}
return valid || coda_isroot(de->d_inode);
}
/* this baby may be lost if:
- - it's type changed
+ - it's type changed
- it's ino changed
*/
old_mode = inode->i_mode;
return -EIO;
}
- cii->c_flags &= ~C_VATTR;
+ cii->c_flags &= ~(C_VATTR | C_PURGE);
return 0;
}
return -1;
}
- cnp->c_flags &= ~C_VATTR;
-
down(&cont_inode->i_sem);
result = cont_file.f_op->write(&cont_file , buff, count,
&(cont_file.f_pos));
up(&cont_inode->i_sem);
coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
+
+ if (result)
+ cnp->c_flags |= C_VATTR;
return result;
}
ENTRY;
+
+ sb->s_dev = 0;
coda_cache_clear_all(sb);
sb_info = coda_sbp(sb);
sb_info->sbi_vcomm->vc_inuse = 0;
#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry proc_sys_root;
+struct proc_dir_entry proc_sys_root = {
+ PROC_SYS, 3, "sys", /* inode, name */
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, /* mode, nlink, uid, gid */
+ 0, &proc_dir_inode_operations, /* size, ops */
+ NULL, NULL, /* get_info, fill_inode */
+ NULL, /* next */
+ NULL, NULL /* parent, subdir */
+};
-struct proc_dir_entry proc_fs_coda = {
- PROC_FS_CODA, 4, "coda",
+
+struct proc_dir_entry proc_sys_coda = {
+ 0, 4, "coda",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_dir_inode_operations,
NULL, NULL,
NULL, NULL
};
-struct proc_dir_entry proc_sys_coda = {
- 0, 4, "coda",
+struct proc_dir_entry proc_fs = {
+ PROC_FS, 2, "fs",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_dir_inode_operations,
NULL, NULL,
NULL, NULL
};
-struct proc_dir_entry proc_fs = {
- PROC_FS, 2, "fs",
+/*
+ * target directory structure:
+ /proc/fs/
+ /proc/fs/coda
+ /proc/fs/coda/{vfs_stats,
+
+*/
+
+
+struct proc_dir_entry proc_fs_coda = {
+ PROC_FS_CODA, 4, "coda",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_dir_inode_operations,
NULL, NULL,
NULL, NULL
};
-#if 0
-struct proc_dir_entry proc_coda_ncstats = {
- 0 , 12, "coda-ncstats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- cfsnc_nc_info
- };
-#endif
-
struct proc_dir_entry proc_coda_vfs = {
PROC_VFS_STATS , 9, "vfs_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
proc_register(&proc_fs_coda,&proc_coda_upcall);
proc_register(&proc_fs_coda,&proc_coda_permission);
proc_register(&proc_fs_coda,&proc_coda_cache_inv);
-#if 0
- proc_register(&proc_fs_coda, &proc_coda_ncstats);
-#endif
+
proc_register(&proc_sys_root,&proc_sys_coda);
proc_register(&proc_sys_coda,&proc_coda_vfs_control);
proc_register(&proc_sys_coda,&proc_coda_upcall_control);
proc_unregister(&proc_sys_coda, proc_coda_cache_inv_control.low_ino);
proc_unregister(&proc_sys_coda, proc_coda_permission_control.low_ino);
proc_unregister(&proc_sys_coda, proc_coda_upcall_control.low_ino);
- proc_unregister(&proc_sys_coda,proc_coda_vfs_control.low_ino);
+ proc_unregister(&proc_sys_coda, proc_coda_vfs_control.low_ino);
proc_unregister(&proc_sys_root, proc_sys_coda.low_ino);
-#if 0
- proc_unregister(&proc_fs_coda, proc_coda_ncstats.low_ino);
-#endif
proc_unregister(&proc_fs_coda, proc_coda_cache_inv.low_ino);
proc_unregister(&proc_fs_coda, proc_coda_permission.low_ino);
proc_unregister(&proc_fs_coda, proc_coda_upcall.low_ino);
*
*/
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
* force a new lookup for all the children
of this dir.
- * CFS_ZAPVNODE -- intended to be a zapfile for just one cred.
- Not used?
*
* The next is a result of Venus detecting an inconsistent file.
* CFS_PURGEFID -- flush the attribute for the file
int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
{
- /* Handle invalidate requests. */
- switch (opcode) {
- case CFS_FLUSH : {
- clstats(CFS_FLUSH);
- CDEBUG(D_DOWNCALL, "CFS_FLUSH\n");
- coda_cache_clear_all(sb);
- shrink_dcache_sb(sb);
- return(0);
- }
- case CFS_PURGEUSER : {
- struct coda_cred *cred = &out->cfs_purgeuser.cred;
- CDEBUG(D_DOWNCALL, "CFS_PURGEUSER\n");
- if ( !cred ) {
- printk("PURGEUSER: null cred!\n");
- return 0;
- }
- clstats(CFS_PURGEUSER);
- coda_cache_clear_cred(sb, cred);
- return(0);
- }
- case CFS_ZAPDIR : {
- struct inode *inode;
- ViceFid *fid = &out->cfs_zapdir.CodaFid;
- if ( !fid ) {
- printk("ZAPDIR: Null fid\n");
- return 0;
- }
- CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid));
- clstats(CFS_ZAPDIR);
- inode = coda_fid_to_inode(fid, sb);
- coda_flag_inode(inode, C_VATTR);
- coda_cache_clear_inode(inode);
- coda_flag_alias_children(inode, C_PURGE);
- return(0);
- }
-
- case CFS_ZAPVNODE :
- case CFS_ZAPFILE : {
- struct inode *inode;
- struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
- clstats(CFS_ZAPFILE);
- if ( !fid ) {
- printk("ZAPFILE: Null fid\n");
- return 0;
- }
- CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
- inode = coda_fid_to_inode(fid, sb);
- coda_flag_inode(inode, C_VATTR);
- coda_cache_clear_inode(inode);
- return 0;
- }
- case CFS_PURGEFID : {
- struct inode *inode;
- ViceFid *fid = &out->cfs_purgefid.CodaFid;
- if ( !fid ) {
- printk("PURGEFID: Null fid\n");
- return 0;
- }
- CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
- clstats(CFS_PURGEFID);
- inode = coda_fid_to_inode(fid, sb);
- coda_flag_inode(inode, C_PURGE);
- coda_cache_clear_inode(inode);
- return 0;
- }
- case CFS_REPLACE : {
- printk("CFS_REPLACCE\n");
- clstats(CFS_REPLACE);
- CDEBUG(D_DOWNCALL, "CFS_REPLACE\n");
- coda_cache_clear_all(sb);
- shrink_dcache_sb(sb);
- return (0);
- }
- }
- return 0;
+ /* Handle invalidation requests. */
+ if ( !sb ) {
+ printk("coda_downcall: opcode %d, no sb!\n", opcode);
+ return 0;
+ }
+
+ switch (opcode) {
+
+ case CFS_FLUSH : {
+ clstats(CFS_FLUSH);
+ CDEBUG(D_DOWNCALL, "CFS_FLUSH\n");
+ coda_cache_clear_all(sb);
+ shrink_dcache_sb(sb);
+ return(0);
+ }
+
+ case CFS_PURGEUSER : {
+ struct coda_cred *cred = &out->cfs_purgeuser.cred;
+ CDEBUG(D_DOWNCALL, "CFS_PURGEUSER\n");
+ if ( !cred ) {
+ printk("PURGEUSER: null cred!\n");
+ return 0;
+ }
+ clstats(CFS_PURGEUSER);
+ coda_cache_clear_cred(sb, cred);
+ return(0);
+ }
+
+ case CFS_ZAPDIR : {
+ struct inode *inode;
+ ViceFid *fid = &out->cfs_zapdir.CodaFid;
+ CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid));
+ clstats(CFS_ZAPDIR);
+
+ inode = coda_fid_to_inode(fid, sb);
+ if ( inode ) {
+ coda_flag_inode(inode, C_VATTR);
+ coda_cache_clear_inode(inode);
+ coda_flag_alias_children(inode, C_PURGE);
+ }
+ return(0);
+ }
+
+ case CFS_ZAPFILE : {
+ struct inode *inode;
+ struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
+ clstats(CFS_ZAPFILE);
+ CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
+ inode = coda_fid_to_inode(fid, sb);
+ if ( inode ) {
+ coda_flag_inode(inode, C_VATTR);
+ coda_cache_clear_inode(inode);
+ }
+ return 0;
+ }
+
+ case CFS_PURGEFID : {
+ struct inode *inode;
+ ViceFid *fid = &out->cfs_purgefid.CodaFid;
+ CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
+ clstats(CFS_PURGEFID);
+ inode = coda_fid_to_inode(fid, sb);
+ if ( inode ) {
+ coda_flag_inode(inode, C_PURGE);
+ coda_cache_clear_inode(inode);
+ }
+ return 0;
+ }
+
+ case CFS_REPLACE : {
+ printk("CFS_REPLACCE\n");
+ clstats(CFS_REPLACE);
+ CDEBUG(D_DOWNCALL, "CFS_REPLACE\n");
+ coda_cache_clear_all(sb);
+ shrink_dcache_sb(sb);
+ return (0);
+ }
+ }
+ return 0;
}
EXPORT_SYMBOL(proc_dir_inode_operations);
EXPORT_SYMBOL(proc_net_inode_operations);
EXPORT_SYMBOL(proc_net);
+EXPORT_SYMBOL(proc_bus);
/*
* This is required so that if we load scsi later, that the
*/
static int cp_old_stat(struct inode * inode, struct __old_kernel_stat * statbuf)
{
+ static int warncount = 5;
struct __old_kernel_stat tmp;
- printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n",
- current->comm);
+ if (warncount) {
+ warncount--;
+ printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n",
+ current->comm);
+ }
+
tmp.st_dev = kdev_t_to_nr(inode->i_dev);
tmp.st_ino = inode->i_ino;
tmp.st_mode = inode->i_mode;
#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
} __kernel_fsid_t;
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
#undef __FD_SET
#define __FD_SET(fd,fdsetp) \
__asm__ __volatile__("btsl %1,%0": \
:"a" (0), "c" (__FDSET_LONGS), \
"D" ((__kernel_fd_set *) (fdsetp)) :"cx","di")
+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+
#endif
#define spin_lock_init(x) do { (x)->lock = 0; } while (0)
#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
-#define spin_lock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_lock(%s:%p) already locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0)
-#define spin_unlock_wait(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0)
-#define spin_unlock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s: spin_unlock(%s:%p) not locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0)
-#define spin_lock_irq(x) do {cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_lock_irq(%s:%p) already locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1;} while (0)
-#define spin_unlock_irq(x) do {cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_lock(%s:%p) already locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; sti();} while (0)
-
-#define spin_lock_irqsave(x,flags) do {save_flags(flags); cli(); if ((x)->lock&&(x)->babble) {printk("%s: spin_lock_irqsave(%s:%p) already locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1;} while (0)
-#define spin_unlock_irqrestore(x,flags) do {cli(); if (!(x)->lock&&(x)->babble) {printk("%s: spin_unlock_irqrestore(%s:%p) not locked\n", __BASE_FILE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(flags);} while (0)
+#define spin_lock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0)
+#define spin_unlock_wait(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0)
+#define spin_unlock(x) do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0)
+#define spin_lock_irq(x) do {cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock_irq(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1;} while (0)
+#define spin_unlock_irq(x) do {cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; sti();} while (0)
+
+#define spin_lock_irqsave(x,flags) do {save_flags(flags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock_irqsave(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1;} while (0)
+#define spin_unlock_irqrestore(x,flags) do {cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_irqrestore(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(flags);} while (0)
#endif /* DEBUG_SPINLOCKS */
esp register. */
long int signal; /* Signal that caused the core dump. */
int reserved; /* No longer used */
- struct pt_regs * u_ar0; /* Used by gdb to help find the values for */
+ struct user_pt_regs * u_ar0; /* Used by gdb to help find the values for */
/* the registers. */
struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */
unsigned long magic; /* To uniquely identify a core file */
#ifndef _VUID_T_
#define _VUID_T_
-typedef u_long vuid_t;
-typedef u_long vgid_t;
+typedef unsigned int vuid_t;
+typedef unsigned int vgid_t;
#endif /*_VUID_T_ */
#ifndef _CODACRED_T_
#define CFS_PURGEUSER ((u_long) 26)
#define CFS_ZAPFILE ((u_long) 27)
#define CFS_ZAPDIR ((u_long) 28)
-#define CFS_ZAPVNODE ((u_long) 29)
+/* #define CFS_ZAPVNODE ((u_long) 29) obsolete */
#define CFS_PURGEFID ((u_long) 30)
#define CFS_OPEN_BY_PATH ((u_long) 31)
#define CFS_NCALLS 32
char *coda_f2s(ViceFid *f);
int coda_isroot(struct inode *i);
int coda_fid_is_volroot(struct ViceFid *);
+int coda_fid_is_weird(struct ViceFid *fid);
int coda_iscontrol(const char *name, size_t length);
-/* $Revision: 2.3 $$Date: 1998/03/16 18:01:12 $
+/* $Revision: 2.4 $$Date: 1998/06/01 12:09:53 $
* linux/include/linux/cyclades.h
*
* This file is maintained by Ivan Passos <ivan@cyclades.com>,
*
* This file contains the general definitions for the cyclades.c driver
*$Log: cyclades.h,v $
+ *Revision 2.4 1998/06/01 12:09:53 ivan
+ *removed closing_wait2 from cyclades_port structure;
+ *
*Revision 2.3 1998/03/16 18:01:12 ivan
*changes in the cyclades_port structure to get it closer to the
*standard serial port structure;
*added constants for new ioctls;
+ *
*Revision 2.2 1998/02/17 16:50:00 ivan
*changes in the cyclades_port structure (addition of shutdown_wait and
*chip_rev variables);
#define CZ_DEF_POLL (HZ/25)
#define MAX_BOARD 4 /* Max number of boards */
-#define MAX_PORT 128 /* Max number of ports per board */
#define MAX_DEV 256 /* Max number of ports total */
+#define CYZ_MAX_SPEED 921600
#define CYZ_FIFO_SIZE 16
int x_char; /* to be pushed out ASAP */
int close_delay;
unsigned short closing_wait;
- unsigned short closing_wait2;
unsigned long event;
unsigned long last_active;
int count; /* # of fd on device */
#define Cy_EVENT_OPEN_WAKEUP 4
#define Cy_EVENT_SHUTDOWN_WAKEUP 5
-#define CLOSING_WAIT_DELAY 30
+#define CLOSING_WAIT_DELAY 30*HZ
+#define CY_CLOSING_WAIT_NONE 65535
+#define CY_CLOSING_WAIT_INF 0
+
#define CyMAX_CHIPS_PER_CARD 8
#define CyMAX_CHAR_FIFO 12
#define CyPORTS_PER_CHIP 4
+#define CD1400_MAX_SPEED 115200
#define CyISA_Ywin 0x2000
extern inline int capable(int cap)
{
-#if 0 /* not yet */
+#if 1 /* ok now */
if (cap_raised(current->cap_effective, cap))
#else
if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0)
/*
- * include/linux/serial.h
+ * include/linux/serial_reg.h
*
* Copyright (C) 1992, 1994 by Theodore Ts'o.
*
#ifndef _LINUX_SOCKET_H
#define _LINUX_SOCKET_H
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
#include <asm/socket.h> /* arch-dependent defines */
#include <linux/sockios.h> /* the SIOCxxx I/O controls */
#include <linux/uio.h> /* iovec support */
extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
#endif
+#endif /* not kernel and not glibc */
#endif /* _LINUX_SOCKET_H */
#endif
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
#define S_IFMT 00170000
#define S_IFSOCK 0140000
#define S_IFLNK 0120000
#define S_IWOTH 00002
#define S_IXOTH 00001
+#endif
+
#ifdef __KERNEL__
#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
prev->next_run = p;
}
+static inline void move_first_runqueue(struct task_struct * p)
+{
+ struct task_struct *next = p->next_run;
+ struct task_struct *prev = p->prev_run;
+
+ /* remove from list */
+ next->prev_run = prev;
+ prev->next_run = next;
+ /* add back to list */
+ p->prev_run = &init_task;
+ next = init_task.next_run;
+ init_task.next_run = p;
+ p->next_run = next;
+ next->prev_run = p;
+}
+
/*
* The tasklist_lock protects the linked list of processes.
*
p->policy = policy;
p->rt_priority = lp.sched_priority;
if (p->next_run)
- move_last_runqueue(p);
+ move_first_runqueue(p);
need_resched = 1;
if (current->euid != old_euid)
current->dumpable = 0;
- if(new_ruid != old_ruid) {
+ if (new_ruid != old_ruid) {
/* See comment above about NPROC rlimit issues... */
charge_uid(current, -1);
current->uid = new_ruid;
int old_ruid = current->uid;
int old_euid = current->euid;
int old_suid = current->suid;
- if (current->uid != 0 && current->euid != 0 && current->suid != 0) {
+ if (!capable(CAP_SETUID)) {
if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
(ruid != current->euid) && (ruid != current->suid))
return -EPERM;
*/
asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
{
- if (current->uid != 0 && current->euid != 0 && current->suid != 0) {
+ if (!capable(CAP_SETGID)) {
if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
(rgid != current->egid) && (rgid != current->sgid))
return -EPERM;
current->dumpable = 0;
/* We emulate fsuid by essentially doing a scaled-down version
- * of what we did in setresuid and friends. However, we only
- * operate on the fs-specific bits of the process' effective
- * capabilities
- *
- * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
- * if not, we might be a bit too harsh here.
- */
+ * of what we did in setresuid and friends. However, we only
+ * operate on the fs-specific bits of the process' effective
+ * capabilities
+ *
+ * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
+ * if not, we might be a bit too harsh here.
+ */
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
if (old_fsuid == 0 && current->fsuid != 0) {
read_lock(&tasklist_lock);
for_each_task(p) {
if (p->pgrp == current->pid)
- goto out;
+ goto out;
}
current->leader = 1;
i = current->ngroups;
if (gidsetsize) {
if (i > gidsetsize)
- return -EINVAL;
+ return -EINVAL;
if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
return -EFAULT;
}
}
asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
- unsigned long arg4, unsigned long arg5)
+ unsigned long arg4, unsigned long arg5)
{
int error = 0;
int sig;
case PR_SET_PDEATHSIG:
sig = arg2;
if (sig > _NSIG) {
- error = -EINVAL;
- break;
- }
- current->pdeath_signal = sig;
- break;
+ error = -EINVAL;
+ break;
+ }
+ current->pdeath_signal = sig;
+ break;
default:
error = -EINVAL;
break;
- }
- return error;
+ }
+ return error;
}
static unsigned long tcp_lastsynq_overflow;
/*
- * This table has to be sorted. Only 8 entries are allowed and the
- * last entry has to be duplicated.
+ * This table has to be sorted and terminated with (__u16)-1.
* XXX generate a better table.
* Unresolved Issues: HIPPI with a 64k MSS is not well supported.
*/
static __u16 const msstab[] = {
- 64,
- 256,
- 512,
- 536,
- 1024,
- 1440,
- 1460,
- 4312,
- 4312
+ 64-1,
+ 256-1,
+ 512-1,
+ 536-1,
+ 1024-1,
+ 1440-1,
+ 1460-1,
+ 4312-1,
+ (__u16)-1
};
-
-static __u32 make_syncookie(struct sk_buff *skb, __u32 counter, __u32 seq)
-{
- __u32 z;
-
- z = secure_tcp_syn_cookie(skb->nh.iph->saddr, skb->nh.iph->daddr,
- skb->h.th->source, skb->h.th->dest,
- seq,
- counter);
-
-#if 0
- printk(KERN_DEBUG
- "msc: z=%u,cnt=%u,seq=%u,sadr=%u,dadr=%u,sp=%u,dp=%u\n",
- z,counter,seq,
- skb->nh.iph->saddr,skb->nh.iph->daddr,
- ntohs(skb->h.th->source), ntohs(skb->h.th->dest));
-#endif
-
- return z;
-}
+/* The number doesn't include the -1 terminator */
+#define NUM_MSS (sizeof(msstab)/sizeof(msstab[0]) - 1)
/*
- * Generate a syncookie.
+ * Generate a syncookie. mssp points to the mss, which is returned
+ * rounded down to the value encoded in the cookie.
*/
__u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
__u16 *mssp)
{
- int i;
- __u32 isn;
- const __u16 mss = *mssp, *w;
+ int mssind;
+ const __u16 mss = *mssp;
tcp_lastsynq_overflow = jiffies;
-
- isn = make_syncookie(skb, (jiffies/HZ) >> 6, ntohl(skb->h.th->seq));
-
- /* XXX sort msstab[] by probability? */
- w = msstab;
- for (i = 0; i < 8; i++)
- if (mss >= *w && mss < *++w)
- goto found;
- i--;
-found:
- *mssp = w[-1];
+ /* XXX sort msstab[] by probability? Binary search? */
+ for (mssind = 0; mss > msstab[mssind+1]; mssind++)
+ ;
+ *mssp = msstab[mssind]+1;
net_statistics.SyncookiesSent++;
- isn |= i;
- return isn;
+ return secure_tcp_syn_cookie(skb->nh.iph->saddr, skb->nh.iph->daddr,
+ skb->h.th->source, skb->h.th->dest,
+ ntohl(skb->h.th->seq),
+ jiffies / (HZ*60), mssind);
}
-/* This value should be dependent on TCP_TIMEOUT_INIT and
- * sysctl_tcp_retries1. It's a rather complicated formula
- * (exponential backoff) to compute at runtime so it's currently hardcoded
- * here.
+/*
+ * This (misnamed) value is the age of syncookie which is permitted.
+ * Its ideal value should be dependent on TCP_TIMEOUT_INIT and
+ * sysctl_tcp_retries1. It's a rather complicated formula (exponential
+ * backoff) to compute at runtime so it's currently hardcoded here.
*/
#define COUNTER_TRIES 4
-
/*
* Check if a ack sequence number is a valid syncookie.
+ * Return the decoded mss if it is, or 0 if not.
*/
static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
{
- int mssind;
- int i;
- __u32 counter;
__u32 seq;
+ __u32 mssind;
- if ((jiffies - tcp_lastsynq_overflow) > TCP_TIMEOUT_INIT
- && tcp_lastsynq_overflow) {
+ if ((jiffies - tcp_lastsynq_overflow) > TCP_TIMEOUT_INIT)
return 0;
- }
-
- mssind = cookie & 7;
- cookie &= ~7;
- counter = (jiffies/HZ)>>6;
seq = ntohl(skb->h.th->seq)-1;
- for (i = 0; i < COUNTER_TRIES; i++)
- if (make_syncookie(skb, counter-i, seq) == cookie)
- return msstab[mssind];
+ mssind = check_tcp_syn_cookie(cookie,
+ skb->nh.iph->saddr, skb->nh.iph->daddr,
+ skb->h.th->source, skb->h.th->dest,
+ seq, jiffies/(HZ*60), COUNTER_TRIES);
- return 0;
+ return mssind < NUM_MSS ? msstab[mssind]+1 : 0;
}
extern struct or_calltable or_ipv4;
&& (pdata->state != SPX_CONNECTED))
{
pdata->state = SPX_CONNECTED;
- pdatat->dest_connid = ipxh->spx.sconn;
+ pdata->dest_connid = ipxh->spx.sconn;
if(spx_retransmit_chk(pdata, 0, CONACK) < 0)
goto toss_skb;
// command-line argument, and redirect the oops-log into stdin. Out
// will come the EIP and call-trace in symbolic form.
+// Changed by Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+// adapted to Linux/m68k
+
//////////////////////////////////////////////////////////////////////////////
// BUGS:
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
+#include <a.out.h>
-inline int strnequ(char const* x, char const* y, size_t n) { return (::strncmp(x, y, n) == 0); }
+inline int strnequ(char const* x, char const* y, size_t n) { return (strncmp(x, y, n) == 0); }
const int code_size = 20;
/* This is a hack to avoid using gcc. We create an object file by
concatenating objfile_head, the twenty bytes of code, and
objfile_tail. */
- unsigned char objfile_head[] = {
- 0x07, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ static struct exec objfile_head = {
+ OMAGIC, code_size + 4, 0, 0, sizeof (struct nlist) * 3, 0, 0, 0
};
- unsigned char objfile_tail[] = {
- 0x00, 0x90, 0x90, 0x90,
- 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
- 'g', 'c', 'c', '2', '_', 'c', 'o', 'm',
- 'p', 'i', 'l', 'e', 'd', '.', '\0', '_',
- 'E', 'I', 'P', '\0', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', '\0', '\0'
+ static struct {
+ unsigned char tail[4];
+ struct nlist syms[3];
+ unsigned long strsize;
+ char strings[42];
+ } objfile_tail = {
+#ifdef i386
+ { 0x00, 0x90, 0x90, 0x90 },
+#endif
+#ifdef mc68000
+ { 0x00, 0x00, 0x00, 0x00 },
+#endif
+ { { (char *) 4, N_TEXT, 0, 0, 0 },
+ { (char *) 19, N_TEXT, 0, 0, 0 },
+ { (char *) 37, N_TEXT | N_EXT, 0, 0, 0 } },
+ 42,
+ "gcc2_compiled.\0___gnu_compiled_c\0_EIP\0"
};
char const* objdump_command = "objdump -d oops_decode.o";
char const* objfile_name = &objdump_command[11];
ofstream objfile_stream(objfile_name);
- objfile_stream.write(objfile_head, sizeof(objfile_head));
+ objfile_stream.write((char *) &objfile_head, sizeof(objfile_head));
objfile_stream.write(code, code_size);
- objfile_stream.write(objfile_tail, sizeof(objfile_tail));
+ objfile_stream.write((char *) &objfile_tail, sizeof(objfile_tail));
objfile_stream.close();
FILE* objdump_FILE = popen(objdump_command, "r");
memset(newbuf, '\0', sizeof(newbuf));
ostrstream ost(newbuf, sizeof(newbuf));
ost.width(8);
- ost << offset;
- ost << " <_EIP+" << offset << ">: " << &buf[6] << ends;
+ ost << hex << offset;
+ ost << " <_EIP+" << hex << offset << ">: " << &buf[6] << ends;
strcpy(buf, newbuf);
}
if (!strnequ(&buf[9], "<_EIP", 5))
bp++;
if (!isxdigit(*bp)) {
cout << bp_0;
+#ifdef i386
} else if (*bp_1 == 'j' || strnequ(bp_1, "call", 4)) { // a jump or call insn
long rel_addr = strtol(bp, 0, 16);
ksym = find(eip_addr + rel_addr);
cout << bp_0 << *ksym << endl;
} else
cout << bp_0;
+#endif
+#ifdef mc68000
+ } else if ((bp_1[0] == 'b' && bp_1[4] == ' ' && strchr("swl", bp_1[3]))
+ || (bp_1[0] == 'd' && bp_1[1] == 'b')) {
+ // a branch or decr-and-branch insn
+ if (bp_1[0] == 'd') // skip register
+ while (*bp && *bp++ != ',');
+ long rel_addr = strtoul(bp, 0, 16);
+ ksym = find(eip_addr + rel_addr);
+ if (ksym) {
+ *bp++ = '\0';
+ cout << bp_0 << *ksym << endl;
+ } else
+ cout << bp_0;
+#endif
} else {
cout << bp_0;
}
if (cin.eof())
break;
cin.get(c); /* swallow newline */
+#ifdef i386
if (strstr(buffer, "EIP:") && names.valid()) {
oops_column = strstr(buffer, "EIP:");
if (sscanf(oops_column+13, "[<%x>]", &eip_addr) != 1) {
else
cout << ::hex << eip_addr << " cannot be resolved" << endl;
}
+#endif
+#ifdef mc68000
+ if (strstr(buffer, "PC:") && names.valid()) {
+ oops_column = strstr(buffer, "PC:");
+ if (sscanf(oops_column+4, "[<%x>]", &eip_addr) != 1) {
+ cout << "Cannot read pc address from PC: line. Is this a valid oops file?" << endl;
+ exit(1);
+ }
+ cout << ">>PC: ";
+ KSym* ksym = names.find(eip_addr);
+ if (ksym)
+ cout << *ksym << endl;
+ else
+ cout << ::hex << eip_addr << " cannot be resolved" << endl;
+ }
+#endif
else if (oops_column && strstr(oops_column, "[<") && names.valid()) {
unsigned long address;
while (strstr(oops_column, "[<")) {
++p;
if (sscanf(p, "%x", &c) != 1)
break;
+#ifdef mc68000
+ *cp++ = c >> 8;
+#endif
*cp++ = c;
while (*p && *p++ != ' ')
;