Commit ddb701b2 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.52

parent a6d938f4
......@@ -529,6 +529,7 @@ S: Canada
N: Richard Gnther
E: richard.guenther@student.uni-tuebingen.de
P: 2048/2E829319 2F 83 FC 93 E9 E4 19 E2 93 7A 32 42 45 37 23 57
D: binfmt_misc
S: Fichtenweg 3/511
S: 72076 Tbingen
......@@ -1467,10 +1468,12 @@ S: MacGregor A.C.T
S: 2615 Australia
N: Winfried Trmper
E: truemper@MI.Uni-Koeln.DE
D: German HOWTO, Enhanced German HOWTO, Crash-Kurs Linux (German)
D: 1- or 5-days tutorials on Linux twice a year (free of charge)
D: Linux-Workshop Kln (aka LUUG cologne, germany)
E: winni@xpilot.org
W: http://www.shop.de/~winni/
D: German HOWTO, Crash-Kurs Linux (German, 100 comprehensive pages)
D: CD-Writing HOWTO, various mini-HOWTOs
D: one-week tutorials on Linux twice a year (free of charge)
D: Linux-Workshop Kln (aka LUG Cologne, Germany), Installfests
S: Tacitusstr. 6
S: D-50968 Kln
......
......@@ -54,6 +54,7 @@ running, the suggested command should tell you.
- Autofs 0.3.7 ; automount --version
- NFS 0.4.21 ; showmount --version
- Bash 1.14.7 ; bash -version
- Smbfs 2.1.0
Upgrade notes
*************
......@@ -160,6 +161,10 @@ to a 2.6 release. Also, amd is being phased out in favor of the much
better autofs. You'll also have to get the appropriate utils to use
autofs as well as the new NFS utils.
The smbfs code is also being revised. This results in an incompatible
mount interface. See the README of smbfs-2.1.0 or later for a
description of the new mount command.
RPM
===
......
......@@ -1982,12 +1982,10 @@ NCR53C8XX SCSI support
CONFIG_SCSI_NCR53C8XX
This is the BSD ncr driver adapted to linux for the NCR53C8XX family
of PCI-SCSI controllers. This driver supports parity checking,
tagged command queuing, fast scsi II transfer up to 10 MB/s with
narrow scsi devices and 20 MB/s with wide scsi devices.
Support of Ultra SCSI data transfers with NCR53C860 and NCR53C875
controllers has been recently added to the driver.
tagged command queuing, Fast-20 data transfer up to 20 MB/s with
narrow scsi devices and 40 MB/s with wide scsi devices.
Please read drivers/scsi/README.ncr53c8xx for more information.
Linux/i386 and Linux/Alpha are supported by this driver.
Linux/i386, Linux/Alpha and Linux/PPC are supported by this driver.
synchronous data transfers frequency
CONFIG_SCSI_NCR53C8XX_SYNC
......@@ -2015,10 +2013,11 @@ use normal IO
CONFIG_SCSI_NCR53C8XX_IOMAPPED
This option allows you to force the driver to use normal IO.
Memory mapped IO has less latency than normal IO and works for most
Intel-based hardware.
Under Linux/Alpha only normal IO is currently supported by the driver
and so, this option has no effect.
The normal answer therefore is N. Try Y only if you have problems.
Intel-based hardware. Under Linux/Alpha and Linux/PPC only normal
IO is currently supported by the driver and so, this option has no
effect. On Linux/PPC MMIO and normal IO are done the same (all IO
is memory mapped) so you loose nothing by using normal IO. The normal
answer therefore is N. Try Y only if you have problems.
not allow targets to disconnect
CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
......
......@@ -9,7 +9,7 @@ To achieve this you must tell binfmt_misc which interpreter has to be invoked
with which binary. Binfmt_misc recognises the binary-type by matching some bytes
at the beginning of the file with a magic byte sequence (masking out specified
bits) you have supplied. Binfmt_misc can also recognise a filename extension
(aka .com) and optionally strip it off.
aka '.com' or '.exe'.
To actually register a new binary type, you have to set up a string looking like
:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon
......@@ -18,44 +18,46 @@ Here is what the fields mean:
- 'name' is an identifier string. A new /proc file will be created with this
name below /proc/sys/fs/binfmt_misc
- 'type' is the type of recognition. Give 'M' for magic and 'E' for extension.
Give the corresponding lowercase letter to let binfmt_misc strip off the
filename extension.
- 'offset' is the offset of the magic/mask in the file, counted in bytes. This
defaults to 0 if you omit it (i.e. you write ':name:type::magic...')
- 'magic' is the byte sequence binfmt_misc is matching for. The magic string
may contain hex-encoded characters like \x0a or \xA4. In a shell environment
you will have to write \\x0a to prevent the shell from eating your \.
If you chose filename extension matching, this is the extension to be
recognised (the \x0a specials are not allowed). Extension matching is case
sensitive!
recognised (without the '.', the \x0a specials are not allowed). Extension
matching is case sensitive!
- 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some
bits from matching by supplying a string like magic and as long as magic.
The mask is anded with the byte sequence of the file.
- 'interpreter' is the program that should be invoked with the binary as first
argument (specify the full path)
There are some restrictions:
- the whole register string may not exceed 255 characters
- the magic must resist in the first 128 bytes of the file, i.e.
offset+size(magic) has to be less than 128
- the interpreter string may not exceed 127 characters
You may want to add the binary formats in one of your /etc/rc scripts during
boot-up. Read the manual of your init program to figure out how to do this
right.
Think about the order of adding entries! Later added entries are matched first!
A few examples (assumed you are in /proc/sys/fs/binfmt_misc):
- enable support for em86 (like binfmt_em86, for Alpha AXP only):
echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
echo ':i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:' > register
echo ':i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:' > register
- enable support for packed DOS applications (pre-configured dosemu hdimages):
echo ":DEXE:M::\x0eDEX::/usr/bin/dosexec:" > register
echo ':DEXE:M::\x0eDEX::/usr/bin/dosexec:' > register
- enable support for DOS/Windows executables (using mzloader and dosemu/wine):
echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register
echo ":DOScom:E::com::/usr/sbin/mzloader:" > register
echo ":DOSexe:E::exe::/usr/sbin/mzloader:" > register
echo ':DOSWin:M::MZ::/usr/sbin/mzloader:' > register
echo ':DOScom:E::com::/usr/sbin/mzloader:' > register
echo ':DOSexe:E::exe::/usr/sbin/mzloader:' > register
You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable)
......@@ -71,11 +73,11 @@ Emulating binfmt_java:
To emulate binfmt_java the following register-strings could be used:
for compiled Java programs use
":Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:"
':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:'
for simple applet support use
":Applet:E::html::/usr/local/java/bin/appletviewer:"
':Applet:E::html::/usr/local/java/bin/appletviewer:'
for more selective applet support (like binfmt_java) use
":Applet:M::\<\!--applet::/usr/local/java/bin/appletviewer:"
':Applet:M::<!--applet::/usr/local/java/bin/appletviewer:'
Note, that for the more selective applet support you have to modify
existing html-files to contain <!--applet--> in the first line to
......@@ -94,7 +96,7 @@ CLASS=$1
if [ -L "$1" ] ; then
CLASS=`ls --color=no -l $1 | tr -s '\t ' ' ' | cut -d ' ' -f 11`
fi
CLASSN=`basename $CLASS | sed s/\.class$//`
CLASSN=`basename $CLASS .class`
CLASSP=`dirname $CLASS`
FOO=$PATH
......
......@@ -8,6 +8,6 @@ NetBIOS over TCP/IP. There you also find explanation for concepts like
netbios name or share.
To use smbfs, you need a special mount program, which can be found in
the ksmbfs package, found on
the smbfs package, found on
sunsite.unc.edu:/pub/Linux/system/filesystems/smbfs
ftp://ftp.gwdg.de/pub/linux/misc/smbfs/
Ioctl Numbers
7 Aug 1997
1 Sep 1997
Michael Chastain
<mec@shout.net>
......@@ -106,6 +106,8 @@ Code Seq# Include File Comments
'u' all linux/smb_fs.h
'v' all linux/ext2_fs.h
'w' all CERN SCI driver in development
'z' 00-3F CAN bus card in development:
<mailto:hdstich@connectu.ulm.circular.de>
0x89 00-0F asm-i386/sockios.h
0x89 10-DF linux/sockios.h
0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range
......
......@@ -449,7 +449,7 @@ PARALLEL PORT SHARING SUPPORT
P: Phil Blundell
M: Philip.Blundell@pobox.com
P: Tim Waugh
M: tmw20@cyberelk.demon.co.uk
M: tim@cyberelk.demon.co.uk
P: David Campbell
M: campbell@tirian.che.curtin.edu.au
L: linux-parport@torque.net
......
VERSION = 2
PATCHLEVEL = 1
SUBLEVEL = 51
SUBLEVEL = 52
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
......
......@@ -94,9 +94,9 @@ bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
tristate 'Parallel port support' CONFIG_PARPORT
......
......@@ -43,7 +43,7 @@ CONFIG_SYSCTL=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_EM86=y
# CONFIG_PNP_PARPORT is not set
# CONFIG_PARPORT is not set
#
# Plug and Play support
......@@ -67,7 +67,6 @@ CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_BLK_DEV_XD is not set
# CONFIG_BLK_DEV_EZ is not set
# CONFIG_BLK_DEV_HD is not set
......@@ -142,6 +141,7 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
CONFIG_SCSI_QLOGIC_ISP=y
......@@ -150,6 +150,8 @@ CONFIG_SCSI_QLOGIC_ISP=y
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_MESH is not set
# CONFIG_SCSI_MAC53C94 is not set
#
# Network device support
......@@ -174,6 +176,7 @@ CONFIG_DE4X5=y
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_NET_RADIO is not set
# CONFIG_SLIP is not set
......@@ -215,6 +218,7 @@ CONFIG_ISO9660_FS=y
# CONFIG_ROMFS_FS is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_UFS_FS is not set
# CONFIG_MAC_PARTITION is not set
#
# Character devices
......@@ -230,12 +234,15 @@ CONFIG_MOUSE=y
# CONFIG_MS_BUSMOUSE is not set
CONFIG_PSMOUSE=y
# CONFIG_82C710_MOUSE is not set
# CONFIG_PC110_PAD is not set
# CONFIG_UMISC is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_FTAPE is not set
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
# CONFIG_NVRAM is not set
# CONFIG_JOYSTICK is not set
#
# Sound
......
......@@ -437,8 +437,8 @@ entUnaUser:
stq $13,32($30)
stq $14,40($30)
stq $15,48($30)
bis $31,$30,$19
lda $8,0x3fff
addq $30,56,$19
bic $30,$8,$8
jsr $26,do_entUnaUser
ldq $9,0($30)
......
......@@ -491,8 +491,22 @@ static inline unsigned long s_reg_to_mem (unsigned long s_reg)
| 1L << 0x2c | 1L << 0x2d /* stl stq */ \
| 1L << 0xd ) /* stw */
#define R(x) ((size_t) &((struct pt_regs *)0)->x)
static int unauser_reg_offsets[32] = {
R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), R(r8),
/* r9 ... r15 are stored in front of regs. */
-56, -48, -40, -32, -24, -16, -8,
R(r16), R(r17), R(r18),
R(r19), R(r20), R(r21), R(r22), R(r23), R(r24), R(r25), R(r26),
R(r27), R(r28), R(gp),
0, 0
};
#undef R
asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
unsigned long reg, unsigned long * frame)
unsigned long reg, struct pt_regs *regs)
{
extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
extern unsigned long alpha_read_fp_reg (unsigned long reg);
......@@ -501,12 +515,10 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
static long last_time = 0;
unsigned long tmp1, tmp2, tmp3, tmp4;
unsigned long *reg_addr, *pc_addr, fake_reg;
unsigned long fake_reg, *reg_addr = &fake_reg;
unsigned long uac_bits;
long error;
pc_addr = frame + 7 + 20 + 1; /* pc in PAL frame */
/* Check the UAC bits to decide what the user wants us to do
with the unaliged access. */
......@@ -519,7 +531,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
lock_kernel();
printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
current->comm, current->pid,
*pc_addr - 4, va, opcode, reg);
regs->pc - 4, va, opcode, reg);
unlock_kernel();
}
last_time = jiffies;
......@@ -540,51 +552,19 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
++unaligned[1].count;
unaligned[1].va = (unsigned long)va;
unaligned[1].pc = *pc_addr - 4;
unaligned[1].pc = regs->pc - 4;
reg_addr = frame;
if ((1L << opcode) & OP_INT_MASK) {
/* it's an integer load/store */
switch (reg) {
case 0: case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8:
/* v0-t7 in SAVE_ALL frame */
reg_addr += 7 + reg;
break;
case 9: case 10: case 11: case 12:
case 13: case 14: case 15:
/* s0-s6 in entUna frame */
reg_addr += (reg - 9);
break;
case 16: case 17: case 18:
/* a0-a2 in PAL frame */
reg_addr += 7 + 20 + 3 + (reg - 16);
break;
case 19: case 20: case 21: case 22: case 23:
case 24: case 25: case 26: case 27: case 28:
/* a3-at in SAVE_ALL frame */
reg_addr += 7 + 9 + (reg - 19);
break;
case 29:
/* gp in PAL frame */
reg_addr += 7 + 20 + 2;
break;
case 30:
if (reg < 30) {
reg_addr = (unsigned long *)
((char *)regs + unauser_reg_offsets[reg]);
} else if (reg == 30) {
/* usp in PAL regs */
fake_reg = rdusp();
reg_addr = &fake_reg;
break;
case 31:
} else {
/* zero "register" */
fake_reg = 0;
reg_addr = &fake_reg;
break;
}
}
......@@ -728,7 +708,6 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
case 0x26: /* sts */
fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg));
reg_addr = &fake_reg;
/* FALLTHRU */
case 0x2c: /* stl */
......@@ -763,7 +742,6 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
case 0x27: /* stt */
fake_reg = alpha_read_fp_reg(reg);
reg_addr = &fake_reg;
/* FALLTHRU */
case 0x2d: /* stq */
......@@ -807,14 +785,14 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
return;
give_sigsegv:
*pc_addr -= 4; /* make pc point to faulting insn */
regs->pc -= 4; /* make pc point to faulting insn */
lock_kernel();
force_sig(SIGSEGV, current);
unlock_kernel();
return;
give_sigbus:
*pc_addr -= 4;
regs->pc -= 4;
lock_kernel();
force_sig(SIGBUS, current);
unlock_kernel();
......
......@@ -36,7 +36,7 @@ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
choice 'Processor type' \
......
......@@ -52,9 +52,7 @@ bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
fi
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_AMIGA" = "y" ]; then
bool 'Amiga AutoConfig Identification' CONFIG_ZORRO
......
......@@ -77,7 +77,8 @@ fi
define_bool CONFIG_BINFMT_ELF y
define_bool CONFIG_BINFMT_AOUT n
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
bool 'Networking support' CONFIG_NET
bool 'System V IPC' CONFIG_SYSVIPC
......
......@@ -46,7 +46,7 @@ bool 'System V IPC' CONFIG_SYSVIPC
define_bool CONFIG_BINFMT_ELF y
define_bool CONFIG_KERNEL_ELF y
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
if [ "$CONFIG_PMAC" = "y" ]; then
define_bool CONFIG_PMAC_CONSOLE y
......
......@@ -53,9 +53,9 @@ bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
endmenu
......
......@@ -57,11 +57,9 @@ if [ "$CONFIG_SPARC32_COMPAT" != "n" ]; then
tristate 'Kernel support for 32-bit ELF binaries' CONFIG_BINFMT_ELF32
bool 'Kernel support for 32-bit (ie. SunOS) a.out binaries' CONFIG_BINFMT_AOUT32
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi
endmenu
......
......@@ -36,11 +36,11 @@
/* if you have more than 3 printers, remember to increase LP_NO */
struct lp_struct lp_table[] =
{
{NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0,
{NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
{0}},
{NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0,
{NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
{0}},
{NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0,
{NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
{0}}
};
#define LP_NO 3
......@@ -60,6 +60,41 @@ static char *dev_name = "lp";
#undef LP_DEBUG
#undef LP_READ_DEBUG
static inline void lp_parport_release (int minor)
{
parport_release (lp_table[minor].dev);
lp_table[minor].should_relinquish = 0;
}
static inline void lp_parport_claim (int minor)
{
if (parport_claim (lp_table[minor].dev))
sleep_on (&lp_table[minor].lp_wait_q);
}
static inline void lp_schedule (int minor)
{
if (lp_table[minor].should_relinquish) {
lp_parport_release (minor);
schedule ();
lp_parport_claim (minor);
}
else
schedule ();
}
static int lp_preempt (void *handle)
{
struct lp_struct *lps = (struct lp_struct *)handle;
/* Just remember that someone wants the port */
lps->should_relinquish = 1;
/* Don't actually release the port now */
return 1;
}
static int lp_reset(int minor)
{
w_ctr(minor, LP_PSELECP);
......@@ -70,7 +105,8 @@ static int lp_reset(int minor)
static inline int lp_char_polled(char lpchar, int minor)
{
int status, wait = 0;
int status;
unsigned int wait = 0;
unsigned long count = 0;
struct lp_stats *stats;
......@@ -78,7 +114,7 @@ static inline int lp_char_polled(char lpchar, int minor)
status = r_str(minor);
count++;
if (need_resched)
schedule();
lp_schedule (minor);
} while (!LP_READY(minor, status) && count < LP_CHAR(minor));
if (count == LP_CHAR(minor)) {
......@@ -90,11 +126,11 @@ static inline int lp_char_polled(char lpchar, int minor)
stats->chars++;
/* must wait before taking strobe high, and after taking strobe
low, according spec. Some printers need it, others don't. */
while (wait != LP_WAIT(minor))
while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */
wait++;
/* control port takes strobe high */
w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
while (wait)
while (wait) /* FIXME: should be a udelay() */
wait--;
/* take strobe low */
w_ctr(minor, LP_PSELECP | LP_PINITP);
......@@ -116,14 +152,14 @@ static inline int lp_char_polled(char lpchar, int minor)
static inline int lp_char_interrupt(char lpchar, int minor)
{
int wait;
unsigned int wait;
unsigned long count = 0;
unsigned char status;
struct lp_stats *stats;
do {
if(need_resched)
schedule();
lp_schedule (minor);
if ((status = r_str(minor)) & LP_PBUSY) {
if (!LP_CAREFUL_READY(minor, status))
return 0;
......@@ -133,12 +169,12 @@ static inline int lp_char_interrupt(char lpchar, int minor)
/* must wait before taking strobe high, and after taking strobe
low, according spec. Some printers need it, others don't. */
wait = 0;
while (wait != LP_WAIT(minor))
wait++;
while (wait != LP_WAIT(minor)) /* FIXME: should be */
wait++; /* a udelay () */
/* control port takes strobe high */
w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
while (wait)
wait--;
wait--; /* FIXME: should be a udelay() */
/* take strobe low */
w_ctr(minor, LP_PSELECP | LP_PINITP);
/* update waittime statistics */
......@@ -164,7 +200,7 @@ static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct pardevice *pd = pb->cad;
struct lp_struct *lp_dev = (struct lp_struct *) pd->private;
if (lp_dev->lp_wait_q)
if (waitqueue_active (&lp_dev->lp_wait_q))
wake_up(&lp_dev->lp_wait_q);
}
......@@ -211,7 +247,8 @@ static inline int lp_write_interrupt(unsigned int minor, const char *buf, int co
}
LP_STAT(minor).sleeps++;
cli();
w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
enable_irq(lp->dev->port->irq);
w_ctr(minor, LP_PSELECP|LP_PINITP|LP_PINTEN);
status = r_str(minor);
if ((!(status & LP_PACK) || (status & LP_PBUSY))
&& LP_CAREFUL_READY(minor, status)) {
......@@ -222,6 +259,7 @@ static inline int lp_write_interrupt(unsigned int minor, const char *buf, int co
lp_table[minor].runchars = 0;
current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
interruptible_sleep_on(&lp->lp_wait_q);
w_ctr(minor, LP_PSELECP | LP_PINITP);
sti();
if (current->signal & ~current->blocked) {
......@@ -267,7 +305,7 @@ static inline int lp_write_polled(unsigned int minor, const char *buf, int count
return temp-buf?temp-buf:-ENOSPC;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
schedule();
lp_schedule (minor);
} else
if (!(status & LP_PSELECD)) {
printk(KERN_INFO "lp%d off-line\n", minor);
......@@ -275,7 +313,7 @@ static inline int lp_write_polled(unsigned int minor, const char *buf, int count
return temp-buf?temp-buf:-EIO;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
schedule();
lp_schedule (minor);
} else
/* not offline or out of paper. on fire? */
if (!(status & LP_PERRORP)) {
......@@ -284,7 +322,7 @@ static inline int lp_write_polled(unsigned int minor, const char *buf, int count
return temp-buf?temp-buf:-EIO;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
schedule();
lp_schedule (minor);
}
/* check for signals before going to sleep */
......@@ -302,7 +340,7 @@ static inline int lp_write_polled(unsigned int minor, const char *buf, int count
lp_table[minor].runchars=0;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIME(minor);
schedule();
lp_schedule (minor);
}
}
return temp-buf;
......@@ -322,16 +360,14 @@ static long lp_write(struct inode * inode, struct file * file,
/* Claim Parport or sleep until it becomes available
* (see lp_wakeup() for details)
*/
if (parport_claim(lp_table[minor].dev)) {
sleep_on(&lp_table[minor].lp_wait_q);
lp_table[minor].lp_wait_q = NULL;
}
lp_parport_claim (minor);
if (LP_IRQ(minor) > 0)
retv = lp_write_interrupt(minor, buf, count);
else
retv = lp_write_polled(minor, buf, count);
parport_release(lp_table[minor].dev);
lp_parport_release (minor);
return retv;
}
......@@ -370,10 +406,7 @@ static long lp_read(struct inode * inode, struct file * file,
/* Claim Parport or sleep until it becomes available
* (see lp_wakeup() for details)
*/
if (parport_claim(lp_table[minor].dev)) {
sleep_on(&lp_table[minor].lp_wait_q);
lp_table[minor].lp_wait_q = NULL;
}
lp_parport_claim (minor);
temp=buf;
#ifdef LP_READ_DEBUG
......@@ -399,7 +432,7 @@ static long lp_read(struct inode * inode, struct file * file,
udelay(50);
counter++;
if (need_resched)
schedule();
lp_schedule (minor);
} while ( (status == 0x40) && (counter < 20) );
if ( counter == 20 ) { /* Timeout */
#ifdef LP_READ_DEBUG
......@@ -418,7 +451,7 @@ static long lp_read(struct inode * inode, struct file * file,
udelay(20);
counter++;
if (need_resched)
schedule();
lp_schedule (minor);
} while ( (status == 0) && (counter < 20) );
if (counter == 20) { /* Timeout */
#ifdef LP_READ_DEBUG
......@@ -434,7 +467,7 @@ static long lp_read(struct inode * inode, struct file * file,
}
current->state=TASK_INTERRUPTIBLE;
current->timeout=jiffies + LP_TIME(minor);
schedule();
lp_schedule (minor);
}
counter=0;
if (( i & 1) != 0) {
......@@ -656,7 +689,7 @@ void lp_wakeup(void *ref)
{
struct lp_struct *lp_dev = (struct lp_struct *) ref;
if (!lp_dev->lp_wait_q)
if (!waitqueue_active (&lp_dev->lp_wait_q))
return; /* Wake up whom? */
/* Claim the Parport */
......@@ -691,8 +724,8 @@ int lp_init(void)
(parport[0] == -3 &&
pb->probe_info.class == PARPORT_CLASS_PRINTER)) {
lp_table[count].dev =
parport_register_device(pb, dev_name, NULL,
lp_wakeup,
parport_register_device(pb, dev_name,
lp_preempt, lp_wakeup,
lp_interrupt, PARPORT_DEV_TRAN,
(void *) &lp_table[count]);
lp_table[count].flags |= LP_EXIST;
......
......@@ -530,7 +530,8 @@ __initfunc(int chr_dev_init(void))
defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
defined (CONFIG_AMIGAMOUSE) || defined (CONFIG_ATARIMOUSE) || \
defined (CONFIG_PCWATCHDOG) || \
defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE)
defined (CONFIG_APM) || defined (CONFIG_RTC) || \
defined (CONFIG_SUN_MOUSE) || defined (CONFIG_NVRAM)
misc_init();
#endif
#ifdef CONFIG_SOUND
......
......@@ -490,6 +490,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KIOCSOUND:
if (!perm)
return -EPERM;
if (arg)
arg = 1193180 / arg;
kd_mksound(arg, 0);
return 0;
......@@ -505,6 +507,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
count = ticks ? (arg & 0xffff) : 0;
if (count)
count = 1193180 / count;
kd_mksound(count, ticks);
return 0;
}
......
Currently known (or at least suspected) bugs in parport:
o /proc/parport is untested under 2.0.XX
o SCSI aborts for PPA under 2.0.29 [reported by jmr]. Under investigation.
o make config (etc) allow you to select CONFIG_PNP_PARPORT=m, CONFIG_PPA=y -
the resulting kernel won't link.
o IEEE1284 code does not do the terminating handshake after transfers, which
seems to upset some devices.
......
/* $Id$
* Parallel-port routines for ARC onboard hardware.
/* Parallel-port routines for ARC onboard hardware.
*
* Author: Phil Blundell <pjb27@cam.ac.uk>
* Author: Phil Blundell <Philip.Blundell@pobox.com>
*/
#include <linux/tasks.h>
......@@ -37,6 +36,20 @@ static unsigned int arc_read_data(struct parport *p)
return data_copy;
}
static void arc_inc_use_count(void)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
static void arc_dec_use_count(void)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
static struct parport_operations arc_ops =
{
arc_write_data,
......@@ -72,5 +85,8 @@ static struct parport_operations arc_ops =
arc_enable_irq,
arc_disable_irq,
arc_examine_irq
arc_examine_irq,
arc_inc_use_count,
arc_dec_use_count
};
/* $Id$
* IEEE-1284 implementation for parport.
/* IEEE-1284 implementation for parport.
*
* Authors: Philip Blundell <pjb27@cam.ac.uk>
* Authors: Phil Blundell <Philip.Blundell@pobox.com>
* Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
* Jose Renau <renau@acm.org>
*/
......
/* $Id: parport_init.c,v 1.1.2.2 1997/04/18 15:00:52 phil Exp $
* Parallel-port initialisation code.
/* Parallel-port initialisation code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
* Tim Waugh <tmw20@cam.ac.uk>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Jose Renau <renau@acm.org>
*
* based on work by Grant Guenther <grant@torque.net>
......@@ -62,17 +61,6 @@ int init_module(void)
void cleanup_module(void)
{
struct parport *port, *next;
for (port = parport_enumerate(); port; port = next) {
next = port->next;
if (!(port->flags & PARPORT_FLAG_COMA))
parport_quiesce(port);
parport_proc_unregister(port);
kfree(port->name);
kfree(port);
}
parport_proc_cleanup();
}
#else
......
/* $Id: parport_pc.c,v 1.1.2.3 1997/04/18 15:00:52 phil Exp $
* Parallel-port routines for PC architecture
/* Parallel-port routines for PC architecture
*
* Authors: Phil Blundell <pjb27@cam.ac.uk>
* Tim Waugh <tmw20@cam.ac.uk>
* Authors: Phil Blundell <Philip.Blundell@pobox.com>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Jose Renau <renau@acm.org>
* David Campbell <campbell@tirian.che.curtin.edu.au>
*
* based on work by Grant Guenther <grant@torque.net>
* and Philip Blundell <Philip.Blundell@pobox.com>
* based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
*/
#include <linux/stddef.h>
......@@ -153,7 +151,7 @@ static int pc_claim_resources(struct parport *p)
{
/* FIXME check that resources are free */
if (p->irq != PARPORT_IRQ_NONE)
request_irq(p->irq, pc_null_intr_func, 0, p->name, NULL);
request_irq(p->irq, pc_null_intr_func, 0, p->name, p);
request_region(p->base, p->size, p->name);
if (p->modes & PARPORT_MODE_PCECR)
request_region(p->base+0x400, 3, p->name);
......@@ -162,12 +160,14 @@ static int pc_claim_resources(struct parport *p)
static void pc_save_state(struct parport *p, struct parport_state *s)
{
/* FIXME */
s->u.pc.ctr = pc_read_control(p);
s->u.pc.ecr = pc_read_econtrol(p);
}
static void pc_restore_state(struct parport *p, struct parport_state *s)
{
/* FIXME */
pc_write_control(p, s->u.pc.ctr);
pc_write_econtrol(p, s->u.pc.ecr);
}
static unsigned int pc_epp_read_block(struct parport *p, void *buf, unsigned int length)
......@@ -195,6 +195,20 @@ static int pc_examine_irq(struct parport *p)
return 0; /* FIXME */
}
static void pc_inc_use_count(void)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
static void pc_dec_use_count(void)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
static struct parport_operations pc_ops =
{
pc_write_data,
......@@ -230,7 +244,10 @@ static struct parport_operations pc_ops =
pc_enable_irq,
pc_disable_irq,
pc_examine_irq
pc_examine_irq,
pc_inc_use_count,
pc_dec_use_count
};
/******************************************************
......@@ -322,7 +339,6 @@ static int programmable_dma_support(struct parport *pb)
return dma;
}
#if 0
/* Only called if port supports ECP mode.
*
* The only restriction on DMA channels is that it has to be
......@@ -388,7 +404,6 @@ static int parport_dma_probe(struct parport *pb)
return retv;
}
#endif
/******************************************************
* MODE detection section:
......@@ -449,18 +464,20 @@ static int parport_ECR_present(struct parport *pb)
oecr = pc_read_econtrol(pb);
r = pc_read_control(pb);
if ((pc_read_econtrol(pb) & 0x03) == (r & 0x03)) {
pc_write_control(pb, r ^ 0x03 ); /* Toggle bits 0-1 */
if ((pc_read_econtrol(pb) & 0x3) == (r & 0x3)) {
pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
r= pc_read_control(pb);
if ((pc_read_econtrol(pb) & 0x03) == (r & 0x03))
r = pc_read_control(pb);
if ((pc_read_econtrol(pb) & 0x2) == (r & 0x2)) {
pc_write_control(pb, octr);
return 0; /* Sure that no ECR register exists */
}
}
if ((pc_read_econtrol(pb) & 0x03 ) != 0x01)
if ((pc_read_econtrol(pb) & 0x3 ) != 0x1)
return 0;
pc_write_econtrol(pb,0x34);
pc_write_econtrol(pb, 0x34);
if (pc_read_econtrol(pb) != 0x35)
return 0;
......@@ -846,6 +863,11 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
#undef printmode
printk("]\n");
parport_proc_register(p);
p->flags |= PARPORT_FLAG_COMA;
/* Done probing. Now put the port into a sensible start-up state. */
pc_write_control(p, 0xc);
pc_write_data(p, 0);
return 1;
}
......@@ -860,11 +882,8 @@ int parport_pc_init(int *io, int *irq, int *dma)
} else {
/* Probe all the likely ports. */
count += probe_one_port(0x378, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
#if defined(__i386__)
count += probe_one_port(0x278, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
count += probe_one_port(0x3bc, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO);
#endif
}
return count;
}
......@@ -877,22 +896,23 @@ MODULE_PARM(io, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
MODULE_PARM(dma, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
static int init_module(void)
int init_module(void)
{
return (parport_pc_init(io, irq, dma)?0:1);
}
static void cleanup_module(void)
void cleanup_module(void)
{
struct parport *p = parport_enumerate();
struct parport *p = parport_enumerate(), *tmp;
while (p) {
tmp = p->next;
if (p->modes & PARPORT_MODE_PCSPP) {
if (!(p->flags & PARPORT_FLAG_COMA))
parport_quiesce(p);
parport_proc_unregister(p);
parport_unregister_port(p);
}
p = p->next;
p = tmp;
}
}
#endif
/* $Id: parport_procfs.c,v 1.1.2.2 1997/04/18 15:00:52 phil Exp $
* Parallel port /proc interface code.
/* Parallel port /proc interface code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
* Tim Waugh <tmw20@cam.ac.uk>
......
/* $Id: parport_share.c,v 1.1.2.2 1997/04/18 15:00:52 phil Exp $
* Parallel-port resource manager code.
/* Parallel-port resource manager code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
* Tim Waugh <tmw20@cam.ac.uk>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Jose Renau <renau@acm.org>
*
* based on work by Grant Guenther <grant@torque.net>
......@@ -19,6 +18,10 @@
#include <linux/kernel.h>
#include <linux/malloc.h>
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#endif
#undef PARPORT_PARANOID
static struct parport *portlist = NULL, *portlist_tail = NULL;
......@@ -27,6 +30,10 @@ static int portcount = 0;
/* Return a list of all the ports we know about. */
struct parport *parport_enumerate(void)
{
#ifdef CONFIG_KERNELD
if (portlist == NULL)
request_module("parport_lowlevel");
#endif
return portlist;
}
......@@ -93,7 +100,8 @@ void parport_unregister_port(struct parport *port)
struct parport *p;
kfree(port->name);
if (portlist == port) {
portlist = port->next;
if ((portlist = port->next) == NULL)
portlist_tail = NULL;
} else {
for (p = portlist; (p != NULL) && (p->next != port);
p=p->next);
......@@ -184,6 +192,7 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
port->lurker = tmp;
inc_parport_count();
port->ops->inc_use_count();
return tmp;
}
......@@ -218,6 +227,7 @@ void parport_unregister_device(struct pardevice *dev)
kfree(dev);
dec_parport_count();
port->ops->dec_use_count();
/* If there are no more devices, put the port to sleep. */
if (!port->devices)
......
......@@ -123,8 +123,8 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
fi
if [ ! "$CONFIG_PNP_PARPORT" = "n" ]; then
dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PNP_PARPORT
if [ ! "$CONFIG_PARPORT" = "n" ]; then
dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
fi
tristate 'PPP (point-to-point) support' CONFIG_PPP
......
This diff is collapsed.
This diff is collapsed.
#ifndef TLAN_H
#define TLAN_H
/********************************************************************
*
* Linux ThunderLAN Driver
......@@ -18,6 +21,11 @@
#include <asm/types.h>
#include <linux/netdevice.h>
#if LINUX_VERSION_CODE <= 0x20100
#define net_device_stats enet_statistics
#endif
/*****************************************************************
......@@ -37,7 +45,11 @@
#define TLAN_IGNORE 0
#define TLAN_RECORD 1
#define TLAN_DBG(lvl, format, args...) if ( debug >= lvl ) printk( format, ##args );
#define TLAN_DBG(lvl, format, args...) if ( debug & lvl ) printk( format, ##args );
#define TLAN_DEBUG_GNRL 0x0001
#define TLAN_DEBUG_TX 0x0002
#define TLAN_DEBUG_RX 0x0004
#define TLAN_DEBUG_LIST 0x0008
......@@ -50,7 +62,12 @@
/* NOTE: These should be moved to pci.h someday */
#define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34
#define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32
#define PCI_DEVICE_ID_NETFLEX_3_INTEGRATED 0xAE35
#define PCI_DEVICE_ID_NETFLEX_3P_INTEGRATED 0xAE35
#define PCI_DEVICE_ID_NETFLEX_3P 0xF130
#define PCI_DEVICE_ID_NETFLEX_3P_BNC 0xF150
#define PCI_DEVICE_ID_NETELLIGENT_10_100_PROLIANT 0xAE43
#define PCI_DEVICE_ID_NETELLIGENT_10_100_DUAL 0xAE40
#define PCI_DEVICE_ID_DESKPRO_4000_5233MMX 0xB011
typedef struct tlan_pci_id {
......@@ -152,11 +169,12 @@
u32 timerSetAt;
u32 timerType;
struct timer_list timer;
struct enet_statistics stats;
struct net_device_stats stats;
u32 pciEntry;
u8 pciRevision;
u8 pciBus;
u8 pciDeviceFn;
u8 tlanRev;
char devName[8];
} TLanPrivateInfo;
......@@ -479,3 +497,7 @@ inline u32 TLan_HashFunc( u8 *a )
}
#endif
......@@ -52,7 +52,7 @@ static long read_polled(struct parport *port, char *buf,
{
int i;
char *temp=buf;
int count = 0;
unsigned int count = 0;
unsigned char z=0;
unsigned char Byte=0;
......
Thu Aug 23 23:43 1997 Gerard Roudier (groudier@club-internet.fr)
* revision 2.5a
- Update Configure.help for inclusion in linux-2.1.51/2/3
- Use BASE_2 address from PCI config space instead of some
IO register for getting the on-board SRAM bus address.
- Remove error testing of pcibios_read/write functions.
These functions are intended to be used for successfully
detected PCI devices. Expecting error condition from them
is nothing but paranoia.
Thu Aug 21 23:00 1997 Gerard Roudier (groudier@club-internet.fr)
* revision 2.5
- 53C860 chip support fix.
- Move the 'host_status' to the last DWORD of the CCB header.
This header is copied back by the script processor. This
guarantees that the header is entirely copied back over
the PCI when the CPU completes a CCB.
- (re)read ISTAT prior to scanning CCBs for completion. This
ensure that any posted buffer are flushed prior CCBs scan.
- Support for BIG ENDIAN cpu. Added by Cort <cort@cs.nmt.edu>.
Initial patch did'nt support disconnections and tagged commands.
I've completed the patch and it seems that all is ok now.
Only some powerpc under 2.1.X is supported for the moment.
- Misc. trivial fixes and cleanups.
Sat July 26 18:00 1997 Gerard Roudier (groudier@club-internet.fr)
* revision 2.4
Several clean-ups:
......
......@@ -84,8 +84,8 @@ fi
if [ "$CONFIG_MCA" = "y" ]; then
dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI
fi
if [ "$CONFIG_PNP_PARPORT" != "n" ]; then
dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PNP_PARPORT
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
if [ "$CONFIG_SCSI_PPA" != "n" ]; then
int ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3
int ' EPP timeout' CONFIG_SCSI_PPA_EPP_TIME 128
......
......@@ -4,7 +4,7 @@ Written by Gerard Roudier <groudier@club-internet.fr>
21 Rue Carnot
95170 DEUIL LA BARRE - FRANCE
19 June 1997
23 August 1997
===============================================================================
1. Introduction
......@@ -46,6 +46,9 @@ Written by Gerard Roudier <groudier@club-internet.fr>
17.1 Features
17.2 Symbios NVRAM layout
17.3 Tekram NVRAM layout
18. Support for Big Endian
18.1 Big Endian CPU
18.2 NCR chip in Big Endian mode of operations
===============================================================================
......@@ -83,7 +86,7 @@ This short documentation only describes the features of the NCR53C8XX
driver, configuration parameters and control commands available
through the proc SCSI file system read / write operations.
This driver has been tested OK with linux/i386 and Linux/Alpha.
This driver has been tested OK with linux/i386, Linux/Alpha and Linux/PPC.
Latest driver version and patches are available at:
......@@ -429,7 +432,10 @@ this feature after boot-up only for devices that support it safely.
CONFIG_SCSI_NCR53C8XX_IOMAPPED (default answer: n)
Answer "y" if you suspect your mother board to not allow memory mapped I/O.
May slow down performance a little.
May slow down performance a little. This option is required by
Linux/PPC and is used no matter what you select here. Linux/PPC
suffers no performance loss with this option since all IO is memory
mapped anyway.
CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE (default answer: n)
Answer "y" if you are sure that all your SCSI devices that are able to
......@@ -1430,8 +1436,29 @@ default nvram data:
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0xfbbc
===============================================================================
End of NCR53C8XX driver README file
18. Support for Big Endian
The PCI local bus has been primarily designed for x86 architecture.
As a consequence, PCI devices generally expect DWORDS using little endian
byte ordering.
18.1 Big Endian CPU
In order to support NCR chips on a Big Endian architecture the driver has to
perform byte reordering each time it is needed. This feature has been
added to the driver by Cort <cort@cs.nmt.edu> and is available in driver
version 2.5 and later ones. For the moment Big Endian support has only
been tested on Linux/PPC (PowerPC).
18.2 NCR chip in Big Endian mode of operations
It can be read in SYMBIOS documentation that some chips support a special
Big Endian mode, on paper: 53C815, 53C825A, 53C875, 53C875N, 53C895.
This mode of operations is not software-selectable, but needs pin named
BigLit to be pulled-up. Using this mode, most of byte reorderings should
be avoided when the driver is running on a Big Endian CPU.
Driver version 2.5 is also, in theory, ready for this feature.
===============================================================================
End of NCR53C8XX driver README file
This diff is collapsed.
......@@ -45,7 +45,7 @@
/*
** Name and revision of the driver
*/
#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.4"
#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.5a"
/*
** Check supported Linux versions
......@@ -155,9 +155,11 @@
#endif
/*
* Use normal IO if configured. Forced for alpha.
* Use normal IO if configured. Forced for alpha and ppc.
*/
#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) || defined(__alpha__)
#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED)
#define SCSI_NCR_IOMAPPED
#elif defined(__alpha__) || defined(__powerpc__)
#define SCSI_NCR_IOMAPPED
#endif
......@@ -315,6 +317,45 @@ int ncr53c8xx_release(struct Scsi_Host *);
#ifndef HOSTS_C
/*
** IO functions definition for big/little endian support.
** For now, the NCR is only supported in little endian addressing mode,
** and big endian byte ordering is only supported for the PPC.
** MMIO is not used on PPC.
*/
#ifdef __BIG_ENDIAN
#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
#error "BIG ENDIAN byte ordering needs kernel version >= 2.1.0"
#endif
#ifdef __powerpc__
#define inw_l2b inw
#define inl_l2b inl
#define outw_b2l outw
#define outl_b2l outl
#else
#error "Support for BIG ENDIAN is only available for the PowerPC"
#endif
#else /* Assumed x86 or alpha */
#define inw_raw inw
#define inl_raw inl
#define outw_raw outw
#define outl_raw outl
#define readw_raw readw
#define readl_raw readl
#define writew_raw writew
#define writel_raw writel
#endif
#ifdef SCSI_NCR_BIG_ENDIAN
#error "The NCR in BIG ENDIAN adressing mode is not (yet) supported"
#endif
/*
** NCR53C8XX Device Ids
*/
......@@ -416,7 +457,7 @@ typedef struct {
FE_WIDE|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM} \
, \
{PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, \
FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN|FE_RAM} \
FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} \
, \
{PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 7, 16, 5, \
FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
......
......@@ -9,6 +9,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/page.h>
#include <linux/errno.h>
#include <linux/kernel.h>
......@@ -23,7 +24,7 @@
#define MAX_RETRIES 5
#define MAX_TIMEOUT (9 * HZ)
#define MAX_BUF 4096
#define MAX_BUF PAGE_SIZE
#define max(a,b) (((a) > (b)) ? (a) : (b))
......@@ -73,12 +74,9 @@ static int ioctl_probe(struct Scsi_Host * host, void *buffer)
*
* *(char *) ((int *) arg)[2] the actual command byte.
*
* Note that no more than MAX_BUF data bytes will be transfered. Since
* SCSI block device size is 512 bytes, I figured 1K was good.
* but (WDE) changed it to 8192 to handle large bad track buffers.
* ERY: I changed this to a dynamic allocation using scsi_malloc - we were
* getting a kernel stack overflow which was crashing the system when we
* were using 8192 bytes.
* Note that if more than MAX_BUF bytes are requested to be transfered,
* the ioctl will fail with error EINVAL. MAX_BUF can be increased in
* the future by increasing the size that scsi_malloc will accept.
*
* This size *does not* include the initial lengths that were passed.
*
......@@ -201,8 +199,8 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
* If the user needs to transfer more data than this, they
* should use scsi_generics instead.
*/
if( inlen > MAX_BUF ) inlen = MAX_BUF;
if( outlen > MAX_BUF ) outlen = MAX_BUF;
if( inlen > MAX_BUF ) return -EINVAL;
if( outlen > MAX_BUF ) return -EINVAL;
cmd_in = sic->data;
get_user(opcode, cmd_in);
......
......@@ -17,83 +17,87 @@
/* POSIX UID/GID verification for setting inode attributes. */
int inode_change_ok(struct inode *inode, struct iattr *attr)
{
int retval = -EPERM;
unsigned int ia_valid = attr->ia_valid;
/* If force is set do it anyway. */
if (attr->ia_valid & ATTR_FORCE)
return 0;
if (ia_valid & ATTR_FORCE)
goto fine;
/* Make sure a caller can chown. */
if ((attr->ia_valid & ATTR_UID) &&
if ((ia_valid & ATTR_UID) &&
(current->fsuid != inode->i_uid ||
attr->ia_uid != inode->i_uid) && !fsuser())
return -EPERM;
goto error;
/* Make sure caller can chgrp. */
if ((attr->ia_valid & ATTR_GID) &&
if ((ia_valid & ATTR_GID) &&
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) &&
!fsuser())
return -EPERM;
goto error;
/* Make sure a caller can chmod. */
if (attr->ia_valid & ATTR_MODE) {
if (ia_valid & ATTR_MODE) {
if ((current->fsuid != inode->i_uid) && !fsuser())
return -EPERM;
goto error;
/* Also check the setgid bit! */
if (!fsuser() && !in_group_p((attr->ia_valid & ATTR_GID) ? attr->ia_gid :
if (!fsuser() && !in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
inode->i_gid))
attr->ia_mode &= ~S_ISGID;
}
/* Check for setting the inode time. */
if ((attr->ia_valid & ATTR_ATIME_SET) &&
((current->fsuid != inode->i_uid) && !fsuser()))
return -EPERM;
if ((attr->ia_valid & ATTR_MTIME_SET) &&
((current->fsuid != inode->i_uid) && !fsuser()))
return -EPERM;
return 0;
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
if (current->fsuid != inode->i_uid && !fsuser())
goto error;
}
fine:
retval = 0;
error:
return retval;
}
void inode_setattr(struct inode * inode, struct iattr * attr)
{
if(attr->ia_valid &
(ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME|ATTR_MODE)) {
if (attr->ia_valid & ATTR_UID)
unsigned int ia_valid = attr->ia_valid;
if (ia_valid & ATTR_UID)
inode->i_uid = attr->ia_uid;
if (attr->ia_valid & ATTR_GID)
if (ia_valid & ATTR_GID)
inode->i_gid = attr->ia_gid;
if (attr->ia_valid & ATTR_SIZE)
if (ia_valid & ATTR_SIZE)
inode->i_size = attr->ia_size;
if (attr->ia_valid & ATTR_ATIME)
if (ia_valid & ATTR_ATIME)
inode->i_atime = attr->ia_atime;
if (attr->ia_valid & ATTR_MTIME)
if (ia_valid & ATTR_MTIME)
inode->i_mtime = attr->ia_mtime;
if (attr->ia_valid & ATTR_CTIME)
if (ia_valid & ATTR_CTIME)
inode->i_ctime = attr->ia_ctime;
if (attr->ia_valid & ATTR_MODE) {
if (ia_valid & ATTR_MODE) {
inode->i_mode = attr->ia_mode;
if (!fsuser() && !in_group_p(inode->i_gid))
inode->i_mode &= ~S_ISGID;
}
mark_inode_dirty(inode);
}
}
int notify_change(struct inode * inode, struct iattr * attr)
{
int error;
time_t now = CURRENT_TIME;
unsigned int ia_valid = attr->ia_valid;
attr->ia_ctime = now;
if ((attr->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET)) == ATTR_ATIME)
if (!(ia_valid & ATTR_ATIME_SET))
attr->ia_atime = now;
if ((attr->ia_valid & (ATTR_MTIME | ATTR_MTIME_SET)) == ATTR_MTIME)
if (!(ia_valid & ATTR_MTIME_SET))
attr->ia_mtime = now;
attr->ia_valid &= ~(ATTR_CTIME);
if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->notify_change)
return inode->i_sb->s_op->notify_change(inode, attr);
error = inode_change_ok(inode, attr);
if(!error)
if (!error)
inode_setattr(inode, attr);
return error;
}
......@@ -12,6 +12,7 @@
* 1997-05-19 cleanup
* 1997-06-26 hpa: pass the real filename rather than argv[0]
* 1997-06-30 minor cleanup
* 1997-08-09 removed extension stripping, locking cleanup
*/
#include <linux/module.h>
......@@ -31,10 +32,6 @@
#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
#ifndef MIN
#define MIN(x,y) (((x)<(y))?(x):(y))
#endif
struct binfmt_entry {
struct binfmt_entry *next;
int id;
......@@ -50,7 +47,6 @@ struct binfmt_entry {
#define ENTRY_ENABLED 1 /* the old binfmt_entry.enabled */
#define ENTRY_MAGIC 8 /* not filename detection */
#define ENTRY_STRIP_EXT 32 /* strip off last filename extension */
static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
static void entry_proc_cleanup(struct binfmt_entry *e);
......@@ -70,7 +66,9 @@ static struct binfmt_entry *entries = NULL;
static int free_id = 1;
static int enabled = 1;
#ifdef __SMP__
static rwlock_t entries_lock = RW_LOCK_UNLOCKED;
#endif
/*
......@@ -84,12 +82,14 @@ static void clear_entry(int id)
ep = &entries;
while (*ep && ((*ep)->id != id))
ep = &((*ep)->next);
if ((e = *ep)) {
if ((e = *ep))
*ep = e->next;
write_unlock(&entries_lock);
if (e) {
entry_proc_cleanup(e);
kfree(e);
}
write_unlock(&entries_lock);
}
/*
......@@ -97,29 +97,45 @@ static void clear_entry(int id)
*/
static void clear_entries(void)
{
struct binfmt_entry *e;
struct binfmt_entry *e, *n;
write_lock(&entries_lock);
while ((e = entries)) {
entries = entries->next;
n = entries;
entries = NULL;
write_unlock(&entries_lock);
while ((e = n)) {
n = e->next;
entry_proc_cleanup(e);
kfree(e);
}
write_unlock(&entries_lock);
}
/*
* Find entry through id - caller has to do locking
* Find entry through id and lock it
*/
static struct binfmt_entry *get_entry(int id)
{
struct binfmt_entry *e = entries;
struct binfmt_entry *e;
read_lock(&entries_lock);
e = entries;
while (e && (e->id != id))
e = e->next;
if (!e)
read_unlock(&entries_lock);
return e;
}
/*
* unlock entry
*/
static inline void put_entry(struct binfmt_entry *e)
{
if (e)
read_unlock(&entries_lock);
}
/*
* Check if we support the binfmt
......@@ -128,10 +144,11 @@ static struct binfmt_entry *get_entry(int id)
*/
static struct binfmt_entry *check_file(struct linux_binprm *bprm)
{
struct binfmt_entry *e = entries;
struct binfmt_entry *e;
char *p = strrchr(bprm->filename, '.');
int j;
e = entries;
while (e) {
if (e->flags & ENTRY_ENABLED) {
if (!(e->flags & ENTRY_MAGIC)) {
......@@ -160,7 +177,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
struct binfmt_entry *fmt;
struct dentry * dentry;
char iname[128];
char *iname_addr = iname, *p;
char *iname_addr = iname;
int retval, fmt_flags = 0;
MOD_INC_USE_COUNT;
......@@ -186,9 +203,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
bprm->dentry = NULL;
/* Build args for interpreter */
if ((fmt_flags & ENTRY_STRIP_EXT) &&
(p = strrchr(bprm->filename, '.')))
*p = '\0';
remove_arg_zero(bprm);
bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
bprm->argc++;
......@@ -288,13 +302,12 @@ static int proc_write_register(struct file *file, const char *buffer,
e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
/* we can use bit 3 and 5 of type for ext/magic and ext-strip
flag due to the nice encoding of E, M, e and m */
if ((*sp & 0x92) || (sp[1] != del))
/* we can use bit 3 of type for ext/magic
flag due to the nice encoding of E and M */
if ((*sp & ~('E' | 'M')) || (sp[1] != del))
err = -EINVAL;
else
e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_STRIP_EXT))
| ENTRY_ENABLED;
e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
cnt -= 2; sp++;
e->offset = 0;
......@@ -342,17 +355,17 @@ static int proc_read_status(char *page, char **start, off_t off,
{
struct binfmt_entry *e;
char *dp;
int elen, i;
int elen, i, err;
MOD_INC_USE_COUNT;
#ifndef VERBOSE_STATUS
if (data) {
read_lock(&entries_lock);
if (!(e = get_entry((int) data)))
i = 0;
else
if (!(e = get_entry((int) data))) {
err = -ENOENT;
goto _err;
}
i = e->flags & ENTRY_ENABLED;
read_unlock(&entries_lock);
put_entry(e);
} else {
i = enabled;
}
......@@ -361,10 +374,9 @@ static int proc_read_status(char *page, char **start, off_t off,
if (!data)
sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
else {
read_lock(&entries_lock);
if (!(e = get_entry((int) data))) {
*page = '\0';
goto _out;
err = -ENOENT;
goto _err;
}
sprintf(page, "%s\ninterpreter %s\n",
(e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
......@@ -391,10 +403,7 @@ static int proc_read_status(char *page, char **start, off_t off,
*dp++ = '\n';
*dp = '\0';
}
if (e->flags & ENTRY_STRIP_EXT)
sprintf(dp, "extension stripped\n");
_out:
read_unlock(&entries_lock);
put_entry(e);
}
#endif
......@@ -403,9 +412,11 @@ static int proc_read_status(char *page, char **start, off_t off,
elen = 0;
*eof = (elen <= count) ? 1 : 0;
*start = page + off;
err = elen;
_err:
MOD_DEC_USE_COUNT;
return elen;
return err;
}
/*
......@@ -419,18 +430,18 @@ static int proc_write_status(struct file *file, const char *buffer,
int res = count;
MOD_INC_USE_COUNT;
if (((buffer[0] == '1') || (buffer[0] == '0')) &&
((count == 1) || ((count == 2) && (buffer[1] == '\n')))) {
if (buffer[count-1] == '\n')
count--;
if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
if (data) {
read_lock(&entries_lock);
if ((e = get_entry((int) data)))
e->flags = (e->flags & -2) | (int) (buffer[0] - '0');
read_unlock(&entries_lock);
e->flags = (e->flags & ~ENTRY_ENABLED)
| (int)(buffer[0] - '0');
put_entry(e);
} else {
enabled = buffer[0] - '0';
}
} else if ((buffer[0] == '-') && (buffer[1] == '1') &&
((count == 2) || ((count == 3) && (buffer[2] == '\n')))) {
} else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
if (data)
clear_entry((int) data);
else
......
......@@ -823,12 +823,8 @@ printk("refill_freelist: waking bdflush\n");
struct buffer_head * getblk(kdev_t dev, int block, int size)
{
struct buffer_head * bh;
int isize = BUFSIZE_INDEX(size);
int isize;
/* If there are too many dirty buffers, we wake up the update process
* now so as to ensure that there are still clean buffers available
* for user processes to use (and dirty).
*/
repeat:
bh = get_hash_table(dev, block, size);
if (bh) {
......@@ -841,17 +837,15 @@ struct buffer_head * getblk(kdev_t dev, int block, int size)
return bh;
}
while(!free_list[isize])
refill_freelist(size);
if (find_buffer(dev,block,size))
goto repeat;
isize = BUFSIZE_INDEX(size);
get_free:
bh = free_list[isize];
if (!bh)
goto refill;
remove_from_free_list(bh);
/* OK, FINALLY we know that this buffer is the only one of its kind,
* and that it's unused (b_count=0), unlocked (buffer_locked=0), and clean.
* and that it's unused (b_count=0), unlocked, and clean.
*/
bh->b_count=1;
bh->b_list = BUF_CLEAN;
......@@ -862,6 +856,16 @@ struct buffer_head * getblk(kdev_t dev, int block, int size)
bh->b_blocknr=block;
insert_into_queues(bh);
return bh;
/*
* If we block while refilling the free list, somebody may
* create the buffer first ... search the hashes again.
*/
refill:
refill_freelist(size);
if (!find_buffer(dev,block,size))
goto get_free;
goto repeat;
}
void set_writetime(struct buffer_head * buf, int flag)
......
......@@ -19,6 +19,9 @@
#include <linux/malloc.h>
#include <linux/init.h>
/* For managing the dcache */
extern int nr_free_pages, free_pages_low;
/*
* This is the single most critical data structure when it comes
* to the dcache: the hashtable for lookups. Somebody should try
......@@ -72,13 +75,13 @@ void dput(struct dentry *dentry)
dentry->d_count = count;
if (!count) {
list_del(&dentry->d_lru);
if (dentry->d_op && dentry->d_op->d_delete)
dentry->d_op->d_delete(dentry);
if (list_empty(&dentry->d_hash)) {
struct inode *inode = dentry->d_inode;
struct dentry * parent;
if (inode) {
list_del(&dentry->d_alias);
if (inode)
iput(inode);
}
parent = dentry->d_parent;
d_free(dentry);
if (dentry == parent)
......@@ -134,7 +137,6 @@ void shrink_dcache(void)
if (dentry->d_inode) {
struct inode * inode = dentry->d_inode;
list_del(&dentry->d_alias);
dentry->d_inode = NULL;
iput(inode);
}
......@@ -152,6 +154,13 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
char * str;
struct dentry *dentry;
/*
* Check whether to shrink the dcache ... this greatly reduces
* the likelyhood that kmalloc() will need additional memory.
*/
if (nr_free_pages < free_pages_low)
shrink_dcache();
dentry = kmalloc(sizeof(struct dentry), GFP_KERNEL);
if (!dentry)
return NULL;
......@@ -172,7 +181,6 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
dentry->d_mounts = dentry;
dentry->d_covers = dentry;
INIT_LIST_HEAD(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_alias);
INIT_LIST_HEAD(&dentry->d_lru);
dentry->d_name.name = str;
......@@ -194,9 +202,6 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
*/
void d_instantiate(struct dentry *entry, struct inode * inode)
{
if (inode)
list_add(&entry->d_alias, &inode->i_dentry);
entry->d_inode = inode;
}
......@@ -312,10 +317,10 @@ void d_delete(struct dentry * dentry)
*/
if (dentry->d_count == 1) {
struct inode * inode = dentry->d_inode;
if (inode) {
dentry->d_inode = NULL;
list_del(&dentry->d_alias);
iput(inode);
}
return;
}
......
......@@ -134,21 +134,23 @@ int unregister_binfmt(struct linux_binfmt * fmt)
}
#endif /* CONFIG_MODULES */
/* N.B. Error returns must be < 0 */
int open_dentry(struct dentry * dentry, int mode)
{
int fd;
struct inode * inode = dentry->d_inode;
struct file * f;
int error;
error = -EINVAL;
if (!inode->i_op || !inode->i_op->default_file_ops)
return -EINVAL;
goto out;
fd = get_unused_fd();
if (fd >= 0) {
struct file * f = get_empty_filp();
if (!f) {
put_unused_fd(fd);
return -ENFILE;
}
error = -ENFILE;
f = get_empty_filp();
if (!f)
goto out_fd;
f->f_flags = mode;
f->f_mode = (mode+1) & O_ACCMODE;
f->f_dentry = dentry;
......@@ -156,17 +158,23 @@ int open_dentry(struct dentry * dentry, int mode)
f->f_reada = 0;
f->f_op = inode->i_op->default_file_ops;
if (f->f_op->open) {
int error = f->f_op->open(inode,f);
if (error) {
put_filp(f);
put_unused_fd(fd);
return error;
}
error = f->f_op->open(inode,f);
if (error)
goto out_filp;
}
current->files->fd[fd] = f;
dget(dentry);
}
return fd;
out_filp:
if (error > 0)
error = -EIO;
put_filp(f);
out_fd:
put_unused_fd(fd);
out:
return error;
}
/*
......@@ -379,37 +387,53 @@ int read_exec(struct dentry *dentry, unsigned long offset,
return result;
}
static void exec_mmap(void)
static int exec_mmap(void)
{
struct mm_struct * mm, * old_mm;
int retval;
if (current->mm->count == 1) {
flush_cache_mm(current->mm);
exit_mmap(current->mm);
clear_page_tables(current);
flush_tlb_mm(current->mm);
return 0;
}
/*
* The clear_page_tables done later on exec does the right thing
* to the page directory when shared, except for graceful abort
* (the oom is wrong there, too, IMHO)
*/
if (current->mm->count > 1) {
struct mm_struct *mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
if (!mm) {
/* this is wrong, I think. */
oom(current);
return;
}
*mm = *current->mm;
init_new_context(mm);
mm->def_flags = 0; /* should future lockings be kept? */
retval = -ENOMEM;
mm = mm_alloc();
if (!mm)
goto fail_nomem;
mm->cpu_vm_mask = (1UL << smp_processor_id());
mm->count = 1;
mm->mmap = mm->mmap_cache = NULL;
mm->total_vm = 0;
mm->rss = 0;
current->mm->count--;
old_mm = current->mm;
current->mm = mm;
new_page_tables(current);
return;
}
flush_cache_mm(current->mm);
exit_mmap(current->mm);
clear_page_tables(current);
flush_tlb_mm(current->mm);
retval = new_page_tables(current);
if (retval)
goto fail_restore;
mmput(old_mm);
return 0;
/*
* Failure ... restore the prior mm_struct.
*/
fail_restore:
current->mm = old_mm;
mmput(mm);
/*
* N.B. binfmt_xxx needs to handle the error instead of oom()
*/
fail_nomem:
/* this is wrong, I think. */
oom(current);
return retval;
}
/*
......@@ -454,9 +478,16 @@ static inline void flush_old_files(struct files_struct * files)
void flush_old_exec(struct linux_binprm * bprm)
{
int i;
int ch;
char * name;
int i, ch, retval;
/*
* Release all of the old mmap stuff ... do this first
* so we can bail out on failure.
*/
retval = exec_mmap();
if (retval)
goto out;
if (current->euid == current->uid && current->egid == current->gid)
current->dumpable = 1;
......@@ -470,9 +501,6 @@ void flush_old_exec(struct linux_binprm * bprm)
}
current->comm[i] = '\0';
/* Release all of the old mmap stuff. */
exec_mmap();
flush_thread();
if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
......@@ -481,6 +509,8 @@ void flush_old_exec(struct linux_binprm * bprm)
flush_old_signals(current->sig);
flush_old_files(current->files);
out:
return; /* retval; FIXME. */
}
/*
......
......@@ -43,26 +43,6 @@ static inline void put_inuse(struct file *file)
file->f_pprev = &inuse_filps;
}
/* Get more free filp's. */
static int grow_files(void)
{
int i = 16;
while(i--) {
struct file * file = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
if(!file) {
if(i == 15)
return 0;
goto got_some;
}
insert_file_free(file);
nr_files++;
}
got_some:
return 1;
}
void file_table_init(void)
{
filp_cache = kmem_cache_create("filp", sizeof(struct file),
......@@ -78,28 +58,36 @@ void file_table_init(void)
*/
struct file * get_empty_filp(void)
{
static int old_max = 0;
struct file * f;
again:
if((f = free_filps) != NULL) {
f = free_filps;
if (!f)
goto get_more;
remove_filp(f);
got_one:
memset(f, 0, sizeof(*f));
f->f_count = 1;
f->f_version = ++event;
put_inuse(f);
} else {
int max = max_files;
return f;
get_more:
/* Reserve a few files for the super-user.. */
if (current->euid)
max -= 10;
if (nr_files < max && grow_files())
goto again;
if (nr_files < (current->euid ? max_files - 10 : max_files)) {
f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
if (f) {
nr_files++;
goto got_one;
}
/* Big problems... */
printk("VFS: filp allocation failed\n");
} else if (max_files > old_max) {
printk("VFS: file-max limit %d reached\n", max_files);
old_max = max_files;
}
return f;
return NULL;
}
/*
......
......@@ -109,7 +109,6 @@ static inline void init_once(struct inode * inode)
{
memset(inode, 0, sizeof(*inode));
init_waitqueue(&inode->i_wait);
INIT_LIST_HEAD(&inode->i_dentry);
INIT_LIST_HEAD(&inode->i_hash);
sema_init(&inode->i_sem, 1);
}
......
......@@ -232,8 +232,11 @@ struct super_block *msdos_read_super(struct super_block *sb,void *data, int sile
sb->s_op = &msdos_sops;
res = fat_read_super(sb, data, silent);
if (res == NULL)
if (res == NULL) {
sb->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
sb->s_root->d_op = &msdos_dentry_operations;
return res;
}
......
This diff is collapsed.
......@@ -7,6 +7,13 @@
*
* 10 Apr 1996 Added silly rename for unlink --okir
* 28 Sep 1996 Improved directory cache --okir
* 23 Aug 1997 Claus Heine claus@momo.math.rwth-aachen.de
* Re-implemented silly rename for unlink, newly implemented
* silly rename for nfs_rename() following the suggestions
* of Olaf Kirch (okir) found in this file.
* Following Linus comments on my original hack, this version
* depends only on the dcache stuff and doesn't touch the inode
* layer (iput() and friends).
*/
#include <linux/sched.h>
......@@ -349,10 +356,13 @@ static int nfs_lookup_revalidate(struct dentry * dentry)
return time < max;
}
static void nfs_silly_delete(struct dentry *);
static struct dentry_operations nfs_dentry_operations = {
nfs_lookup_revalidate,
0, /* d_hash */
0, /* d_compare */
nfs_silly_delete,
};
static int nfs_lookup(struct inode *dir, struct dentry * dentry)
......@@ -378,7 +388,6 @@ static int nfs_lookup(struct inode *dir, struct dentry * dentry)
inode = NULL;
if (!error) {
error = -ENOENT;
inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
if (!inode)
return -EACCES;
......@@ -530,9 +539,150 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
return 0;
}
/*
* We should do silly-rename here, but I'm too lazy to fix
* up the directory entry implications of it..
/* Note: we copy the code from lookup_dentry() here, only: we have to
* omit the directory lock. We are already the owner of the lock when
* we reach here. And "down(&dir->i_sem)" would make us sleep forever
* ('cause WE have the lock)
*
* VERY IMPORTANT: calculate the hash for this dentry!!!!!!!!
* Otherwise the cached lookup DEFINITELY WILL fail. And a new dentry
* is created. Without the DCACHE_NFSFS_RENAMED flag. And with d_count
* == 1. And trouble.
*
* Concerning my choice of the temp name: it is just nice to have
* i_ino part of the temp name, as this offers another check whether
* somebody attempts to remove the "silly renamed" dentry
* itself. Which is something that I consider evil. Your opinion may
* vary.
* BUT:
* Now that I compute the hash value right, it should be possible to simply
* check for the DCACHE_NFSFS_RENAMED flag in dentry->d_flag instead of
* doing the string compare.
* WHICH MEANS:
* This offers the opportunity to shorten the temp name. Currently, I use
* the hex representation of i_ino + the hex value of jiffies. This
* sums up to as much as 36 characters for a 64 bit machine, and needs
* 20 chars on a 32 bit machine. Have a look at jiffiesize etc.
* QUINTESSENCE
* The use of i_ino is simply cosmetic. All we need is a unique temp
* file name for the .nfs files. The hex representation of "jiffies"
* seemed to be adequate. And as we retry in case such a file already
* exists we are guaranteed to succed (after some jiffies have passed
* by :)
*/
static
struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
{
struct qstr sqstr;
struct dentry *sdentry;
int i, error;
sqstr.name = silly;
sqstr.len = slen;
sqstr.hash = init_name_hash();
for (i= 0; i < slen; i++)
sqstr.hash = partial_name_hash(silly[i], sqstr.hash);
sqstr.hash = end_name_hash(sqstr.hash);
sdentry = d_lookup(parent, &sqstr);
if (!sdentry) {
sdentry = d_alloc(parent, &sqstr);
if (sdentry == NULL)
return ERR_PTR(-ENOMEM);
error = nfs_lookup(parent->d_inode, sdentry);
if (error) {
dput(sdentry);
return ERR_PTR(error);
}
}
return sdentry;
}
static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
static unsigned int sillycounter = 0;
const int i_inosize = sizeof(dir->i_ino)*2;
const int countersize = sizeof(sillycounter)*2;
const int slen = strlen(".nfs") + i_inosize + countersize;
char silly[slen+1];
int error;
struct dentry *sdentry;
if (dentry->d_count == 1) {
return -EIO; /* No need to silly rename. */
}
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
return -EBUSY; /* don't allow to unlink silly inode -- nope,
* think a bit: silly DENTRY, NOT inode --
* itself
*/
}
sprintf(silly, ".nfs%*.*lx",
i_inosize, i_inosize, dentry->d_inode->i_ino);
sdentry = NULL;
do {
char *suffix = silly + slen - countersize;
dput(sdentry);
sillycounter++;
sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
dfprintk(VFS, "trying to rename %s to %s\n",
dentry->d_name.name, silly);
sdentry = nfs_silly_lookup(dentry->d_parent, silly, slen);
if (IS_ERR(sdentry)) {
return -EIO; /* FIXME ? */
}
} while(sdentry->d_inode != NULL); /* need negative lookup */
error = nfs_proc_rename(NFS_SERVER(dir),
NFS_FH(dir), dentry->d_name.name,
NFS_FH(dir), silly);
if (error) {
dput(sdentry);
return error;
}
nfs_invalidate_dircache(dir);
d_move(dentry, sdentry);
dput(sdentry);
dentry->d_flags |= DCACHE_NFSFS_RENAMED;
return 0; /* don't unlink */
}
static void nfs_silly_delete(struct dentry *dentry)
{
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
struct inode *dir = dentry->d_parent->d_inode;
int error;
dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
/* Unhash it first */
d_drop(dentry);
dfprintk(VFS, "trying to unlink %s\n", dentry->d_name.name);
error = nfs_proc_remove(NFS_SERVER(dir),
NFS_FH(dir), dentry->d_name.name);
if (error < 0)
printk("NFS " __FUNCTION__ " failed (err = %d)\n",
-error);
dentry->d_inode->i_nlink --;
nfs_invalidate_dircache(dir);
}
}
/* We do silly rename. In case sillyrename() returns -EBUSY, the inode
* belongs to an active ".nfs..." file and we return -EBUSY.
*
* If sillyrename() returns 0, we do nothing, otherwise we unlink.
*
* inode->i_nlink is updated here rather than waiting for the next
* nfs_refresh_inode() for cosmetic reasons only.
*/
static int nfs_unlink(struct inode *dir, struct dentry *dentry)
{
......@@ -549,12 +699,21 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
if (error)
error = nfs_sillyrename(dir, dentry);
if (error == -EBUSY) {
return -EBUSY;
} else if (error < 0) {
error = nfs_proc_remove(NFS_SERVER(dir),
NFS_FH(dir), dentry->d_name.name);
if (error < 0)
return error;
dentry->d_inode->i_nlink --;
nfs_invalidate_dircache(dir);
d_delete(dentry);
}
return 0;
}
......@@ -588,7 +747,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
return error;
nfs_invalidate_dircache(dir);
/* this looks _funny_ doesn't it? But: nfs_proc_symlynk()
/* this looks _funny_ doesn't it? But: nfs_proc_symlink()
* only fills in sattr, not fattr. Thus nfs_fhget() cannot be
* called, it would be pointless, without a valid fattr
* argument. Other possibility: call nfs_proc_lookup()
......@@ -623,7 +782,8 @@ static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentr
return error;
nfs_invalidate_dircache(dir);
inode->i_count++;
inode->i_count ++;
inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
d_instantiate(dentry, inode);
return 0;
}
......@@ -634,8 +794,17 @@ static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentr
* different file handle for the same inode after a rename (e.g. when
* moving to a different directory). A fail-safe method to do so would
* be to look up old_dir/old_name, create a link to new_dir/new_name and
* rename the old file using the silly_rename stuff. This way, the original
* rename the old file using the sillyrename stuff. This way, the original
* file in old_dir will go away when the last process iput()s the inode.
*
* FIXED.
*
* It actually works quite well. One needs to have the possibility for
* at least one ".nfs..." file in each directory the file ever gets
* moved or linked to which happens automagically with the new
* implementation that only depends on the dcache stuff instead of
* using the inode layer
*
*/
static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
......@@ -659,10 +828,22 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (old_dentry->d_name.len > NFS_MAXNAMLEN || new_dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;
if (new_dir != old_dir) {
error = nfs_sillyrename(old_dir, old_dentry);
if (error == -EBUSY) {
return -EBUSY;
} else if (error == 0) { /* did silly rename stuff */
error = nfs_link(old_dentry->d_inode,
new_dir, new_dentry);
return error;
}
/* no need for silly rename, proceed as usual */
}
error = nfs_proc_rename(NFS_SERVER(old_dir),
NFS_FH(old_dir), old_dentry->d_name.name,
NFS_FH(new_dir), new_dentry->d_name.name);
if (error)
return error;
......@@ -737,3 +918,10 @@ void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
} else
inode->i_op = NULL;
}
/*
* Local variables:
* version-control: t
* kept-new-versions: 5
* End:
*/
......@@ -77,10 +77,6 @@ nfs_put_inode(struct inode * inode)
dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
}
/*
* This should do any silly-rename cleanups once we
* get silly-renaming working again..
*/
static void
nfs_delete_inode(struct inode * inode)
{
......@@ -454,6 +450,8 @@ int
init_nfs_fs(void)
{
#ifdef CONFIG_PROC_FS
rpc_register_sysctl();
rpc_proc_init();
rpc_proc_register(&nfs_rpcstat);
#endif
return register_filesystem(&nfs_fs_type);
......
......@@ -46,6 +46,7 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
/*
* Get a file's attributes
* N.B. After this call resp->fh needs an fh_put
*/
static int
nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
......@@ -64,6 +65,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
/*
* Set a file's attributes
* N.B. After this call resp->fh needs an fh_put
*/
static int
nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
......@@ -82,6 +84,7 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
/*
* Look up a path name component
* N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put
*/
static int
nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
......@@ -134,11 +137,13 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
/* Read the symlink. */
resp->len = NFS3_MAXPATHLEN;
nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len);
fh_put(&argp->fh);
RETURN(nfserr);
}
/*
* Read a portion of a file.
* N.B. After this call resp->fh needs an fh_put
*/
static int
nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
......@@ -180,6 +185,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
/*
* Write data to a file
* N.B. After this call resp->fh needs an fh_put
*/
static int
nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
......@@ -207,6 +213,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
* With NFSv3, CREATE processing is a lot easier than with NFSv2.
* At least in theory; we'll see how it fares in practice when the
* first reports about SunOS compatibility problems start to pour in...
* N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put
*/
static int
nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
......@@ -246,6 +253,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
RETURN(nfserr);
}
/* N.B. Is nfsd3_attrstat * correct for resp?? table says "void" */
static int
nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
struct nfsd3_attrstat *resp)
......@@ -257,11 +265,16 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
SVCFH_INO(&argp->fh),
argp->name);
/* Is this correct?? */
fh_copy(&resp->fh, &argp->fh);
/* Unlink. -S_IFDIR means file must not be a directory */
nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
argp->name, argp->len);
nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
/*
* N.B. Should be an fh_put here ... nfsd3_proc_rmdir has one,
* or else as an xdr release function
*/
fh_put(&resp->fh);
RETURN(nfserr);
}
......@@ -336,6 +349,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
/*
* Make directory. This operation is not idempotent.
* N.B. After this call resp->fh needs an fh_put
*/
static int
nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
......@@ -449,13 +463,13 @@ struct svc_procedure nfsd3_procedures2[18] = {
PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE),
PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF),
PROC(none, void, void, void, RC_NOCACHE),
PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE),
PROC(lookup, diropargs, diropres, fhandle2,RC_NOCACHE),
PROC(readlink, fhandle, readlinkres, void, RC_NOCACHE),
PROC(read, readargs, readres, fhandle, RC_NOCACHE),
PROC(none, void, void, void, RC_NOCACHE),
PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF),
PROC(create, createargs, diropres, fhandle, RC_REPLBUFF),
PROC(remove, diropargs, void, void, RC_REPLSTAT),
PROC(create, createargs, diropres, fhandle2,RC_REPLBUFF),
PROC(remove, diropargs, void,/* ??*/ void, RC_REPLSTAT),
PROC(rename, renameargs, void, void, RC_REPLSTAT),
PROC(link, linkargs, void, void, RC_REPLSTAT),
PROC(symlink, symlinkargs, void, void, RC_REPLSTAT),
......
This diff is collapsed.
This diff is collapsed.
......@@ -295,14 +295,20 @@ static int get_uptime(char * buffer)
static int get_meminfo(char * buffer)
{
struct sysinfo i;
int len;
si_meminfo(&i);
si_swapinfo(&i);
len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n"
"Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n"
"Swap: %8lu %8lu %8lu\n",
i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, page_cache_size*PAGE_SIZE,
i.totalswap, i.totalswap-i.freeswap, i.freeswap);
/*
* Tagged format, for easy grepping and expansion.
* Tagged format, for easy grepping and expansion. The above will go away
* eventually, once the tools have been updated.
*/
return sprintf(buffer,
return len + sprintf(buffer+len,
"MemTotal: %8lu kB\n"
"MemFree: %8lu kB\n"
"MemShared: %8lu kB\n"
......
......@@ -840,26 +840,19 @@ static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode
if (!dir)
return -ENOENT;
if (dentry->d_name.len > 256) {
iput (dir);
if (dentry->d_name.len > 256)
return -EINVAL;
}
if (aliases_nodes == ALIASES_NNODES) {
iput (dir);
if (aliases_nodes == ALIASES_NNODES)
return -EIO;
}
p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL);
if (!p) {
iput (dir);
if (!p)
return -ENOMEM;
}
strncpy (p, dentry->d_name.name, dentry->d_name.len);
p [dentry->d_name.len] = 0;
alias_names [aliases_nodes++] = p;
inode = proc_get_inode (dir->i_sb,
NODEP2INO(NODE(dir->i_ino).first_prop)
+ aliases_nodes, 0);
iput (dir);
if (!inode)
return -EINVAL;
inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
......
This diff is collapsed.
......@@ -423,7 +423,7 @@ asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
wait_table.nr = 0;
wait_table.entry = entry;
fdcount = do_poll(nfds, fds, &wait_table);
fdcount = do_poll(nfds, fds, timeout ? &wait_table : NULL);
current->timeout = 0;
free_wait(&wait_table);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -123,6 +123,7 @@ struct lp_struct {
unsigned int lastcall;
unsigned int runchars;
unsigned int waittime;
unsigned int should_relinquish;
struct lp_stats stats;
};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment