diff -u --recursive --new-file v2.1.88/linux/CREDITS linux/CREDITS --- v2.1.88/linux/CREDITS Mon Feb 23 18:12:01 1998 +++ linux/CREDITS Wed Feb 25 10:47:19 1998 @@ -37,7 +37,8 @@ E: cananian@alumni.princeton.edu W: http://www.pdos.lcs.mit.edu/~cananian P: 1024/85AD9EED AD C0 49 08 91 67 DF D7 FA 04 1A EE 09 E8 44 B0 -D: pty improvements. +D: Unix98 pty support. +D: APM update to 1.2 spec. N: Erik Andersen E: andersee@debian.org @@ -930,8 +931,8 @@ N: Bas Laarhoven E: bas@vimec.nl D: Loadable modules and ftape driver -S: Mr. v. Boemellaan 39 -S: NL-5237 KA 's-Hertogenbosch +S: J. Obrechtstr 23 +S: NL-5216 GP 's-Hertogenbosch S: The Netherlands N: Savio Lam @@ -1133,8 +1134,8 @@ N: Dirk Melchers E: dirk@merlin.nbg.sub.org D: 8 bit XT hard disk driver for OMTI5520 -S: Heidackerstrass 19 -S: D-91056 Erlangen +S: Schloessleinsgasse 31 +S: D-90453 Nuernberg S: Germany N: Michael Meskes @@ -1841,10 +1842,12 @@ S: The Netherlands N: David Woodhouse -E: dwmw2@cam.ac.uk +E: Dave@imladris.demon.co.uk D: Extensive ARCnet rewrite D: ARCnet COM20020, COM90xx IO-MAP drivers D: SO_BINDTODEVICE in 2.1.x (from Elliot Poger's code in 2.0.31) +D: Contributed to NCPFS rewrite for 2.1.x dcache +D: Alpha platforms: SX164, LX164 and Ruffian ported to 2.1.x S: Robinson College, Grange Road S: Cambridge. CB3 9AN S: England diff -u --recursive --new-file v2.1.88/linux/Documentation/Changes linux/Documentation/Changes --- v2.1.88/linux/Documentation/Changes Sun Nov 30 12:23:16 1997 +++ linux/Documentation/Changes Tue Feb 24 23:49:20 1998 @@ -14,10 +14,10 @@ therefore owes credit to the same people as that file (Jared Mauch, Axel Boldt, Alessandro Sigala, and countless other users all over the 'net). Please feel free to submit changes, corrections, gripes, -flames, money, etc. to me (gt1355b@prism.gatech.edu). If you do so, -you don't need to bother doing so in the form of a diff, as this is -generated by texinfo so a diff is useless anyway (though I can -incorporate one by hand if you insist upon sending it that way ;-). +flames, money, etc. to me (kaboom@gatech.edu). If you do so, you don't +need to bother doing so in the form of a diff, as this is generated by +texinfo so a diff is useless anyway (though I can incorporate one by +hand if you insist upon sending it that way ;-). Check out http://www.cviog.uga.edu/Misc/info/LinuxBleed.html for an HTML-ized shopping list. @@ -26,8 +26,14 @@ http://www.datanet.hu/generations/linux/Changes2.html is an English-language HTML version. -Last updated: September 13. 1997 -Current Author: Chris Ricker (gt1355b@prism.gatech.edu). + The most current version should always be available from +http://cyberbuzz.gatech.edu/kaboom/linux/ as well. + + Also, don't forget http://www.linuxhq.com/ for all your Linux kernel +needs. + +Last updated: February 16. 1998 +Current Author: Chris Ricker (kaboom@gatech.edu). Current Minimal Requirements **************************** @@ -36,21 +42,24 @@ encountered a bug! If you're unsure what version you're currently running, the suggested command should tell you. -- Kernel modules modutils-2.1.55 ; insmod -V +- Kernel modules modutils-2.1.85 ; insmod -V - Gnu C 2.7.2.3 ; gcc --version - Binutils 2.8.1.0.1 ; ld -v - Linux C Library 5.4.38 ; ls -l /lib/libc.so.* - Dynamic Linker (ld.so) 1.9.5 ; ldd -v - Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.* -- Procps 1.2 ; ps --version +- Procps 1.2.5 ; ps --version - Procinfo 0.11 ; procinfo -v -- Mount 2.6h ; mount --version +- Mount 2.7l ; mount --version - Net-tools 1.41 ; hostname -V - Loadlin 1.6a - Sh-utils 1.16 ; expr --v -- Autofs 0.3.11 ; automount --version +- Autofs 0.3.11 ; automount --version - NFS 0.4.21 ; showmount --version - Bash 1.14.7 ; bash -version +- Ncpfs 2.1.1 ; ncpmount -v +- Pcmcia-cs 2.9.12 +- PPP 2.3.3 ; pppd -v Upgrade notes ************* @@ -76,7 +85,7 @@ For modules to work, you need to be running libc-5.4.x or greater. Since updates to libc fix other problems as well (security flaws, for example) and since 5.4.7 is missing a few needed symbols, try to get -the latest 5.4.x you can. Currently, libc-5.4.38 is the latest public +the latest 5.4.x you can. Currently, libc-5.4.44 is the latest public release. If you upgrade to libc-5.4.x, you also have to upgrade your dynamic @@ -90,10 +99,14 @@ If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if you're using NIS. + If you upgrade to libc-5.4.44, please read and pay attention to its +accompanying release notes. The section about it breaking make is not +a joke. + Modules ======= - You need to upgrade to modutils-2.1.55 for kernels 2.1.55 and later. + You need to upgrade to modutils-2.1.85 for kernels 2.1.85 and later. This version will also work with 2.0.x kernels. Binutils @@ -108,9 +121,13 @@ You need at least GCC 2.7.2 to compile the kernel. If you're upgrading from an earlier release, you might as well get GCC 2.7.2.3, -the latest public release. If you already have GCC 2.7.2 on your -system, you don't have to upgrade just so the kernel will work (though -feel free to upgrade if you want the gcc bug fixes). +the latest stable public release. If you already have GCC 2.7.2 on +your system, you don't have to upgrade just so the kernel will work +(though feel free to upgrade if you want the gcc bug fixes). + + Note that the latest compilers (egcs, pgcc, gcc 2.8) may do Bad +Things while compiling your kernel, particularly if absurd +optimizations (like -O9) are used. Caveat emptor. Networking Changes ================== @@ -190,18 +207,13 @@ /dev/lp0 with the new Plug-and-Play driver. If printing breaks with the new driver, try checking your lpd configuration. -pppd -==== -This kernel version needs a minor bugfix to pppd. See -Documentation/networking/ppp.txt for more information. - Syncookies ========== -When you build your kernel with Syncookie support (CONFIG_SYN_COOKIES) -the syncookie code still defaults to off (unlike the 2.0.30+ behaviour). -You have to explicitely enable it by add a line like -echo 1 >/proc/sys/net/ipv4/tcp_syncookies -to one of your startup scripts (e.g. /etc/rc.d/rc.local on a redhat system) + + When you build your kernel with Syncookie support +(CONFIG_SYN_COOKIES) the syncookie code still defaults to off (unlike +the 2.0.30+ behavior). You have to explicitly enable it by issuing the +following command: echo 1 > /proc/sys/net/ipv4/tcp_syncookies Bash ==== @@ -210,6 +222,24 @@ cause problems when compiling modules. Upgrade to at least 1.14 to fix this problem. +Ncpfs +===== + + To mount NetWare shares, you'll need to upgrade to a more recent +version of the ncpfs utils. + +Pcmcia-cs +========= + + If you use pcmcia cards, you'll need to upgrade the daemon and +support utils to the latest release of pcmcia-cs. + +PPP +=== + + Due to changes in the routing code, those of you using PPP +networking will need to upgrade your pppd. + Where to get the files ********************** @@ -263,16 +293,16 @@ Modules utilities ================= -The 2.1.55 release: -ftp://ftp.redhat.com/pub/alphabits/modutils/modutils-2.1.55.tar.gz -ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.55.tar.gz +The 2.1.85 release: +ftp://ftp.redhat.com/pub/alphabits/modutils/modutils-2.1.85.tar.gz +ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.85.tar.gz Procps utilities ================ The 1.2 release: -ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.tar.gz -ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.tgz +ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.5.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.5.tgz Procinfo utilities ================== @@ -317,8 +347,8 @@ Mount ===== -The 2.6h release: -ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6h.tar.gz +The 2.7l release: +ftp://ftp.win.tue.nl/pub/linux/util/mount/mount-2.7l.tar.gz Autofs ====== @@ -336,9 +366,8 @@ Net-tools ========= -The 1.41 release: -ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz -ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz +The 1.432 release: +ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.432.tar.gz Ypbind ====== @@ -352,6 +381,25 @@ The 1.14.7 release: ftp://prep.ai.mit.edu/pub/gnu/bash-1.14.7.tar.gz +Ncpfs +===== + +The 2.1.1 release: +ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.1.1.tgz +ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/ncpfs/ncpfs-2.1.1.tgz + +Pcmcia-cs +========= + +The 1.9.12 release: +ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs-2.9.12.tar.gz + +PPP +=== + +The 2.3.3 release: +ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.3.tar.gz + Other Info ========== @@ -380,5 +428,5 @@ Please send info about any other packages that 2.1.x "broke" or about any new features of 2.1.x that require extra or new packages for use to -Chris Ricker (gt1355b@prism.gatech.edu). +Chris Ricker (kaboom@gatech.edu). diff -u --recursive --new-file v2.1.88/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.88/linux/Documentation/Configure.help Wed Feb 4 11:35:59 1998 +++ linux/Documentation/Configure.help Tue Feb 24 22:37:02 1998 @@ -6477,6 +6477,13 @@ powers off the computer). As with the other APM options, this option may not work reliably with some APM BIOS implementations. +Ignore multiple suspend/standby events +CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + This option is necessary on the Thinkpad 560, but should work on all + other laptops. When the APM BIOS returns multiple suspend or standby + events while one is already being processed they will be ignored. + Without this the Thinkpad 560 has troubles with apmd, and pcmcia-cs. + Watchdog Timer Support CONFIG_WATCHDOG If you say Y here (and to one of the following options) and create a diff -u --recursive --new-file v2.1.88/linux/Documentation/filesystems/affs.txt linux/Documentation/filesystems/affs.txt --- v2.1.88/linux/Documentation/filesystems/affs.txt Tue Dec 2 22:25:07 1997 +++ linux/Documentation/filesystems/affs.txt Mon Feb 23 22:01:26 1998 @@ -65,6 +65,11 @@ verbose The volume name, file system type and block size will be written to the syslog when the filesystem is mounted. +mufs The filesystem is really a muFS, also it doesn't + identify itself as one. This option is neccessary if + the filesystem wasn't formatted as muFS, but is used + as one. + prefix=path Path will be prefixed to every absolute path name of symbolic links on an AFFS partition. Default = / diff -u --recursive --new-file v2.1.88/linux/Documentation/filesystems/vfs.txt linux/Documentation/filesystems/vfs.txt --- v2.1.88/linux/Documentation/filesystems/vfs.txt Sun Feb 2 05:18:29 1997 +++ linux/Documentation/filesystems/vfs.txt Tue Feb 24 22:08:00 1998 @@ -8,7 +8,7 @@ The VFS relatively simple, but it is nice not to have to browse through pages of code to determine what is expected when writing a filesystem. Hopefully this helps anyone attempting such a feat, as well as clearing up -a few important points/dependancies. +a few important points/dependencies. register_filesystem (struct file_system_type *fstype) diff -u --recursive --new-file v2.1.88/linux/Documentation/isdn/README linux/Documentation/isdn/README --- v2.1.88/linux/Documentation/isdn/README Thu May 29 21:53:03 1997 +++ linux/Documentation/isdn/README Tue Feb 24 22:08:00 1998 @@ -285,7 +285,7 @@ 5. Application a) For some card-types, firmware has to be loaded into the cards, before - proceeding with device-independant setup. See README. + proceeding with device-independent setup. See README. for how to do that. b) If you only intend to use ttys, you are nearly ready now. diff -u --recursive --new-file v2.1.88/linux/Documentation/m68k/kernel-options.txt linux/Documentation/m68k/kernel-options.txt --- v2.1.88/linux/Documentation/m68k/kernel-options.txt Tue Feb 17 13:12:43 1998 +++ linux/Documentation/m68k/kernel-options.txt Tue Feb 24 22:08:01 1998 @@ -567,7 +567,7 @@ type. The second parameter tells the kernel whether to use - track buffering (1) or not (0). The default is machine dependant: + track buffering (1) or not (0). The default is machine-dependent: no for the Medusa and yes for all others. With the two following parameters, you can change the default diff -u --recursive --new-file v2.1.88/linux/Makefile linux/Makefile --- v2.1.88/linux/Makefile Mon Feb 23 18:12:01 1998 +++ linux/Makefile Mon Feb 23 18:10:59 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 88 +SUBLEVEL = 89 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.88/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.1.88/linux/arch/alpha/config.in Tue Feb 17 13:12:44 1998 +++ linux/arch/alpha/config.in Mon Feb 23 10:25:10 1998 @@ -46,6 +46,8 @@ EB64+ CONFIG_ALPHA_EB64P \ EB164 CONFIG_ALPHA_EB164 \ PC164 CONFIG_ALPHA_PC164 \ + LX164 CONFIG_ALPHA_LX164 \ + SX164 CONFIG_ALPHA_SX164 \ Jensen CONFIG_ALPHA_JENSEN \ Noname CONFIG_ALPHA_NONAME \ Mikasa CONFIG_ALPHA_MIKASA \ @@ -54,6 +56,7 @@ Miata CONFIG_ALPHA_MIATA \ Sable CONFIG_ALPHA_SABLE \ AlphaBook1 CONFIG_ALPHA_BOOK1 \ + Ruffian CONFIG_ALPHA_RUFFIAN \ Platform2000 CONFIG_ALPHA_P2K" Cabriolet if [ "$CONFIG_ALPHA_BOOK1" = "y" ] @@ -102,7 +105,8 @@ define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_T2 y fi -if [ "$CONFIG_ALPHA_MIATA" = "y" ] +if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \ + -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ] then define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y @@ -122,7 +126,8 @@ -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \ -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ - -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" ] + -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ + -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" ] then bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM fi diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.1.88/linux/arch/alpha/kernel/Makefile Tue Feb 17 13:12:44 1998 +++ linux/arch/alpha/kernel/Makefile Mon Feb 23 10:25:10 1998 @@ -35,6 +35,13 @@ ifdef CONFIG_ALPHA_T2 O_OBJS += t2.o endif +ifneq ($(CONFIG_ALPHA_PC164)$(CONFIG_ALPHA_LX164),nn) +O_OBJS += smc37c93x.o +endif +ifdef CONFIG_ALPHA_SX164 +O_OBJS += smc37c669.o +endif + all: kernel.o head.o diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.1.88/linux/arch/alpha/kernel/bios32.c Mon Jan 12 14:51:14 1998 +++ linux/arch/alpha/kernel/bios32.c Mon Feb 23 10:25:10 1998 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #if 0 # define DBG_DEVS(args) printk args @@ -98,8 +100,11 @@ extern struct hwrpb_struct *hwrpb; /* Forward declarations for some extra fixup routines for specific hardware. */ -#ifdef CONFIG_ALPHA_PC164 -static int SMCInit(void); +#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) +extern int SMC93x_Init(void); +#endif +#ifdef CONFIG_ALPHA_SX164 +extern int SMC669_Init(void); #endif #ifdef CONFIG_ALPHA_MIATA static int es1888_init(void); @@ -174,16 +179,25 @@ struct pci_bus *bus; unsigned short cmd; -#if defined(CONFIG_ALPHA_EISA) +#ifdef CONFIG_ALPHA_EISA /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( */ - if (dev->vendor == 0x8086 && dev->device == 0x0482) { + if (dev->vendor == PCI_VENDOR_ID_INTEL && + dev->device == PCI_DEVICE_ID_INTEL_82375) { DBG_DEVS(("disable_dev: ignoring PCEB...\n")); return; } #endif +#ifdef CONFIG_ALPHA_SX164 + if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + /* FIXME: We want a symbolic device name here. */ + dev->device == 0xc693) { + DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n")); + return; + } +#endif bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); @@ -206,6 +220,7 @@ unsigned int base, mask, size, reg; unsigned int alignto; +#ifdef CONFIG_ALPHA_EISA /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( @@ -215,6 +230,14 @@ DBG_DEVS(("layout_dev: ignoring PCEB...\n")); return; } +#endif +#ifdef CONFIG_ALPHA_SX164 + if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + dev->device == 0xc693) { + DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n")); + return; + } +#endif bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); @@ -729,6 +752,46 @@ 0x0000000); } } +#ifdef CONFIG_ALPHA_SX164 + /* If it the CYPRESS PCI-ISA bridge, disable IDE + interrupt routing through PCI (ie do through PIC). */ + else if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + dev->device == 0xc693 && + PCI_FUNC(dev->devfn) == 0) { + pcibios_write_config_word(dev->bus->number, + dev->devfn, 0x04, 0x0007); + + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x40, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x41, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x42, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x43, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x44, 0x27); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x45, 0xe0); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x48, 0xf0); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x49, 0x40); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4a, 0x00); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4b, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4c, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4d, 0x70); + + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); + } +#endif /* SX164 */ } if (ide_base) { enable_ide(ide_base); @@ -750,7 +813,7 @@ */ static inline void eb66p_fixup(void) { - static char irq_tab[5][5] = { + static char irq_tab[5][5] __initdata = { {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */ {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ @@ -762,7 +825,7 @@ /* - * The PC164 has 19 PCI interrupts, four from each of the four PCI + * The PC164/LX164 has 19 PCI interrupts, four from each of the four PCI * slots, the SIO, PCI/IDE, and USB. * * Each of the interrupts can be individually masked. This is @@ -803,10 +866,10 @@ * */ -#ifdef CONFIG_ALPHA_PC164 +#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) static inline void alphapc164_fixup(void) { - static char irq_tab[7][5] = { + static char irq_tab[7][5] __initdata = { /*INT INTA INTB INTC INTD */ { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */ { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */ @@ -818,7 +881,7 @@ }; common_fixup(5, 11, 5, irq_tab, 0); - SMCInit(); + SMC93x_Init(); } #endif @@ -837,7 +900,7 @@ */ static inline void cabriolet_fixup(void) { - static char irq_tab[5][5] = { + static char irq_tab[5][5] __initdata = { { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */ { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */ { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */ @@ -893,7 +956,7 @@ */ static inline void eb66_and_eb64p_fixup(void) { - static char irq_tab[5][5] = { + static char irq_tab[5][5] __initdata = { {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */ {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */ {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */ @@ -942,7 +1005,7 @@ */ static inline void mikasa_fixup(void) { - static char irq_tab[8][5] = { + static char irq_tab[8][5] __initdata = { /*INT INTA INTB INTC INTD */ {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */ { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ @@ -1013,7 +1076,7 @@ */ static inline void noritake_fixup(void) { - static char irq_tab[13][5] = { + static char irq_tab[13][5] __initdata = { /*INT INTA INTB INTC INTD */ { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ { -1, -1, -1, -1, -1}, /* IdSel 19, PPB */ @@ -1077,7 +1140,7 @@ */ static inline void alcor_fixup(void) { - static char irq_tab[6][5] = { + static char irq_tab[6][5] __initdata = { /*INT INTA INTB INTC INTD */ { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 19, slot 3 */ @@ -1132,7 +1195,7 @@ */ static inline void xlt_fixup(void) { - static char irq_tab[7][5] = { + static char irq_tab[7][5] __initdata = { /*INT INTA INTB INTC INTD */ {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */ { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ @@ -1194,13 +1257,16 @@ * above for PCI interrupts. The IRQ relates to which bit the interrupt * comes in on. This makes interrupt processing much easier. */ -/* NOTE: the IRQ assignments below are arbitrary, but need to be consistent - with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables - in irq.c +/* + * NOTE: the IRQ assignments below are arbitrary, but need to be consistent + * with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables + * in irq.c */ + +#ifdef CONFIG_ALPHA_SABLE static inline void sable_fixup(void) { - static char irq_tab[9][5] = { + static char irq_tab[9][5] __initdata = { /*INT INTA INTB INTC INTD */ { 32+0, 32+0, 32+0, 32+0, 32+0}, /* IdSel 0, TULIP */ { 32+1, 32+1, 32+1, 32+1, 32+1}, /* IdSel 1, SCSI */ @@ -1214,6 +1280,7 @@ }; common_fixup(0, 8, 5, irq_tab, 0); } +#endif /* * Fixup configuration for MIATA (EV56+PYXIS) @@ -1282,7 +1349,7 @@ #ifdef CONFIG_ALPHA_MIATA static inline void miata_fixup(void) { - static char irq_tab[18][5] = { + static char irq_tab[18][5] __initdata = { /*INT INTA INTB INTC INTD */ {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8}, /* IdSel 14, DC21142 */ { -1, -1, -1, -1, -1}, /* IdSel 15, EIDE */ @@ -1311,6 +1378,64 @@ #endif /* + * Fixup configuration for SX164 (PCA56+PYXIS) + * + * Summary @ PYXIS_INT_REQ: + * Bit Meaning + * 0 RSVD + * 1 NMI + * 2 Halt/Reset switch + * 3 MBZ + * 4 RAZ + * 5 RAZ + * 6 Interval timer (RTC) + * 7 PCI-ISA Bridge + * 8 Interrupt Line A from slot 3 + * 9 Interrupt Line A from slot 2 + *10 Interrupt Line A from slot 1 + *11 Interrupt Line A from slot 0 + *12 Interrupt Line B from slot 3 + *13 Interrupt Line B from slot 2 + *14 Interrupt Line B from slot 1 + *15 Interrupt line B from slot 0 + *16 Interrupt Line C from slot 3 + + *17 Interrupt Line C from slot 2 + *18 Interrupt Line C from slot 1 + *19 Interrupt Line C from slot 0 + *20 Interrupt Line D from slot 3 + *21 Interrupt Line D from slot 2 + *22 Interrupt Line D from slot 1 + *23 Interrupt Line D from slot 0 + * + * IdSel + * 5 32 bit PCI option slot 2 + * 6 64 bit PCI option slot 0 + * 7 64 bit PCI option slot 1 + * 8 Cypress I/O + * 9 32 bit PCI option slot 3 + * + */ + +#ifdef CONFIG_ALPHA_SX164 +static inline void sx164_fixup(void) +{ + static char irq_tab[5][5] __initdata = { + /*INT INTA INTB INTC INTD */ + { 16+ 9, 16+ 9, 16+13, 16+17, 16+21}, /* IdSel 5 slot 2 J17 */ + { 16+11, 16+11, 16+15, 16+19, 16+23}, /* IdSel 6 slot 0 J19 */ + { 16+10, 16+10, 16+14, 16+18, 16+22}, /* IdSel 7 slot 1 J18 */ + { -1, -1, -1, -1, -1}, /* IdSel 8 SIO */ + { 16+ 8, 16+ 8, 16+12, 16+16, 16+20} /* IdSel 9 slot 3 J15 */ + }; + + common_fixup(5, 9, 5, irq_tab, 0); + + SMC669_Init(); +} +#endif + +/* * Fixup configuration for all boards that route the PCI interrupts * through the SIO PCI/ISA bridge. This includes Noname (AXPpci33), * Avanti (AlphaStation) and Kenetics's Platform 2000. @@ -1336,7 +1461,7 @@ * that they use the default INTA line, if they are interrupt * driven at all). */ - static const char pirq_tab[][5] = { + static const char pirq_tab[][5] __initdata = { #ifdef CONFIG_ALPHA_P2K { 0, 0, -1, -1, -1}, /* idsel 6 (53c810) */ {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */ @@ -1560,9 +1685,10 @@ extern void tga_console_init(void); #endif /* CONFIG_TGA_CONSOLE */ -unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) +unsigned long __init +pcibios_fixup(unsigned long mem_start, unsigned long mem_end) { -#if PCI_MODIFY +#if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN) /* * Scan the tree, allocating PCI memory and I/O space. */ @@ -1577,7 +1703,7 @@ sio_fixup(); #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB164) cabriolet_fixup(); -#elif defined(CONFIG_ALPHA_PC164) +#elif defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) alphapc164_fixup(); #elif defined(CONFIG_ALPHA_EB66P) eb66p_fixup(); @@ -1597,6 +1723,10 @@ miata_fixup(); #elif defined(CONFIG_ALPHA_NORITAKE) noritake_fixup(); +#elif defined(CONFIG_ALPHA_SX164) + sx164_fixup(); +#elif defined(CONFIG_ALPHA_RUFFIAN) + /* no fixup needed */ #else # error "You must tell me what kind of platform you want." #endif @@ -1702,251 +1832,12 @@ } -#ifdef CONFIG_ALPHA_PC164 -/* device "activate" register contents */ -#define DEVICE_ON 1 -#define DEVICE_OFF 0 - -/* configuration on/off keys */ -#define CONFIG_ON_KEY 0x55 -#define CONFIG_OFF_KEY 0xaa - -/* configuration space device definitions */ -#define FDC 0 -#define IDE1 1 -#define IDE2 2 -#define PARP 3 -#define SER1 4 -#define SER2 5 -#define RTCL 6 -#define KYBD 7 -#define AUXIO 8 - -/* Chip register offsets from base */ -#define CONFIG_CONTROL 0x02 -#define INDEX_ADDRESS 0x03 -#define LOGICAL_DEVICE_NUMBER 0x07 -#define DEVICE_ID 0x20 -#define DEVICE_REV 0x21 -#define POWER_CONTROL 0x22 -#define POWER_MGMT 0x23 -#define OSC 0x24 - -#define ACTIVATE 0x30 -#define ADDR_HI 0x60 -#define ADDR_LO 0x61 -#define INTERRUPT_SEL 0x70 -#define INTERRUPT_SEL_2 0x72 /* KYBD/MOUS only */ -#define DMA_CHANNEL_SEL 0x74 /* FDC/PARP only */ - -#define FDD_MODE_REGISTER 0x90 -#define FDD_OPTION_REGISTER 0x91 - -/* values that we read back that are expected ... */ -#define VALID_DEVICE_ID 2 - -/* default device addresses */ -#define KYBD_INTERRUPT 1 -#define MOUS_INTERRUPT 12 -#define COM2_BASE 0x2f8 -#define COM2_INTERRUPT 3 -#define COM1_BASE 0x3f8 -#define COM1_INTERRUPT 4 -#define PARP_BASE 0x3bc -#define PARP_INTERRUPT 7 - -#define SMC_DEBUG 0 - -static unsigned long SMCConfigState(unsigned long baseAddr) -{ - unsigned char devId; - unsigned char devRev; - - unsigned long configPort; - unsigned long indexPort; - unsigned long dataPort; - - configPort = indexPort = baseAddr; - dataPort = configPort + 1; - - outb(CONFIG_ON_KEY, configPort); - outb(CONFIG_ON_KEY, configPort); - outb(DEVICE_ID, indexPort); - devId = inb(dataPort); - if ( devId == VALID_DEVICE_ID ) { - outb(DEVICE_REV, indexPort); - devRev = inb(dataPort); - } - else { - baseAddr = 0; - } - return baseAddr; -} - -static void SMCRunState(unsigned long baseAddr) -{ - outb(CONFIG_OFF_KEY, baseAddr); -} - -static unsigned long SMCDetectUltraIO(void) -{ - unsigned long baseAddr; - - baseAddr = 0x3F0; - if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) { - return( baseAddr ); - } - baseAddr = 0x370; - if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) { - return( baseAddr ); - } - return( ( unsigned long )0 ); -} - -static void SMCEnableDevice(unsigned long baseAddr, - unsigned long device, - unsigned long portaddr, - unsigned long interrupt) -{ - unsigned long indexPort; - unsigned long dataPort; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(device, dataPort); - - outb(ADDR_LO, indexPort); - outb(( portaddr & 0xFF ), dataPort); - - outb(ADDR_HI, indexPort); - outb((portaddr >> 8) & 0xFF, dataPort); - - outb(INTERRUPT_SEL, indexPort); - outb(interrupt, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); -} - -static void SMCEnableKYBD(unsigned long baseAddr) -{ - unsigned long indexPort; - unsigned long dataPort; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(KYBD, dataPort); - - outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ - outb(KYBD_INTERRUPT, dataPort); - - outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */ - outb(MOUS_INTERRUPT, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); -} - -static void SMCEnableFDC(unsigned long baseAddr) -{ - unsigned long indexPort; - unsigned long dataPort; - - unsigned char oldValue; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(FDC, dataPort); - - outb(FDD_MODE_REGISTER, indexPort); - oldValue = inb(dataPort); - - oldValue |= 0x0E; /* Enable burst mode */ - outb(oldValue, dataPort); - - outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ - outb(0x06, dataPort ); - - outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */ - outb(0x02, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); -} - -#if SMC_DEBUG -static void SMCReportDeviceStatus(unsigned long baseAddr) -{ - unsigned long indexPort; - unsigned long dataPort; - unsigned char currentControl; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(POWER_CONTROL, indexPort); - currentControl = inb(dataPort); - - printk(currentControl & (1 << FDC) - ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n"); - printk(currentControl & (1 << IDE1) - ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n"); - printk(currentControl & (1 << IDE2) - ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n"); - printk(currentControl & (1 << PARP) - ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n"); - printk(currentControl & (1 << SER1) - ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n"); - printk(currentControl & (1 << SER2) - ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n"); - - printk( "\n" ); -} -#endif - -static int SMCInit(void) -{ - unsigned long SMCUltraBase; - - if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) { - printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", - SMCUltraBase); -#if SMC_DEBUG - SMCReportDeviceStatus(SMCUltraBase); -#endif - SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT); - SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT); - SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT); - /* On PC164, IDE on the SMC is not enabled; - CMD646 (PCI) on MB */ - SMCEnableKYBD(SMCUltraBase); - SMCEnableFDC(SMCUltraBase); -#if SMC_DEBUG - SMCReportDeviceStatus(SMCUltraBase); -#endif - SMCRunState(SMCUltraBase); - return 1; - } - else { -#if SMC_DEBUG - printk("No SMC FDC37C93X Ultra I/O Controller found\n"); -#endif - return 0; - } -} -#endif /* CONFIG_ALPHA_PC164 */ - #ifdef CONFIG_ALPHA_MIATA /* * Init the built-in ES1888 sound chip (SB16 compatible) */ -static int es1888_init(void) +static int __init +es1888_init(void) { /* Sequence of IO reads to init the audio controller */ inb(0x0229); diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.1.88/linux/arch/alpha/kernel/irq.c Mon Feb 23 18:12:01 1998 +++ linux/arch/alpha/kernel/irq.c Mon Feb 23 10:25:10 1998 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,9 @@ #elif defined(CONFIG_ALPHA_ALCOR) /* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */ # define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL) +#elif defined(CONFIG_ALPHA_RUFFIAN) + /* must leave timer irq 0 in the mask */ +# define PROBE_MASK ((1UL << NR_IRQS) - 1) #else /* always mask out unused timer irq 0: */ # define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL) @@ -210,6 +214,53 @@ } } +#ifdef CONFIG_ALPHA_RUFFIAN +static inline void +ruffian_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + case 16 ... 47: + /* Note inverted sense of mask bits: */ + /* Make CERTAIN none of the bogus ints get enabled... */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & 0x00000000ffffffbfUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} +#endif + +#ifdef CONFIG_ALPHA_SX164 +static inline void +sx164_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + case 16 ... 39: + /* Make CERTAIN none of the bogus ints get enabled */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & ~0x000000000000003bUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} +#endif + /* Unlabeled mechanisms based on the number of irqs. Someone should probably document and name these. */ @@ -262,7 +313,8 @@ } } -#if defined(CONFIG_ALPHA_PC164) && defined(CONFIG_ALPHA_SRM) +#if (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \ + && defined(CONFIG_ALPHA_SRM) /* * On the pc164, we cannot take over the IRQs from the SRM, * so we call down to do our dirty work. Too bad the SRM @@ -313,6 +365,10 @@ alcor_and_xlt_update_hw(irq, mask); #elif defined(CONFIG_ALPHA_MIKASA) mikasa_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_SX164) + sx164_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_update_hw(irq, mask); #elif NR_IRQS == 33 update_hw_33(irq, mask); #elif NR_IRQS == 32 @@ -355,7 +411,7 @@ unmask_irq(IRQ_TO_MASK(irq_nr)); restore_flags(flags); } -#endif /* PC164 && SRM */ +#endif /* (PC164 || LX164) && SRM */ /* * Initial irq handlers. @@ -404,9 +460,23 @@ outb(0xE0 | 4, 0x534); /* slave 2 */ break; } -#else /* CONFIG_ALPHA_SABLE */ +#elif defined(CONFIG_ALPHA_RUFFIAN) if (irq < 16) { - /* ACK the interrupt making it the lowest priority */ + /* Ack PYXIS ISA interrupt. */ + *(vulp)PYXIS_INT_REQ = 1 << 7; + mb(); + if (irq > 7) { + outb(0x20, 0xa0); + } + outb(0x20, 0x20); + } else { + /* Ack PYXIS interrupt. */ + *(vulp)PYXIS_INT_REQ = (1UL << (irq - 16)); + mb(); + } +#else + if (irq < 16) { + /* Ack the interrupt making it the lowest priority */ /* First the slave .. */ if (irq > 7) { outb(0xE0 | (irq - 8), 0xa0); @@ -418,9 +488,9 @@ /* on ALCOR/XLT, need to dismiss interrupt via GRU */ *(vuip)GRU_INT_CLEAR = 0x80000000; mb(); *(vuip)GRU_INT_CLEAR = 0x00000000; mb(); -#endif /* ALCOR || XLT */ +#endif } -#endif /* CONFIG_ALPHA_SABLE */ +#endif } int check_irq(unsigned int irq) @@ -830,7 +900,7 @@ restore_flags(flags); } -#if defined(CONFIG_ALPHA_MIATA) +#if defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164) /* We have to conditionally compile this because of PYXIS_xxx symbols */ static inline void miata_device_interrupt(unsigned long vector, struct pt_regs *regs) @@ -850,15 +920,19 @@ *(vulp)PYXIS_INT_MASK, inb(0x20) | (inb(0xA0) << 8)); #endif -#if 1 - /* - * For now, AND off any bits we are not interested in: - * HALT (2), timer (6), ISA Bridge (7), 21142/3 (8) - * then all the PCI slots/INTXs (12-31). - */ + /* For now, AND off and bits we are not interested in. */ +#if defined(CONFIG_ALPHA_MIATA) + /* HALT (2), timer (6), ISA Bridge (7), 21142/3 (8), + then all the PCI slots/INTXs (12-31). */ /* Maybe HALT should only be used for SRM console boots? */ pld &= 0x00000000fffff1c4UL; #endif +#if defined(CONFIG_ALPHA_SX164) + /* HALT (2), timer (6), ISA Bridge (7), + then all the PCI slots/INTXs (8-23). */ + /* HALT should only be used for SRM console boots. */ + pld &= 0x0000000000ffffc0UL; +#endif /* * Now for every possible bit set, work through them and call @@ -879,7 +953,7 @@ } restore_flags(flags); } -#endif /* MIATA */ +#endif /* MIATA || SX164 */ static inline void noritake_device_interrupt(unsigned long vector, struct pt_regs *regs) @@ -917,6 +991,69 @@ restore_flags(flags); } +#if defined(CONFIG_ALPHA_RUFFIAN) +static inline void +ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* Read the interrupt summary register of PYXIS */ + pld = *(vulp)PYXIS_INT_REQ; + + /* For now, AND off any bits we are not interested in: + * HALT (2), timer (6), ISA Bridge (7), 21142 (8) + * then all the PCI slots/INTXs (12-31) + * flash(5) :DWH: + */ + pld &= 0x00000000ffffff9fUL; + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + + if (i == 7) { + /* Copy this bit from isa_device_interrupt cause + we need to hook into int 0 for the timer. I + refuse to soil device_interrupt with ifdefs. */ + + /* Generate a PCI interrupt acknowledge cycle. + The PIC will respond with the interrupt + vector of the highest priority interrupt + that is pending. The PALcode sets up the + interrupts vectors such that irq level L + generates vector L. */ + + unsigned int j = *(vuip)PYXIS_IACK_SC & 0xff; + if (j == 7 && !(inb(0x20) & 0x80)) { + /* It's only a passive release... */ + } else if (j == 0) { + timer_interrupt(regs); + ack_irq(0); + } else { + device_interrupt(j, j, regs); + } + } else { + device_interrupt(16 + i, 16 + i, regs); + } + + *(vulp)PYXIS_INT_REQ = 1UL << i; + mb(); + *(vulp)PYXIS_INT_REQ; + } + + restore_flags(flags); +} +#endif /* RUFFIAN */ + #endif /* CONFIG_PCI */ /* @@ -1119,16 +1256,18 @@ #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \ defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM) srm_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_MIATA) +#elif defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164) miata_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_NORITAKE) noritake_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) alcor_and_xlt_device_interrupt(vector, ®s); -#elif NR_IRQS == 33 - cabriolet_and_eb66p_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_MIKASA) mikasa_device_interrupt(vector, ®s); +#elif NR_IRQS == 33 + cabriolet_and_eb66p_device_interrupt(vector, ®s); #elif NR_IRQS == 32 eb66_and_eb64p_device_interrupt(vector, ®s); #elif NR_IRQS == 16 @@ -1154,6 +1293,57 @@ outb(0x44, 0x535); /* enable cascades in master */ } +#ifdef CONFIG_ALPHA_SX164 +static inline void sx164_init_IRQ(void) +{ + /* note invert on MASK bits */ + *(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); +#if 0 + *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */ + *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */ +#endif + enable_irq(16 + 6); /* enable timer */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(2); /* enable cascade */ +} +#endif /* SX164 */ + +#ifdef CONFIG_ALPHA_RUFFIAN +static inline void ruffian_init_IRQ(void) +{ + /* invert 6&7 for i82371 */ + *(vulp)PYXIS_INT_HILO = 0x000000c0UL; mb(); + *(vulp)PYXIS_INT_CNFG = 0x00002064UL; mb(); /* all clear */ + *(vulp)PYXIS_INT_MASK = 0x00000000UL; mb(); + *(vulp)PYXIS_INT_REQ = 0xffffffffUL; mb(); + + outb(0x11,0xA0); + outb(0x08,0xA1); + outb(0x02,0xA1); + outb(0x01,0xA1); + outb(0xFF,0xA1); + + outb(0x11,0x20); + outb(0x00,0x21); + outb(0x04,0x21); + outb(0x01,0x21); + outb(0xFF,0x21); + + /* Send -INTA pulses to clear any pending interrupts ...*/ + *(vuip) IACK_SC; + + /* Finish writing the 82C59A PIC Operation Control Words */ + outb(0x20,0xA0); + outb(0x20,0x20); + + /* Turn on the interrupt controller, the timer interrupt */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(0); /* enable timer */ + enable_irq(2); /* enable 2nd PIC cascade */ +} +#endif /* RUFFIAN */ + + #ifdef CONFIG_ALPHA_MIATA static inline void miata_init_IRQ(void) { @@ -1219,27 +1409,36 @@ enable_irq(2); /* enable cascade */ } -void init_IRQ(void) +void __init +init_IRQ(void) { wrent(entInt, 0); dma_outb(0, DMA1_RESET_REG); dma_outb(0, DMA2_RESET_REG); +#ifndef CONFIG_ALPHA_SX164 dma_outb(0, DMA1_CLR_MASK_REG); + /* We need to figure out why this fails on the SX164. */ dma_outb(0, DMA2_CLR_MASK_REG); +#endif #if defined(CONFIG_ALPHA_SABLE) sable_init_IRQ(); #elif defined(CONFIG_ALPHA_MIATA) miata_init_IRQ(); +#elif defined(CONFIG_ALPHA_SX164) + sx164_init_IRQ(); #elif defined(CONFIG_ALPHA_NORITAKE) noritake_init_IRQ(); #elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) alcor_and_xlt_init_IRQ(); -#elif defined(CONFIG_ALPHA_PC164) && defined(CONFIG_ALPHA_SRM) +#elif (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \ + && defined(CONFIG_ALPHA_SRM) /* Disable all the PCI interrupts? Otherwise, everthing was done by SRM already. */ #elif defined(CONFIG_ALPHA_MIKASA) mikasa_init_IRQ(); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_init_IRQ(); #elif NR_IRQS == 33 init_IRQ_33(); #elif NR_IRQS == 32 diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.1.88/linux/arch/alpha/kernel/osf_sys.c Tue Feb 17 13:12:44 1998 +++ linux/arch/alpha/kernel/osf_sys.c Tue Feb 24 18:04:07 1998 @@ -872,7 +872,7 @@ software but have not been seen, enable the exception in hardware so that we can update our software status mask. */ fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK); - fpcr = ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16); + fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16); wrfpcr(fpcr); return 0; diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/pyxis.c linux/arch/alpha/kernel/pyxis.c --- v2.1.88/linux/arch/alpha/kernel/pyxis.c Fri Jan 30 11:28:05 1998 +++ linux/arch/alpha/kernel/pyxis.c Mon Feb 23 10:25:10 1998 @@ -375,6 +375,10 @@ mb() ; pyxis_err = *(vuip)PYXIS_ERR ; +#ifdef CONFIG_ALPHA_RUFFIAN + printk("pyxis_init: Skipping window register rewrites --" + " trust DeskStation firmware!\n"); +#else /* * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, we may @@ -390,6 +394,7 @@ *(vuip)PYXIS_W2_BASE = 0x0 ; *(vuip)PYXIS_W3_BASE = 0x0 ; mb(); +#endif /* * check ASN in HWRPB for validity, report if bad @@ -510,3 +515,42 @@ } #endif } + +#if defined(CONFIG_ALPHA_RUFFIAN) +/* Note: This is only used by MILO, AFAIK... */ +/* + * The DeskStation Ruffian motherboard firmware does not place + * the memory size in the PALimpure area. Therefore, we use + * the Bank Configuration Registers in PYXIS to obtain the size. + */ +unsigned long pyxis_get_bank_size(unsigned long offset) +{ + unsigned long bank_addr, bank, ret = 0; + + /* Valid offsets are: 0x800, 0x840 and 0x880 + since Ruffian only uses three banks. */ + bank_addr = (unsigned long)PYXIS_MCR + offset; + bank = *(vulp)bank_addr; + + /* Check BANK_ENABLE */ + if (bank & 0x01) { + static unsigned long size[] = { + 0x40000000UL, /* 0x00, 1G */ + 0x20000000UL, /* 0x02, 512M */ + 0x10000000UL, /* 0x04, 256M */ + 0x08000000UL, /* 0x06, 128M */ + 0x04000000UL, /* 0x08, 64M */ + 0x02000000UL, /* 0x0a, 32M */ + 0x01000000UL, /* 0x0c, 16M */ + 0x00800000UL, /* 0x0e, 8M */ + 0x80000000UL, /* 0x10, 2G */ + }; + + bank = (bank & 0x1e) >> 1; + if (bank < sizeof(size)/sizeof(*size)) + ret = size[bank]; + } + + return ret; +} +#endif /* CONFIG_ALPHA_RUFFIAN */ diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.1.88/linux/arch/alpha/kernel/setup.c Mon Jan 12 14:51:14 1998 +++ linux/arch/alpha/kernel/setup.c Mon Feb 23 10:25:10 1998 @@ -107,11 +107,13 @@ outb(LATCH >> 8, 0x40); /* MSB */ request_region(0x40, 0x20, "timer"); /* reserve pit */ #else +#ifndef CONFIG_ALPHA_RUFFIAN outb(0x36, 0x43); /* counter 0: system timer */ outb(0x00, 0x40); outb(0x00, 0x40); - request_region(0x70, 0x10, "timer"); /* reserve rtc */ #endif + request_region(0x70, 0x10, "timer"); /* reserve rtc */ +#endif /* RTC */ outb(0xb6, 0x43); /* counter 2: speaker */ outb(0x31, 0x42); @@ -186,38 +188,115 @@ #endif } + +#define N(a) (sizeof(a)/sizeof(a[0])) + + +static void +get_sysnames(long type, long variation, + char **type_name, char **variation_name) +{ + static char *sys_unknown = "Unknown"; + static char *systype_names[] = { + "0", + "ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen", + "Pelican", "Morgan", "Sable", "Medulla", "Noname", + "Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind", + "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", + "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", + "Cortex", "29", "Miata", "XXM", "Takara", "Yukon", + "Tsunami", "Wildfire", "CUSCO" + }; + + static char *unofficial_names[] = {"100", "Ruffian"}; + + static char * eb164_names[] = {"EB164", "PC164", "LX164", "SX164"}; + static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3}; + + static char * alcor_names[] = {"Alcor", "Maverick", "Bret"}; + static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2}; + + static char * eb64p_names[] = {"EB64+", "Cabriolet", "AlphaPCI64"}; + static int eb64p_indices[] = {0,0,1.2}; + + static char * eb66_names[] = {"EB66", "EB66+"}; + static int eb66_indices[] = {0,0,1}; + + long member; + + /* Restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */ + if (type < 0) + type = -type; + + /* If not in the tables, make it UNKNOWN, + else set type name to family */ + if (type < N(systype_names)) { + *type_name = systype_names[type]; + } else if ((type > ST_UNOFFICIAL_BIAS) && + (type - ST_UNOFFICIAL_BIAS) < N(unofficial_names)) { + *type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS]; + } else { + *type_name = sys_unknown; + *variation_name = sys_unknown; + return; + } + + /* Set variation to "0"; if variation is zero, done */ + *variation_name = systype_names[0]; + if (variation == 0) { + return; + } + + member = (variation >> 10) & 0x3f; /* member ID is a bit-field */ + + switch (type) { + case ST_DEC_EB164: + if (member < N(eb164_indices)) + *variation_name = eb164_names[eb164_indices[member]]; + break; + case ST_DEC_ALCOR: + if (member < N(alcor_indices)) + *variation_name = alcor_names[alcor_indices[member]]; + break; + case ST_DEC_EB64P: + if (member < N(eb64p_indices)) + *variation_name = eb64p_names[eb64p_indices[member]]; + break; + case ST_DEC_EB66: + if (member < N(eb66_indices)) + *variation_name = eb66_names[eb66_indices[member]]; + break; + } +} + /* * BUFFER is PAGE_SIZE bytes long. */ int get_cpuinfo(char *buffer) { - const char *cpu_name[] = { - "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45", "EV56", - "EV6", "PCA56" + static char *cpu_names[] = { + "EV3", "EV4", "Unknown", "LCA4", "EV5", "EV45", "EV56", + "EV6", "PCA56", "PCA57" }; -# define SYSTYPE_NAME_BIAS 20 - const char *systype_name[] = { - "Cabriolet", "EB66P", "-18", "-17", "-16", "-15", - "-14", "-13", "-12", "-11", "-10", "-9", "-8", - "-7", "-6", "-5", "-4", "-3", "-2", "-1", "0", - "ADU", "Cobra", "Ruby", "Flamingo", "5", "Jensen", - "Pelican", "8", "Sable", "AXPvme", "Noname", - "Turbolaser", "Avanti", "Mustang", "Alcor", "16", - "Mikasa", "18", "EB66", "EB64+", "AlphaBook1", - "Rawhide", "Lego", "Lynx", "25", "EB164", "Noritake", - "Cortex", "29", "Miata", "31", "Takara", "Yukon" - }; - struct percpu_struct *cpu; - unsigned int cpu_index; - long sysname_index; + extern struct unaligned_stat { unsigned long count, va, pc; } unaligned[2]; -# define N(a) (sizeof(a)/sizeof(a[0])) + + struct percpu_struct *cpu; + unsigned int cpu_index; + char *cpu_name; + char *systype_name; + char *sysvariation_name; cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); cpu_index = (unsigned) (cpu->type - 1); - sysname_index = hwrpb->sys_type + SYSTYPE_NAME_BIAS; + cpu_name = "Unknown"; + if (cpu_index < N(cpu_names)) + cpu_name = cpu_names[cpu_index]; + + get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, + &systype_name, &sysvariation_name); return sprintf(buffer, "cpu\t\t\t: Alpha\n" @@ -226,7 +305,7 @@ "cpu revision\t\t: %ld\n" "cpu serial number\t: %s\n" "system type\t\t: %s\n" - "system variation\t: %ld\n" + "system variation\t: %s\n" "system revision\t\t: %ld\n" "system serial number\t: %s\n" "cycle frequency [Hz]\t: %lu\n" @@ -238,12 +317,9 @@ "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n", - (cpu_index < N(cpu_name) - ? cpu_name[cpu_index] : "Unknown"), - cpu->variation, cpu->revision, (char*)cpu->serial_no, - (sysname_index < N(systype_name) - ? systype_name[sysname_index] : "Unknown"), - hwrpb->sys_variation, hwrpb->sys_revision, + cpu_name, cpu->variation, cpu->revision, + (char*)cpu->serial_no, + systype_name, sysvariation_name, hwrpb->sys_revision, (char*)hwrpb->ssn, hwrpb->cycle_freq, hwrpb->intr_freq / 4096, @@ -254,5 +330,4 @@ loops_per_sec / 500000, (loops_per_sec / 5000) % 100, unaligned[0].count, unaligned[0].pc, unaligned[0].va, unaligned[1].count, unaligned[1].pc, unaligned[1].va); -# undef N } diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/smc37c669.c linux/arch/alpha/kernel/smc37c669.c --- v2.1.88/linux/arch/alpha/kernel/smc37c669.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/smc37c669.c Mon Feb 23 10:25:10 1998 @@ -0,0 +1,2584 @@ +/* + * SMC 37C669 initialization code + */ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +#define SMC_DEBUG 0 + +/* File: smcc669_def.h + * + * Copyright (C) 1997 by + * Digital Equipment Corporation, Maynard, Massachusetts. + * All rights reserved. + * + * This software is furnished under a license and may be used and copied + * only in accordance of the terms of such license and with the + * inclusion of the above copyright notice. This software or any other + * copies thereof may not be provided or otherwise made available to any + * other person. No title to and ownership of the software is hereby + * transferred. + * + * The information in this software is subject to change without notice + * and should not be construed as a commitment by Digital Equipment + * Corporation. + * + * Digital assumes no responsibility for the use or reliability of its + * software on equipment which is not supplied by Digital. + * + * + * Abstract: + * + * This file contains header definitions for the SMC37c669 + * Super I/O controller. + * + * Author: + * + * Eric Rasmussen + * + * Modification History: + * + * er 28-Jan-1997 Initial Entry + */ + +#ifndef __SMC37c669_H +#define __SMC37c669_H + +/* +** Macros for handling device IRQs +** +** The mask acts as a flag used in mapping actual ISA IRQs (0 - 15) +** to device IRQs (A - H). +*/ +#define SMC37c669_DEVICE_IRQ_MASK 0x80000000 +#define SMC37c669_DEVICE_IRQ( __i ) \ + ((SMC37c669_DEVICE_IRQ_MASK) | (__i)) +#define SMC37c669_IS_DEVICE_IRQ(__i) \ + (((__i) & (SMC37c669_DEVICE_IRQ_MASK)) == (SMC37c669_DEVICE_IRQ_MASK)) +#define SMC37c669_RAW_DEVICE_IRQ(__i) \ + ((__i) & ~(SMC37c669_DEVICE_IRQ_MASK)) + +/* +** Macros for handling device DRQs +** +** The mask acts as a flag used in mapping actual ISA DMA +** channels to device DMA channels (A - C). +*/ +#define SMC37c669_DEVICE_DRQ_MASK 0x80000000 +#define SMC37c669_DEVICE_DRQ(__d) \ + ((SMC37c669_DEVICE_DRQ_MASK) | (__d)) +#define SMC37c669_IS_DEVICE_DRQ(__d) \ + (((__d) & (SMC37c669_DEVICE_DRQ_MASK)) == (SMC37c669_DEVICE_DRQ_MASK)) +#define SMC37c669_RAW_DEVICE_DRQ(__d) \ + ((__d) & ~(SMC37c669_DEVICE_DRQ_MASK)) + +#define SMC37c669_DEVICE_ID 0x3 + +/* +** SMC37c669 Device Function Definitions +*/ +#define SERIAL_0 0 +#define SERIAL_1 1 +#define PARALLEL_0 2 +#define FLOPPY_0 3 +#define IDE_0 4 +#define NUM_FUNCS 5 + +/* +** Default Device Function Mappings +*/ +#define COM1_BASE 0x3F8 +#define COM1_IRQ 4 +#define COM2_BASE 0x2F8 +#define COM2_IRQ 3 +#define PARP_BASE 0x3BC +#define PARP_IRQ 7 +#define PARP_DRQ 3 +#define FDC_BASE 0x3F0 +#define FDC_IRQ 6 +#define FDC_DRQ 2 + +/* +** Configuration On/Off Key Definitions +*/ +#define SMC37c669_CONFIG_ON_KEY 0x55 +#define SMC37c669_CONFIG_OFF_KEY 0xAA + +/* +** SMC 37c669 Device IRQs +*/ +#define SMC37c669_DEVICE_IRQ_A ( SMC37c669_DEVICE_IRQ( 0x01 ) ) +#define SMC37c669_DEVICE_IRQ_B ( SMC37c669_DEVICE_IRQ( 0x02 ) ) +#define SMC37c669_DEVICE_IRQ_C ( SMC37c669_DEVICE_IRQ( 0x03 ) ) +#define SMC37c669_DEVICE_IRQ_D ( SMC37c669_DEVICE_IRQ( 0x04 ) ) +#define SMC37c669_DEVICE_IRQ_E ( SMC37c669_DEVICE_IRQ( 0x05 ) ) +#define SMC37c669_DEVICE_IRQ_F ( SMC37c669_DEVICE_IRQ( 0x06 ) ) +/* SMC37c669_DEVICE_IRQ_G *** RESERVED ***/ +#define SMC37c669_DEVICE_IRQ_H ( SMC37c669_DEVICE_IRQ( 0x08 ) ) + +/* +** SMC 37c669 Device DMA Channel Definitions +*/ +#define SMC37c669_DEVICE_DRQ_A ( SMC37c669_DEVICE_DRQ( 0x01 ) ) +#define SMC37c669_DEVICE_DRQ_B ( SMC37c669_DEVICE_DRQ( 0x02 ) ) +#define SMC37c669_DEVICE_DRQ_C ( SMC37c669_DEVICE_DRQ( 0x03 ) ) + +/* +** Configuration Register Index Definitions +*/ +#define SMC37c669_CR00_INDEX 0x00 +#define SMC37c669_CR01_INDEX 0x01 +#define SMC37c669_CR02_INDEX 0x02 +#define SMC37c669_CR03_INDEX 0x03 +#define SMC37c669_CR04_INDEX 0x04 +#define SMC37c669_CR05_INDEX 0x05 +#define SMC37c669_CR06_INDEX 0x06 +#define SMC37c669_CR07_INDEX 0x07 +#define SMC37c669_CR08_INDEX 0x08 +#define SMC37c669_CR09_INDEX 0x09 +#define SMC37c669_CR0A_INDEX 0x0A +#define SMC37c669_CR0B_INDEX 0x0B +#define SMC37c669_CR0C_INDEX 0x0C +#define SMC37c669_CR0D_INDEX 0x0D +#define SMC37c669_CR0E_INDEX 0x0E +#define SMC37c669_CR0F_INDEX 0x0F +#define SMC37c669_CR10_INDEX 0x10 +#define SMC37c669_CR11_INDEX 0x11 +#define SMC37c669_CR12_INDEX 0x12 +#define SMC37c669_CR13_INDEX 0x13 +#define SMC37c669_CR14_INDEX 0x14 +#define SMC37c669_CR15_INDEX 0x15 +#define SMC37c669_CR16_INDEX 0x16 +#define SMC37c669_CR17_INDEX 0x17 +#define SMC37c669_CR18_INDEX 0x18 +#define SMC37c669_CR19_INDEX 0x19 +#define SMC37c669_CR1A_INDEX 0x1A +#define SMC37c669_CR1B_INDEX 0x1B +#define SMC37c669_CR1C_INDEX 0x1C +#define SMC37c669_CR1D_INDEX 0x1D +#define SMC37c669_CR1E_INDEX 0x1E +#define SMC37c669_CR1F_INDEX 0x1F +#define SMC37c669_CR20_INDEX 0x20 +#define SMC37c669_CR21_INDEX 0x21 +#define SMC37c669_CR22_INDEX 0x22 +#define SMC37c669_CR23_INDEX 0x23 +#define SMC37c669_CR24_INDEX 0x24 +#define SMC37c669_CR25_INDEX 0x25 +#define SMC37c669_CR26_INDEX 0x26 +#define SMC37c669_CR27_INDEX 0x27 +#define SMC37c669_CR28_INDEX 0x28 +#define SMC37c669_CR29_INDEX 0x29 + +/* +** Configuration Register Alias Definitions +*/ +#define SMC37c669_DEVICE_ID_INDEX SMC37c669_CR0D_INDEX +#define SMC37c669_DEVICE_REVISION_INDEX SMC37c669_CR0E_INDEX +#define SMC37c669_FDC_BASE_ADDRESS_INDEX SMC37c669_CR20_INDEX +#define SMC37c669_IDE_BASE_ADDRESS_INDEX SMC37c669_CR21_INDEX +#define SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX SMC37c669_CR22_INDEX +#define SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX SMC37c669_CR23_INDEX +#define SMC37c669_SERIAL0_BASE_ADDRESS_INDEX SMC37c669_CR24_INDEX +#define SMC37c669_SERIAL1_BASE_ADDRESS_INDEX SMC37c669_CR25_INDEX +#define SMC37c669_PARALLEL_FDC_DRQ_INDEX SMC37c669_CR26_INDEX +#define SMC37c669_PARALLEL_FDC_IRQ_INDEX SMC37c669_CR27_INDEX +#define SMC37c669_SERIAL_IRQ_INDEX SMC37c669_CR28_INDEX + +/* +** Configuration Register Definitions +** +** The INDEX (write only) and DATA (read/write) ports are effective +** only when the chip is in the Configuration State. +*/ +typedef struct _SMC37c669_CONFIG_REGS { + unsigned char index_port; + unsigned char data_port; +} SMC37c669_CONFIG_REGS; + +/* +** CR00 - default value 0x28 +** +** IDE_EN (CR00<1:0>): +** 0x - 30ua pull-ups on nIDEEN, nHDCS0, NHDCS1 +** 11 - IRQ_H available as IRQ output, +** IRRX2, IRTX2 available as alternate IR pins +** 10 - nIDEEN, nHDCS0, nHDCS1 used to control IDE +** +** VALID (CR00<7>): +** A high level on this software controlled bit can +** be used to indicate that a valid configuration +** cycle has occurred. The control software must +** take care to set this bit at the appropriate times. +** Set to zero after power up. This bit has no +** effect on any other hardware in the chip. +** +*/ +typedef union _SMC37c669_CR00 { + unsigned char as_uchar; + struct { + unsigned ide_en : 2; /* See note above */ + unsigned reserved1 : 1; /* RAZ */ + unsigned fdc_pwr : 1; /* 1 = supply power to FDC */ + unsigned reserved2 : 3; /* Read as 010b */ + unsigned valid : 1; /* See note above */ + } by_field; +} SMC37c669_CR00; + +/* +** CR01 - default value 0x9C +*/ +typedef union _SMC37c669_CR01 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 2; /* RAZ */ + unsigned ppt_pwr : 1; /* 1 = supply power to PPT */ + unsigned ppt_mode : 1; /* 1 = Printer mode, 0 = EPP */ + unsigned reserved2 : 1; /* Read as 1 */ + unsigned reserved3 : 2; /* RAZ */ + unsigned lock_crx: 1; /* Lock CR00 - CR18 */ + } by_field; +} SMC37c669_CR01; + +/* +** CR02 - default value 0x88 +*/ +typedef union _SMC37c669_CR02 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 3; /* RAZ */ + unsigned uart1_pwr : 1; /* 1 = supply power to UART1 */ + unsigned reserved2 : 3; /* RAZ */ + unsigned uart2_pwr : 1; /* 1 = supply power to UART2 */ + } by_field; +} SMC37c669_CR02; + +/* +** CR03 - default value 0x78 +** +** CR03<7> CR03<2> Pin 94 +** ------- ------- ------ +** 0 X DRV2 (input) +** 1 0 ADRX +** 1 1 IRQ_B +** +** CR03<6> CR03<5> Op Mode +** ------- ------- ------- +** 0 0 Model 30 +** 0 1 PS/2 +** 1 0 Reserved +** 1 1 AT Mode +*/ +typedef union _SMC37c669_CR03 { + unsigned char as_uchar; + struct { + unsigned pwrgd_gamecs : 1; /* 1 = PWRGD, 0 = GAMECS */ + unsigned fdc_mode2 : 1; /* 1 = Enhanced Mode 2 */ + unsigned pin94_0 : 1; /* See note above */ + unsigned reserved1 : 1; /* RAZ */ + unsigned drvden : 1; /* 1 = high, 0 - output */ + unsigned op_mode : 2; /* See note above */ + unsigned pin94_1 : 1; /* See note above */ + } by_field; +} SMC37c669_CR03; + +/* +** CR04 - default value 0x00 +** +** PP_EXT_MODE: +** If CR01 = 0 and PP_EXT_MODE = +** 00 - Standard and Bidirectional +** 01 - EPP mode and SPP +** 10 - ECP mode +** In this mode, 2 drives can be supported +** directly, 3 or 4 drives must use external +** 4 drive support. SPP can be selected +** through the ECR register of ECP as mode 000. +** 11 - ECP mode and EPP mode +** In this mode, 2 drives can be supported +** directly, 3 or 4 drives must use external +** 4 drive support. SPP can be selected +** through the ECR register of ECP as mode 000. +** In this mode, EPP can be selected through +** the ECR register of ECP as mode 100. +** +** PP_FDC: +** 00 - Normal +** 01 - PPFD1 +** 10 - PPFD2 +** 11 - Reserved +** +** MIDI1: +** Serial Clock Select: +** A low level on this bit disables MIDI support, +** clock = divide by 13. A high level on this +** bit enables MIDI support, clock = divide by 12. +** +** MIDI operates at 31.25 Kbps which can be derived +** from 125 KHz (24 MHz / 12 = 2 MHz, 2 MHz / 16 = 125 KHz) +** +** ALT_IO: +** 0 - Use pins IRRX, IRTX +** 1 - Use pins IRRX2, IRTX2 +** +** If this bit is set, the IR receive and transmit +** functions will not be available on pins 25 and 26 +** unless CR00 = 11. +*/ +typedef union _SMC37c669_CR04 { + unsigned char as_uchar; + struct { + unsigned ppt_ext_mode : 2; /* See note above */ + unsigned ppt_fdc : 2; /* See note above */ + unsigned midi1 : 1; /* See note above */ + unsigned midi2 : 1; /* See note above */ + unsigned epp_type : 1; /* 0 = EPP 1.9, 1 = EPP 1.7 */ + unsigned alt_io : 1; /* See note above */ + } by_field; +} SMC37c669_CR04; + +/* +** CR05 - default value 0x00 +** +** DEN_SEL: +** 00 - Densel output normal +** 01 - Reserved +** 10 - Densel output 1 +** 11 - Densel output 0 +** +*/ +typedef union _SMC37c669_CR05 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 2; /* RAZ */ + unsigned fdc_dma_mode : 1; /* 0 = burst, 1 = non-burst */ + unsigned den_sel : 2; /* See note above */ + unsigned swap_drv : 1; /* Swap the FDC motor selects */ + unsigned extx4 : 1; /* 0 = 2 drive, 1 = external 4 drive decode */ + unsigned reserved2 : 1; /* RAZ */ + } by_field; +} SMC37c669_CR05; + +/* +** CR06 - default value 0xFF +*/ +typedef union _SMC37c669_CR06 { + unsigned char as_uchar; + struct { + unsigned floppy_a : 2; /* Type of floppy drive A */ + unsigned floppy_b : 2; /* Type of floppy drive B */ + unsigned floppy_c : 2; /* Type of floppy drive C */ + unsigned floppy_d : 2; /* Type of floppy drive D */ + } by_field; +} SMC37c669_CR06; + +/* +** CR07 - default value 0x00 +** +** Auto Power Management CR07<7:4>: +** 0 - Auto Powerdown disabled (default) +** 1 - Auto Powerdown enabled +** +** This bit is reset to the default state by POR or +** a hardware reset. +** +*/ +typedef union _SMC37c669_CR07 { + unsigned char as_uchar; + struct { + unsigned floppy_boot : 2; /* 0 = A:, 1 = B: */ + unsigned reserved1 : 2; /* RAZ */ + unsigned ppt_en : 1; /* See note above */ + unsigned uart1_en : 1; /* See note above */ + unsigned uart2_en : 1; /* See note above */ + unsigned fdc_en : 1; /* See note above */ + } by_field; +} SMC37c669_CR07; + +/* +** CR08 - default value 0x00 +*/ +typedef union _SMC37c669_CR08 { + unsigned char as_uchar; + struct { + unsigned zero : 4; /* 0 */ + unsigned addrx7_4 : 4; /* ADR<7:3> for ADRx decode */ + } by_field; +} SMC37c669_CR08; + +/* +** CR09 - default value 0x00 +** +** ADRx_CONFIG: +** 00 - ADRx disabled +** 01 - 1 byte decode A<3:0> = 0000b +** 10 - 8 byte block decode A<3:0> = 0XXXb +** 11 - 16 byte block decode A<3:0> = XXXXb +** +*/ +typedef union _SMC37c669_CR09 { + unsigned char as_uchar; + struct { + unsigned adra8 : 3; /* ADR<10:8> for ADRx decode */ + unsigned reserved1 : 3; + unsigned adrx_config : 2; /* See note above */ + } by_field; +} SMC37c669_CR09; + +/* +** CR0A - default value 0x00 +*/ +typedef union _SMC37c669_CR0A { + unsigned char as_uchar; + struct { + unsigned ecp_fifo_threshold : 4; + unsigned reserved1 : 4; + } by_field; +} SMC37c669_CR0A; + +/* +** CR0B - default value 0x00 +*/ +typedef union _SMC37c669_CR0B { + unsigned char as_uchar; + struct { + unsigned fdd0_drtx : 2; /* FDD0 Data Rate Table */ + unsigned fdd1_drtx : 2; /* FDD1 Data Rate Table */ + unsigned fdd2_drtx : 2; /* FDD2 Data Rate Table */ + unsigned fdd3_drtx : 2; /* FDD3 Data Rate Table */ + } by_field; +} SMC37c669_CR0B; + +/* +** CR0C - default value 0x00 +** +** UART2_MODE: +** 000 - Standard (default) +** 001 - IrDA (HPSIR) +** 010 - Amplitude Shift Keyed IR @500 KHz +** 011 - Reserved +** 1xx - Reserved +** +*/ +typedef union _SMC37c669_CR0C { + unsigned char as_uchar; + struct { + unsigned uart2_rcv_polarity : 1; /* 1 = invert RX */ + unsigned uart2_xmit_polarity : 1; /* 1 = invert TX */ + unsigned uart2_duplex : 1; /* 1 = full, 0 = half */ + unsigned uart2_mode : 3; /* See note above */ + unsigned uart1_speed : 1; /* 1 = high speed enabled */ + unsigned uart2_speed : 1; /* 1 = high speed enabled */ + } by_field; +} SMC37c669_CR0C; + +/* +** CR0D - default value 0x03 +** +** Device ID Register - read only +*/ +typedef union _SMC37c669_CR0D { + unsigned char as_uchar; + struct { + unsigned device_id : 8; /* Returns 0x3 in this field */ + } by_field; +} SMC37c669_CR0D; + +/* +** CR0E - default value 0x02 +** +** Device Revision Register - read only +*/ +typedef union _SMC37c669_CR0E { + unsigned char as_uchar; + struct { + unsigned device_rev : 8; /* Returns 0x2 in this field */ + } by_field; +} SMC37c669_CR0E; + +/* +** CR0F - default value 0x00 +*/ +typedef union _SMC37c669_CR0F { + unsigned char as_uchar; + struct { + unsigned test0 : 1; /* Reserved - set to 0 */ + unsigned test1 : 1; /* Reserved - set to 0 */ + unsigned test2 : 1; /* Reserved - set to 0 */ + unsigned test3 : 1; /* Reserved - set t0 0 */ + unsigned test4 : 1; /* Reserved - set to 0 */ + unsigned test5 : 1; /* Reserved - set t0 0 */ + unsigned test6 : 1; /* Reserved - set t0 0 */ + unsigned test7 : 1; /* Reserved - set to 0 */ + } by_field; +} SMC37c669_CR0F; + +/* +** CR10 - default value 0x00 +*/ +typedef union _SMC37c669_CR10 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 3; /* RAZ */ + unsigned pll_gain : 1; /* 1 = 3V, 2 = 5V operation */ + unsigned pll_stop : 1; /* 1 = stop PLLs */ + unsigned ace_stop : 1; /* 1 = stop UART clocks */ + unsigned pll_clock_ctrl : 1; /* 0 = 14.318 MHz, 1 = 24 MHz */ + unsigned ir_test : 1; /* Enable IR test mode */ + } by_field; +} SMC37c669_CR10; + +/* +** CR11 - default value 0x00 +*/ +typedef union _SMC37c669_CR11 { + unsigned char as_uchar; + struct { + unsigned ir_loopback : 1; /* Internal IR loop back */ + unsigned test_10ms : 1; /* Test 10ms autopowerdown FDC timeout */ + unsigned reserved1 : 6; /* RAZ */ + } by_field; +} SMC37c669_CR11; + +/* +** CR12 - CR1D are reserved registers +*/ + +/* +** CR1E - default value 0x80 +** +** GAMECS: +** 00 - GAMECS disabled +** 01 - 1 byte decode ADR<3:0> = 0001b +** 10 - 8 byte block decode ADR<3:0> = 0XXXb +** 11 - 16 byte block decode ADR<3:0> = XXXXb +** +*/ +typedef union _SMC37c66_CR1E { + unsigned char as_uchar; + struct { + unsigned gamecs_config: 2; /* See note above */ + unsigned gamecs_addr9_4 : 6; /* GAMECS Addr<9:4> */ + } by_field; +} SMC37c669_CR1E; + +/* +** CR1F - default value 0x00 +** +** DT0 DT1 DRVDEN0 DRVDEN1 Drive Type +** --- --- ------- ------- ---------- +** 0 0 DENSEL DRATE0 4/2/1 MB 3.5" +** 2/1 MB 5.25" +** 2/1.6/1 MB 3.5" (3-mode) +** 0 1 DRATE1 DRATE0 +** 1 0 nDENSEL DRATE0 PS/2 +** 1 1 DRATE0 DRATE1 +** +** Note: DENSEL, DRATE1, and DRATE0 map onto two output +** pins - DRVDEN0 and DRVDEN1. +** +*/ +typedef union _SMC37c669_CR1F { + unsigned char as_uchar; + struct { + unsigned fdd0_drive_type : 2; /* FDD0 drive type */ + unsigned fdd1_drive_type : 2; /* FDD1 drive type */ + unsigned fdd2_drive_type : 2; /* FDD2 drive type */ + unsigned fdd3_drive_type : 2; /* FDD3 drive type */ + } by_field; +} SMC37c669_CR1F; + +/* +** CR20 - default value 0x3C +** +** FDC Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<3:0> = 0XXXb to access. +** +*/ +typedef union _SMC37c669_CR20 { + unsigned char as_uchar; + struct { + unsigned zero : 2; /* 0 */ + unsigned addr9_4 : 6; /* FDC Addr<9:4> */ + } by_field; +} SMC37c669_CR20; + +/* +** CR21 - default value 0x3C +** +** IDE Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<3:0> = 0XXXb to access. +** +*/ +typedef union _SMC37c669_CR21 { + unsigned char as_uchar; + struct { + unsigned zero : 2; /* 0 */ + unsigned addr9_4 : 6; /* IDE Addr<9:4> */ + } by_field; +} SMC37c669_CR21; + +/* +** CR22 - default value 0x3D +** +** IDE Alternate Status Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<3:0> = 0110b to access. +** +*/ +typedef union _SMC37c669_CR22 { + unsigned char as_uchar; + struct { + unsigned zero : 2; /* 0 */ + unsigned addr9_4 : 6; /* IDE Alt Status Addr<9:4> */ + } by_field; +} SMC37c669_CR22; + +/* +** CR23 - default value 0x00 +** +** Parallel Port Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0 to access. +** - If EPP is enabled, A<2:0> = XXXb to access. +** If EPP is NOT enabled, A<1:0> = XXb to access +** +*/ +typedef union _SMC37c669_CR23 { + unsigned char as_uchar; + struct { + unsigned addr9_2 : 8; /* Parallel Port Addr<9:2> */ + } by_field; +} SMC37c669_CR23; + +/* +** CR24 - default value 0x00 +** +** UART1 Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<2:0> = XXXb to access. +** +*/ +typedef union _SMC37c669_CR24 { + unsigned char as_uchar; + struct { + unsigned zero : 1; /* 0 */ + unsigned addr9_3 : 7; /* UART1 Addr<9:3> */ + } by_field; +} SMC37c669_CR24; + +/* +** CR25 - default value 0x00 +** +** UART2 Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<2:0> = XXXb to access. +** +*/ +typedef union _SMC37c669_CR25 { + unsigned char as_uchar; + struct { + unsigned zero : 1; /* 0 */ + unsigned addr9_3 : 7; /* UART2 Addr<9:3> */ + } by_field; +} SMC37c669_CR25; + +/* +** CR26 - default value 0x00 +** +** Parallel Port / FDC DMA Select Register +** +** D3 - D0 DMA +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 DMA_A +** 0010 DMA_B +** 0011 DMA_C +** +*/ +typedef union _SMC37c669_CR26 { + unsigned char as_uchar; + struct { + unsigned ppt_drq : 4; /* See note above */ + unsigned fdc_drq : 4; /* See note above */ + } by_field; +} SMC37c669_CR26; + +/* +** CR27 - default value 0x00 +** +** Parallel Port / FDC IRQ Select Register +** +** D3 - D0 IRQ +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 IRQ_A +** 0010 IRQ_B +** 0011 IRQ_C +** 0100 IRQ_D +** 0101 IRQ_E +** 0110 IRQ_F +** 0111 Reserved +** 1000 IRQ_H +** +** Any unselected IRQ REQ is in tristate +** +*/ +typedef union _SMC37c669_CR27 { + unsigned char as_uchar; + struct { + unsigned ppt_irq : 4; /* See note above */ + unsigned fdc_irq : 4; /* See note above */ + } by_field; +} SMC37c669_CR27; + +/* +** CR28 - default value 0x00 +** +** UART IRQ Select Register +** +** D3 - D0 IRQ +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 IRQ_A +** 0010 IRQ_B +** 0011 IRQ_C +** 0100 IRQ_D +** 0101 IRQ_E +** 0110 IRQ_F +** 0111 Reserved +** 1000 IRQ_H +** 1111 share with UART1 (only for UART2) +** +** Any unselected IRQ REQ is in tristate +** +** To share an IRQ between UART1 and UART2, set +** UART1 to use the desired IRQ and set UART2 to +** 0xF to enable sharing mechanism. +** +*/ +typedef union _SMC37c669_CR28 { + unsigned char as_uchar; + struct { + unsigned uart2_irq : 4; /* See note above */ + unsigned uart1_irq : 4; /* See note above */ + } by_field; +} SMC37c669_CR28; + +/* +** CR29 - default value 0x00 +** +** IRQIN IRQ Select Register +** +** D3 - D0 IRQ +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 IRQ_A +** 0010 IRQ_B +** 0011 IRQ_C +** 0100 IRQ_D +** 0101 IRQ_E +** 0110 IRQ_F +** 0111 Reserved +** 1000 IRQ_H +** +** Any unselected IRQ REQ is in tristate +** +*/ +typedef union _SMC37c669_CR29 { + unsigned char as_uchar; + struct { + unsigned irqin_irq : 4; /* See note above */ + unsigned reserved1 : 4; /* RAZ */ + } by_field; +} SMC37c669_CR29; + +/* +** Aliases of Configuration Register formats (should match +** the set of index aliases). +** +** Note that CR24 and CR25 have the same format and are the +** base address registers for UART1 and UART2. Because of +** this we only define 1 alias here - for CR24 - as the serial +** base address register. +** +** Note that CR21 and CR22 have the same format and are the +** base address and alternate status address registers for +** the IDE controller. Because of this we only define 1 alias +** here - for CR21 - as the IDE address register. +** +*/ +typedef SMC37c669_CR0D SMC37c669_DEVICE_ID_REGISTER; +typedef SMC37c669_CR0E SMC37c669_DEVICE_REVISION_REGISTER; +typedef SMC37c669_CR20 SMC37c669_FDC_BASE_ADDRESS_REGISTER; +typedef SMC37c669_CR21 SMC37c669_IDE_ADDRESS_REGISTER; +typedef SMC37c669_CR23 SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER; +typedef SMC37c669_CR24 SMC37c669_SERIAL_BASE_ADDRESS_REGISTER; +typedef SMC37c669_CR26 SMC37c669_PARALLEL_FDC_DRQ_REGISTER; +typedef SMC37c669_CR27 SMC37c669_PARALLEL_FDC_IRQ_REGISTER; +typedef SMC37c669_CR28 SMC37c669_SERIAL_IRQ_REGISTER; + +/* +** ISA/Device IRQ Translation Table Entry Definition +*/ +typedef struct _SMC37c669_IRQ_TRANSLATION_ENTRY { + int device_irq; + int isa_irq; +} SMC37c669_IRQ_TRANSLATION_ENTRY; + +/* +** ISA/Device DMA Translation Table Entry Definition +*/ +typedef struct _SMC37c669_DRQ_TRANSLATION_ENTRY { + int device_drq; + int isa_drq; +} SMC37c669_DRQ_TRANSLATION_ENTRY; + +/* +** External Interface Function Prototype Declarations +*/ + +SMC37c669_CONFIG_REGS *SMC37c669_detect( + void +); + +unsigned int SMC37c669_enable_device( + unsigned int func +); + +unsigned int SMC37c669_disable_device( + unsigned int func +); + +unsigned int SMC37c669_configure_device( + unsigned int func, + int port, + int irq, + int drq +); + +void SMC37c669_display_device_info( + void +); + +#endif /* __SMC37c669_H */ + +/* file: smcc669.c + * + * Copyright (C) 1997 by + * Digital Equipment Corporation, Maynard, Massachusetts. + * All rights reserved. + * + * This software is furnished under a license and may be used and copied + * only in accordance of the terms of such license and with the + * inclusion of the above copyright notice. This software or any other + * copies thereof may not be provided or otherwise made available to any + * other person. No title to and ownership of the software is hereby + * transferred. + * + * The information in this software is subject to change without notice + * and should not be construed as a commitment by digital equipment + * corporation. + * + * Digital assumes no responsibility for the use or reliability of its + * software on equipment which is not supplied by digital. + */ + +/* + *++ + * FACILITY: + * + * Alpha SRM Console Firmware + * + * MODULE DESCRIPTION: + * + * SMC37c669 Super I/O controller configuration routines. + * + * AUTHORS: + * + * Eric Rasmussen + * + * CREATION DATE: + * + * 28-Jan-1997 + * + * MODIFICATION HISTORY: + * + * er 01-May-1997 Fixed pointer conversion errors in + * SMC37c669_get_device_config(). + * er 28-Jan-1997 Initial version. + * + *-- + */ +#if 0 +/* $INCLUDE_OPTIONS$ */ +#include "cp$inc:platform_io.h" +/* $INCLUDE_OPTIONS_END$ */ +#include "cp$src:common.h" +#include "cp$inc:prototypes.h" +#include "cp$src:kernel_def.h" +#include "cp$src:msg_def.h" +#include "cp$src:smcc669_def.h" +/* Platform-specific includes */ +#include "cp$src:platform.h" +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define wb( _x_, _y_ ) outb( _y_, (unsigned int)((unsigned long)_x_) ) +#define rb( _x_ ) inb( (unsigned int)((unsigned long)_x_) ) + +/* +** Local storage for device configuration information. +** +** Since the SMC37c669 does not provide an explicit +** mechanism for enabling/disabling individual device +** functions, other than unmapping the device, local +** storage for device configuration information is +** allocated here for use in implementing our own +** function enable/disable scheme. +*/ +static struct DEVICE_CONFIG { + unsigned int port1; + unsigned int port2; + unsigned int irq; + unsigned int drq; +} local_config [NUM_FUNCS]; + +/* +** List of all possible addresses for the Super I/O chip +*/ +static unsigned long SMC37c669_Addresses[] __initdata = + { + 0x3F0UL, /* Primary address */ + 0x370UL, /* Secondary address */ + 0UL /* End of list */ + }; + +/* +** Global Pointer to the Super I/O device +*/ +static SMC37c669_CONFIG_REGS *SMC37c669 __initdata = NULL; + +/* +** IRQ Translation Table +** +** The IRQ translation table is a list of SMC37c669 device +** and standard ISA IRQs. +** +*/ +static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata; + +/* +** The following definition is for the default IRQ +** translation table. +*/ +static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[] +__initdata = + { + { SMC37c669_DEVICE_IRQ_A, -1 }, + { SMC37c669_DEVICE_IRQ_B, -1 }, + { SMC37c669_DEVICE_IRQ_C, 7 }, + { SMC37c669_DEVICE_IRQ_D, 6 }, + { SMC37c669_DEVICE_IRQ_E, 4 }, + { SMC37c669_DEVICE_IRQ_F, 3 }, + { SMC37c669_DEVICE_IRQ_H, -1 }, + { -1, -1 } /* End of table */ + }; + +/* +** DRQ Translation Table +** +** The DRQ translation table is a list of SMC37c669 device and +** ISA DMA channels. +** +*/ +static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata; + +/* +** The following definition is the default DRQ +** translation table. +*/ +static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[] +__initdata = + { + { SMC37c669_DEVICE_DRQ_A, 2 }, + { SMC37c669_DEVICE_DRQ_B, 3 }, + { SMC37c669_DEVICE_DRQ_C, -1 }, + { -1, -1 } /* End of table */ + }; + +/* +** Local Function Prototype Declarations +*/ + +static unsigned int SMC37c669_is_device_enabled( + unsigned int func +); + +#if 0 +static unsigned int SMC37c669_get_device_config( + unsigned int func, + int *port, + int *irq, + int *drq +); +#endif + +static void SMC37c669_config_mode( + unsigned int enable +); + +static unsigned char SMC37c669_read_config( + unsigned char index +); + +static void SMC37c669_write_config( + unsigned char index, + unsigned char data +); + +static void SMC37c669_init_local_config( void ); + +static struct DEVICE_CONFIG *SMC37c669_get_config( + unsigned int func +); + +static int SMC37c669_xlate_irq( + unsigned int irq +); + +static int SMC37c669_xlate_drq( + unsigned int drq +); + +#if 0 +/* +** External Data Declarations +*/ + +extern struct LOCK spl_atomic; + +/* +** External Function Prototype Declarations +*/ + +/* From kernel_alpha.mar */ +extern spinlock( + struct LOCK *spl +); + +extern spinunlock( + struct LOCK *spl +); + +/* From filesys.c */ +int allocinode( + char *name, + int can_create, + struct INODE **ipp +); + +extern int null_procedure( void ); + +int smcc669_init( void ); +int smcc669_open( struct FILE *fp, char *info, char *next, char *mode ); +int smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf ); +int smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf ); +int smcc669_close( struct FILE *fp ); + +struct DDB smc_ddb = { + "smc", /* how this routine wants to be called */ + smcc669_read, /* read routine */ + smcc669_write, /* write routine */ + smcc669_open, /* open routine */ + smcc669_close, /* close routine */ + null_procedure, /* name expansion routine */ + null_procedure, /* delete routine */ + null_procedure, /* create routine */ + null_procedure, /* setmode */ + null_procedure, /* validation routine */ + 0, /* class specific use */ + 1, /* allows information */ + 0, /* must be stacked */ + 0, /* is a flash update driver */ + 0, /* is a block device */ + 0, /* not seekable */ + 0, /* is an ethernet device */ + 0, /* is a filesystem driver */ +}; +#endif + +#define spinlock(x) +#define spinunlock(x) + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function detects the presence of an SMC37c669 Super I/O +** controller. +** +** FORMAL PARAMETERS: +** +** None +** +** RETURN VALUE: +** +** Returns a pointer to the device if found, otherwise, +** the NULL pointer is returned. +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +SMC37c669_CONFIG_REGS * __init SMC37c669_detect( void ) +{ + int i; + SMC37c669_DEVICE_ID_REGISTER id; + + for ( i = 0; SMC37c669_Addresses[i] != 0; i++ ) { +/* +** Initialize the device pointer even though we don't yet know if +** the controller is at this address. The support functions access +** the controller through this device pointer so we need to set it +** even when we are looking ... +*/ + SMC37c669 = ( SMC37c669_CONFIG_REGS * )SMC37c669_Addresses[i]; +/* +** Enter configuration mode +*/ + SMC37c669_config_mode( TRUE ); +/* +** Read the device id +*/ + id.as_uchar = SMC37c669_read_config( SMC37c669_DEVICE_ID_INDEX ); +/* +** Exit configuration mode +*/ + SMC37c669_config_mode( FALSE ); +/* +** Does the device id match? If so, assume we have found an +** SMC37c669 controller at this address. +*/ + if ( id.by_field.device_id == SMC37c669_DEVICE_ID ) { +/* +** Initialize the IRQ and DRQ translation tables. +*/ + SMC37c669_irq_table = SMC37c669_default_irq_table; + SMC37c669_drq_table = SMC37c669_default_drq_table; +/* +** erfix +** +** If the platform can't use the IRQ and DRQ defaults set up in this +** file, it should call a platform-specific external routine at this +** point to reset the IRQ and DRQ translation table pointers to point +** at the appropriate tables for the platform. If the defaults are +** acceptable, then the external routine should do nothing. +*/ + +/* +** Put the chip back into configuration mode +*/ + SMC37c669_config_mode( TRUE ); +/* +** Initialize local storage for configuration information +*/ + SMC37c669_init_local_config( ); +/* +** Exit configuration mode +*/ + SMC37c669_config_mode( FALSE ); +/* +** SMC37c669 controller found, break out of search loop +*/ + break; + } + else { +/* +** Otherwise, we did not find an SMC37c669 controller at this +** address so set the device pointer to NULL. +*/ + SMC37c669 = NULL; + } + } + return SMC37c669; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function enables an SMC37c669 device function. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function to enable +** +** RETURN VALUE: +** +** Returns TRUE is the device function was enabled, otherwise, FALSE +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** Enabling a device function in the SMC37c669 controller involves +** setting all of its mappings (port, irq, drq ...). A local +** "shadow" copy of the device configuration is kept so we can +** just set each mapping to what the local copy says. +** +** This function ALWAYS updates the local shadow configuration of +** the device function being enabled, even if the device is always +** enabled. To avoid replication of code, functions such as +** configure_device set up the local copy and then call this +** function to the update the real device. +** +**-- +*/ +unsigned int __init SMC37c669_enable_device ( unsigned int func ) +{ + unsigned int ret_val = FALSE; +/* +** Put the device into configuration mode +*/ + SMC37c669_config_mode( TRUE ); + switch ( func ) { + case SERIAL_0: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Enable the serial 1 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart1_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Enable the serial 1 port base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3; + + SMC37c669_write_config( + SMC37c669_SERIAL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case SERIAL_1: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Enable the serial 2 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart2_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Enable the serial 2 port base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3; + + SMC37c669_write_config( + SMC37c669_SERIAL1_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case PARALLEL_0: + { + SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Enable the parallel port DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.ppt_drq = + SMC37c669_RAW_DEVICE_DRQ( + SMC37c669_xlate_drq( local_config[ func ].drq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Enable the parallel port IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.ppt_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Enable the parallel port base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_2 = local_config[ func ].port1 >> 2; + + SMC37c669_write_config( + SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case FLOPPY_0: + { + SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Enable the floppy controller DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.fdc_drq = + SMC37c669_RAW_DEVICE_DRQ( + SMC37c669_xlate_drq( local_config[ func ].drq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Enable the floppy controller IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.fdc_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Enable the floppy controller base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4; + + SMC37c669_write_config( + SMC37c669_FDC_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case IDE_0: + { + SMC37c669_IDE_ADDRESS_REGISTER ide_addr; +/* +** Enable the IDE alternate status base address mapping +*/ + ide_addr.as_uchar = 0; + ide_addr.by_field.addr9_4 = local_config[ func ].port2 >> 4; + + SMC37c669_write_config( + SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX, + ide_addr.as_uchar + ); +/* +** Enable the IDE controller base address mapping +*/ + ide_addr.as_uchar = 0; + ide_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4; + + SMC37c669_write_config( + SMC37c669_IDE_BASE_ADDRESS_INDEX, + ide_addr.as_uchar + ); + ret_val = TRUE; + break; + } + } +/* +** Exit configuration mode and return +*/ + SMC37c669_config_mode( FALSE ); + + return ret_val; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function disables a device function within the +** SMC37c669 Super I/O controller. +** +** FORMAL PARAMETERS: +** +** func: +** Which function to disable +** +** RETURN VALUE: +** +** Return TRUE if the device function was disabled, otherwise, FALSE +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** Disabling a function in the SMC37c669 device involves +** disabling all the function's mappings (port, irq, drq ...). +** A shadow copy of the device configuration is maintained +** in local storage so we won't worry aboving saving the +** current configuration information. +** +**-- +*/ +unsigned int __init SMC37c669_disable_device ( unsigned int func ) +{ + unsigned int ret_val = FALSE; + +/* +** Put the device into configuration mode +*/ + SMC37c669_config_mode( TRUE ); + switch ( func ) { + case SERIAL_0: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Disable the serial 1 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart1_irq = 0; + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Disable the serial 1 port base address mapping +*/ + base_addr.as_uchar = 0; + SMC37c669_write_config( + SMC37c669_SERIAL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case SERIAL_1: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Disable the serial 2 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart2_irq = 0; + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Disable the serial 2 port base address mapping +*/ + base_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_SERIAL1_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case PARALLEL_0: + { + SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Disable the parallel port DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.ppt_drq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Disable the parallel port IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.ppt_irq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Disable the parallel port base address mapping +*/ + base_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case FLOPPY_0: + { + SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Disable the floppy controller DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.fdc_drq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Disable the floppy controller IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.fdc_irq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Disable the floppy controller base address mapping +*/ + base_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_FDC_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case IDE_0: + { + SMC37c669_IDE_ADDRESS_REGISTER ide_addr; +/* +** Disable the IDE alternate status base address mapping +*/ + ide_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX, + ide_addr.as_uchar + ); +/* +** Disable the IDE controller base address mapping +*/ + ide_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_IDE_BASE_ADDRESS_INDEX, + ide_addr.as_uchar + ); + ret_val = TRUE; + break; + } + } +/* +** Exit configuration mode and return +*/ + SMC37c669_config_mode( FALSE ); + + return ret_val; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function configures a device function within the +** SMC37c669 Super I/O controller. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** port: +** I/O port for the function to use +** +** irq: +** IRQ for the device function to use +** +** drq: +** DMA channel for the device function to use +** +** RETURN VALUE: +** +** Returns TRUE if the device function was configured, +** otherwise, FALSE. +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** If this function returns TRUE, the local shadow copy of +** the configuration is also updated. If the device function +** is currently disabled, only the local shadow copy is +** updated and the actual device function will be updated +** if/when is is enabled. +** +**-- +*/ +unsigned int __init SMC37c669_configure_device ( + unsigned int func, + int port, + int irq, + int drq ) +{ + struct DEVICE_CONFIG *cp; + +/* +** Check for a valid configuration +*/ + if ( ( cp = SMC37c669_get_config ( func ) ) != NULL ) { +/* +** Configuration is valid, update the local shadow copy +*/ + if ( ( drq & ~0xFF ) == 0 ) { + cp->drq = drq; + } + if ( ( irq & ~0xFF ) == 0 ) { + cp->irq = irq; + } + if ( ( port & ~0xFFFF ) == 0 ) { + cp->port1 = port; + } +/* +** If the device function is enabled, update the actual +** device configuration. +*/ + if ( SMC37c669_is_device_enabled( func ) ) { + SMC37c669_enable_device( func ); + } + return TRUE; + } + return FALSE; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function determines whether a device function +** within the SMC37c669 controller is enabled. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** RETURN VALUE: +** +** Returns TRUE if the device function is enabled, otherwise, FALSE +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** To check whether a device is enabled we will only look at +** the port base address mapping. According to the SMC37c669 +** specification, all of the port base address mappings are +** disabled if the addr<9:8> (bits <7:6> of the register) are +** zero. +** +**-- +*/ +static unsigned int __init SMC37c669_is_device_enabled ( unsigned int func ) +{ + unsigned char base_addr = 0; + unsigned int dev_ok = FALSE; + unsigned int ret_val = FALSE; +/* +** Enter configuration mode +*/ + SMC37c669_config_mode( TRUE ); + + switch ( func ) { + case SERIAL_0: + base_addr = + SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case SERIAL_1: + base_addr = + SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case PARALLEL_0: + base_addr = + SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case FLOPPY_0: + base_addr = + SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case IDE_0: + base_addr = + SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + } +/* +** If we have a valid device, check base_addr<7:6> to see if the +** device is enabled (mapped). +*/ + if ( ( dev_ok ) && ( ( base_addr & 0xC0 ) != 0 ) ) { +/* +** The mapping is not disabled, so assume that the function is +** enabled. +*/ + ret_val = TRUE; + } +/* +** Exit configuration mode +*/ + SMC37c669_config_mode( FALSE ); + + return ret_val; +} + + +#if 0 +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function retrieves the configuration information of a +** device function within the SMC37c699 Super I/O controller. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** port: +** I/O port returned +** +** irq: +** IRQ returned +** +** drq: +** DMA channel returned +** +** RETURN VALUE: +** +** Returns TRUE if the device configuration was successfully +** retrieved, otherwise, FALSE. +** +** SIDE EFFECTS: +** +** The data pointed to by the port, irq, and drq parameters +** my be modified even if the configuration is not successfully +** retrieved. +** +** DESIGN: +** +** The device configuration is fetched from the local shadow +** copy. Any unused parameters will be set to -1. Any +** parameter which is not desired can specify the NULL +** pointer. +** +**-- +*/ +static unsigned int __init SMC37c669_get_device_config ( + unsigned int func, + int *port, + int *irq, + int *drq ) +{ + struct DEVICE_CONFIG *cp; + unsigned int ret_val = FALSE; +/* +** Check for a valid device configuration +*/ + if ( ( cp = SMC37c669_get_config( func ) ) != NULL ) { + if ( drq != NULL ) { + *drq = cp->drq; + ret_val = TRUE; + } + if ( irq != NULL ) { + *irq = cp->irq; + ret_val = TRUE; + } + if ( port != NULL ) { + *port = cp->port1; + ret_val = TRUE; + } + } + return ret_val; +} +#endif + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function displays the current state of the SMC37c699 +** Super I/O controller's device functions. +** +** FORMAL PARAMETERS: +** +** None +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +void __init SMC37c669_display_device_info ( void ) +{ + if ( SMC37c669_is_device_enabled( SERIAL_0 ) ) { + printk( " Serial 0: Enabled [ Port 0x%x, IRQ %d ]\n", + local_config[ SERIAL_0 ].port1, + local_config[ SERIAL_0 ].irq + ); + } + else { + printk( " Serial 0: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( SERIAL_1 ) ) { + printk( " Serial 1: Enabled [ Port 0x%x, IRQ %d ]\n", + local_config[ SERIAL_1 ].port1, + local_config[ SERIAL_1 ].irq + ); + } + else { + printk( " Serial 1: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( PARALLEL_0 ) ) { + printk( " Parallel: Enabled [ Port 0x%x, IRQ %d/%d ]\n", + local_config[ PARALLEL_0 ].port1, + local_config[ PARALLEL_0 ].irq, + local_config[ PARALLEL_0 ].drq + ); + } + else { + printk( " Parallel: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( FLOPPY_0 ) ) { + printk( " Floppy Ctrl: Enabled [ Port 0x%x, IRQ %d/%d ]\n", + local_config[ FLOPPY_0 ].port1, + local_config[ FLOPPY_0 ].irq, + local_config[ FLOPPY_0 ].drq + ); + } + else { + printk( " Floppy Ctrl: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( IDE_0 ) ) { + printk( " IDE 0: Enabled [ Port 0x%x, IRQ %d ]\n", + local_config[ IDE_0 ].port1, + local_config[ IDE_0 ].irq + ); + } + else { + printk( " IDE 0: Disabled\n" ); + } +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function puts the SMC37c669 Super I/O controller into, +** and takes it out of, configuration mode. +** +** FORMAL PARAMETERS: +** +** enable: +** TRUE to enter configuration mode, FALSE to exit. +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** The SMC37c669 controller may be left in configuration mode. +** +**-- +*/ +static void __init SMC37c669_config_mode( + unsigned int enable ) +{ + if ( enable ) { +/* +** To enter configuration mode, two writes in succession to the index +** port are required. If a write to another address or port occurs +** between these two writes, the chip does not enter configuration +** mode. Therefore, a spinlock is placed around the two writes to +** guarantee that they complete uninterrupted. +*/ + spinlock( &spl_atomic ); + wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY ); + wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY ); + spinunlock( &spl_atomic ); + } + else { + wb( &SMC37c669->index_port, SMC37c669_CONFIG_OFF_KEY ); + } +} + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function reads an SMC37c669 Super I/O controller +** configuration register. This function assumes that the +** device is already in configuration mode. +** +** FORMAL PARAMETERS: +** +** index: +** Index value of configuration register to read +** +** RETURN VALUE: +** +** Data read from configuration register +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +static unsigned char __init SMC37c669_read_config( + unsigned char index ) +{ + unsigned char data; + + wb( &SMC37c669->index_port, index ); + data = rb( &SMC37c669->data_port ); + return data; +} + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function writes an SMC37c669 Super I/O controller +** configuration register. This function assumes that the +** device is already in configuration mode. +** +** FORMAL PARAMETERS: +** +** index: +** Index of configuration register to write +** +** data: +** Data to be written +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +static void __init SMC37c669_write_config( + unsigned char index, + unsigned char data ) +{ + wb( &SMC37c669->index_port, index ); + wb( &SMC37c669->data_port, data ); +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function initializes the local device +** configuration storage. This function assumes +** that the device is already in configuration +** mode. +** +** FORMAL PARAMETERS: +** +** None +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** Local storage for device configuration information +** is initialized. +** +**-- +*/ +static void __init SMC37c669_init_local_config ( void ) +{ + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER uart_base; + SMC37c669_SERIAL_IRQ_REGISTER uart_irqs; + SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER ppt_base; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER ppt_fdc_irqs; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER ppt_fdc_drqs; + SMC37c669_FDC_BASE_ADDRESS_REGISTER fdc_base; + SMC37c669_IDE_ADDRESS_REGISTER ide_base; + SMC37c669_IDE_ADDRESS_REGISTER ide_alt; + +/* +** Get serial port 1 base address +*/ + uart_base.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX ); +/* +** Get IRQs for serial ports 1 & 2 +*/ + uart_irqs.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); +/* +** Store local configuration information for serial port 1 +*/ + local_config[SERIAL_0].port1 = uart_base.by_field.addr9_3 << 3; + local_config[SERIAL_0].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart1_irq ) + ); +/* +** Get serial port 2 base address +*/ + uart_base.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX ); +/* +** Store local configuration information for serial port 2 +*/ + local_config[SERIAL_1].port1 = uart_base.by_field.addr9_3 << 3; + local_config[SERIAL_1].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart2_irq ) + ); +/* +** Get parallel port base address +*/ + ppt_base.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX ); +/* +** Get IRQs for parallel port and floppy controller +*/ + ppt_fdc_irqs.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); +/* +** Get DRQs for parallel port and floppy controller +*/ + ppt_fdc_drqs.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); +/* +** Store local configuration information for parallel port +*/ + local_config[PARALLEL_0].port1 = ppt_base.by_field.addr9_2 << 2; + local_config[PARALLEL_0].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.ppt_irq ) + ); + local_config[PARALLEL_0].drq = + SMC37c669_xlate_drq( + SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.ppt_drq ) + ); +/* +** Get floppy controller base address +*/ + fdc_base.as_uchar = + SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX ); +/* +** Store local configuration information for floppy controller +*/ + local_config[FLOPPY_0].port1 = fdc_base.by_field.addr9_4 << 4; + local_config[FLOPPY_0].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.fdc_irq ) + ); + local_config[FLOPPY_0].drq = + SMC37c669_xlate_drq( + SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.fdc_drq ) + ); +/* +** Get IDE controller base address +*/ + ide_base.as_uchar = + SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX ); +/* +** Get IDE alternate status base address +*/ + ide_alt.as_uchar = + SMC37c669_read_config( SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX ); +/* +** Store local configuration information for IDE controller +*/ + local_config[IDE_0].port1 = ide_base.by_field.addr9_4 << 4; + local_config[IDE_0].port2 = ide_alt.by_field.addr9_4 << 4; + local_config[IDE_0].irq = 14; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function returns a pointer to the local shadow +** configuration of the requested device function. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** RETURN VALUE: +** +** Returns a pointer to the DEVICE_CONFIG structure for the +** requested function, otherwise, NULL. +** +** SIDE EFFECTS: +** +** {@description or none@} +** +**-- +*/ +static struct DEVICE_CONFIG * __init SMC37c669_get_config( unsigned int func ) +{ + struct DEVICE_CONFIG *cp = NULL; + + switch ( func ) { + case SERIAL_0: + cp = &local_config[ SERIAL_0 ]; + break; + case SERIAL_1: + cp = &local_config[ SERIAL_1 ]; + break; + case PARALLEL_0: + cp = &local_config[ PARALLEL_0 ]; + break; + case FLOPPY_0: + cp = &local_config[ FLOPPY_0 ]; + break; + case IDE_0: + cp = &local_config[ IDE_0 ]; + break; + } + return cp; +} + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function translates IRQs back and forth between ISA +** IRQs and SMC37c669 device IRQs. +** +** FORMAL PARAMETERS: +** +** irq: +** The IRQ to translate +** +** RETURN VALUE: +** +** Returns the translated IRQ, otherwise, returns -1. +** +** SIDE EFFECTS: +** +** {@description or none@} +** +**-- +*/ +static int __init SMC37c669_xlate_irq ( unsigned int irq ) +{ + int i, translated_irq = -1; + + if ( SMC37c669_IS_DEVICE_IRQ( irq ) ) { +/* +** We are translating a device IRQ to an ISA IRQ +*/ + for ( i = 0; ( SMC37c669_irq_table[i].device_irq != -1 ) || ( SMC37c669_irq_table[i].isa_irq != -1 ); i++ ) { + if ( irq == SMC37c669_irq_table[i].device_irq ) { + translated_irq = SMC37c669_irq_table[i].isa_irq; + break; + } + } + } + else { +/* +** We are translating an ISA IRQ to a device IRQ +*/ + for ( i = 0; ( SMC37c669_irq_table[i].isa_irq != -1 ) || ( SMC37c669_irq_table[i].device_irq != -1 ); i++ ) { + if ( irq == SMC37c669_irq_table[i].isa_irq ) { + translated_irq = SMC37c669_irq_table[i].device_irq; + break; + } + } + } + return translated_irq; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function translates DMA channels back and forth between +** ISA DMA channels and SMC37c669 device DMA channels. +** +** FORMAL PARAMETERS: +** +** drq: +** The DMA channel to translate +** +** RETURN VALUE: +** +** Returns the translated DMA channel, otherwise, returns -1 +** +** SIDE EFFECTS: +** +** {@description or none@} +** +**-- +*/ +static int __init SMC37c669_xlate_drq ( unsigned int drq ) +{ + int i, translated_drq = -1; + + if ( SMC37c669_IS_DEVICE_DRQ( drq ) ) { +/* +** We are translating a device DMA channel to an ISA DMA channel +*/ + for ( i = 0; ( SMC37c669_drq_table[i].device_drq != -1 ) || ( SMC37c669_drq_table[i].isa_drq != -1 ); i++ ) { + if ( drq == SMC37c669_drq_table[i].device_drq ) { + translated_drq = SMC37c669_drq_table[i].isa_drq; + break; + } + } + } + else { +/* +** We are translating an ISA DMA channel to a device DMA channel +*/ + for ( i = 0; ( SMC37c669_drq_table[i].isa_drq != -1 ) || ( SMC37c669_drq_table[i].device_drq != -1 ); i++ ) { + if ( drq == SMC37c669_drq_table[i].isa_drq ) { + translated_drq = SMC37c669_drq_table[i].device_drq; + break; + } + } + } + return translated_drq; +} + +#if 0 +int __init smcc669_init ( void ) +{ + struct INODE *ip; + + allocinode( smc_ddb.name, 1, &ip ); + ip->dva = &smc_ddb; + ip->attr = ATTR$M_WRITE | ATTR$M_READ; + ip->len[0] = 0x30; + ip->misc = 0; + INODE_UNLOCK( ip ); + + return msg_success; +} + +int __init smcc669_open( struct FILE *fp, char *info, char *next, char *mode ) +{ + struct INODE *ip; +/* +** Allow multiple readers but only one writer. ip->misc keeps track +** of the number of writers +*/ + ip = fp->ip; + INODE_LOCK( ip ); + if ( fp->mode & ATTR$M_WRITE ) { + if ( ip->misc ) { + INODE_UNLOCK( ip ); + return msg_failure; /* too many writers */ + } + ip->misc++; + } +/* +** Treat the information field as a byte offset +*/ + *fp->offset = xtoi( info ); + INODE_UNLOCK( ip ); + + return msg_success; +} + +int __init smcc669_close( struct FILE *fp ) +{ + struct INODE *ip; + + ip = fp->ip; + if ( fp->mode & ATTR$M_WRITE ) { + INODE_LOCK( ip ); + ip->misc--; + INODE_UNLOCK( ip ); + } + return msg_success; +} + +int __init smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf ) +{ + int i; + int length; + int nbytes; + struct INODE *ip; + +/* +** Always access a byte at a time +*/ + ip = fp->ip; + length = size * number; + nbytes = 0; + + SMC37c669_config_mode( TRUE ); + for ( i = 0; i < length; i++ ) { + if ( !inrange( *fp->offset, 0, ip->len[0] ) ) + break; + *buf++ = SMC37c669_read_config( *fp->offset ); + *fp->offset += 1; + nbytes++; + } + SMC37c669_config_mode( FALSE ); + return nbytes; +} + +int __init smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf ) +{ + int i; + int length; + int nbytes; + struct INODE *ip; +/* +** Always access a byte at a time +*/ + ip = fp->ip; + length = size * number; + nbytes = 0; + + SMC37c669_config_mode( TRUE ); + for ( i = 0; i < length; i++ ) { + if ( !inrange( *fp->offset, 0, ip->len[0] ) ) + break; + SMC37c669_write_config( *fp->offset, *buf ); + *fp->offset += 1; + buf++; + nbytes++; + } + SMC37c669_config_mode( FALSE ); + return nbytes; +} +#endif + +void __init +SMC37c669_dump_registers(void) +{ + int i; + for (i = 0; i <= 0x29; i++) + printk("-- CR%02x : %02x\n", i, SMC37c669_read_config(i)); +} +/*+ + * ============================================================================ + * = SMC_init - SMC37c669 Super I/O controller initialization = + * ============================================================================ + * + * OVERVIEW: + * + * This routine configures and enables device functions on the + * SMC37c669 Super I/O controller. + * + * FORM OF CALL: + * + * SMC_init( ); + * + * RETURNS: + * + * Nothing + * + * ARGUMENTS: + * + * None + * + * SIDE EFFECTS: + * + * None + * + */ +void __init SMC669_Init ( void ) +{ + SMC37c669_CONFIG_REGS *SMC_base; + + if ( ( SMC_base = SMC37c669_detect( ) ) != NULL ) { + printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n", + (unsigned long) SMC_base ); +#if SMC_DEBUG + SMC37c669_config_mode( TRUE ); + SMC37c669_dump_registers( ); + SMC37c669_config_mode( FALSE ); + SMC37c669_display_device_info( ); +#endif + SMC37c669_disable_device( SERIAL_0 ); + SMC37c669_configure_device( + SERIAL_0, + COM1_BASE, + COM1_IRQ, + -1 + ); + SMC37c669_enable_device( SERIAL_0 ); + + SMC37c669_disable_device( SERIAL_1 ); + SMC37c669_configure_device( + SERIAL_1, + COM2_BASE, + COM2_IRQ, + -1 + ); + SMC37c669_enable_device( SERIAL_1 ); + + SMC37c669_disable_device( PARALLEL_0 ); + SMC37c669_configure_device( + PARALLEL_0, + PARP_BASE, + PARP_IRQ, + PARP_DRQ + ); + SMC37c669_enable_device( PARALLEL_0 ); + + SMC37c669_disable_device( FLOPPY_0 ); + SMC37c669_configure_device( + FLOPPY_0, + FDC_BASE, + FDC_IRQ, + FDC_DRQ + ); + SMC37c669_enable_device( FLOPPY_0 ); + + SMC37c669_disable_device( IDE_0 ); + +#if SMC_DEBUG + SMC37c669_config_mode( TRUE ); + SMC37c669_dump_registers( ); + SMC37c669_config_mode( FALSE ); + SMC37c669_display_device_info( ); +#endif + } + else { +#if SMC_DEBUG + printk( "No SMC37c669 Super I/O Controller found\n" ); +#endif + } +} diff -u --recursive --new-file v2.1.88/linux/arch/alpha/kernel/smc37c93x.c linux/arch/alpha/kernel/smc37c93x.c --- v2.1.88/linux/arch/alpha/kernel/smc37c93x.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/smc37c93x.c Mon Feb 23 10:25:10 1998 @@ -0,0 +1,264 @@ +/* + * SMC 37C93X initialization code + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +/* device "activate" register contents */ +#define DEVICE_ON 1 +#define DEVICE_OFF 0 + +/* configuration on/off keys */ +#define CONFIG_ON_KEY 0x55 +#define CONFIG_OFF_KEY 0xaa + +/* configuration space device definitions */ +#define FDC 0 +#define IDE1 1 +#define IDE2 2 +#define PARP 3 +#define SER1 4 +#define SER2 5 +#define RTCL 6 +#define KYBD 7 +#define AUXIO 8 + +/* Chip register offsets from base */ +#define CONFIG_CONTROL 0x02 +#define INDEX_ADDRESS 0x03 +#define LOGICAL_DEVICE_NUMBER 0x07 +#define DEVICE_ID 0x20 +#define DEVICE_REV 0x21 +#define POWER_CONTROL 0x22 +#define POWER_MGMT 0x23 +#define OSC 0x24 + +#define ACTIVATE 0x30 +#define ADDR_HI 0x60 +#define ADDR_LO 0x61 +#define INTERRUPT_SEL 0x70 +#define INTERRUPT_SEL_2 0x72 /* KYBD/MOUS only */ +#define DMA_CHANNEL_SEL 0x74 /* FDC/PARP only */ + +#define FDD_MODE_REGISTER 0x90 +#define FDD_OPTION_REGISTER 0x91 + +/* values that we read back that are expected ... */ +#define VALID_DEVICE_ID 2 + +/* default device addresses */ +#define KYBD_INTERRUPT 1 +#define MOUS_INTERRUPT 12 +#define COM2_BASE 0x2f8 +#define COM2_INTERRUPT 3 +#define COM1_BASE 0x3f8 +#define COM1_INTERRUPT 4 +#define PARP_BASE 0x3bc +#define PARP_INTERRUPT 7 + +#define SMC_DEBUG 0 + +static unsigned long __init SMCConfigState(unsigned long baseAddr) +{ + unsigned char devId; + unsigned char devRev; + + unsigned long configPort; + unsigned long indexPort; + unsigned long dataPort; + + configPort = indexPort = baseAddr; + dataPort = configPort + 1; + + outb(CONFIG_ON_KEY, configPort); + outb(CONFIG_ON_KEY, configPort); + outb(DEVICE_ID, indexPort); + devId = inb(dataPort); + if ( devId == VALID_DEVICE_ID ) { + outb(DEVICE_REV, indexPort); + devRev = inb(dataPort); + } + else { + baseAddr = 0; + } + return baseAddr; +} + +static void __init SMCRunState(unsigned long baseAddr) +{ + outb(CONFIG_OFF_KEY, baseAddr); +} + +static unsigned long __init SMCDetectUltraIO(void) +{ + unsigned long baseAddr; + + baseAddr = 0x3F0; + if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) { + return( baseAddr ); + } + baseAddr = 0x370; + if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) { + return( baseAddr ); + } + return( ( unsigned long )0 ); +} + +static void __init SMCEnableDevice(unsigned long baseAddr, + unsigned long device, + unsigned long portaddr, + unsigned long interrupt) +{ + unsigned long indexPort; + unsigned long dataPort; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(device, dataPort); + + outb(ADDR_LO, indexPort); + outb(( portaddr & 0xFF ), dataPort); + + outb(ADDR_HI, indexPort); + outb((portaddr >> 8) & 0xFF, dataPort); + + outb(INTERRUPT_SEL, indexPort); + outb(interrupt, dataPort); + + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); +} + +static void __init SMCEnableKYBD(unsigned long baseAddr) +{ + unsigned long indexPort; + unsigned long dataPort; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(KYBD, dataPort); + + outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ + outb(KYBD_INTERRUPT, dataPort); + + outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */ + outb(MOUS_INTERRUPT, dataPort); + + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); +} + +static void __init SMCEnableFDC(unsigned long baseAddr) +{ + unsigned long indexPort; + unsigned long dataPort; + + unsigned char oldValue; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(FDC, dataPort); + + outb(FDD_MODE_REGISTER, indexPort); + oldValue = inb(dataPort); + + oldValue |= 0x0E; /* Enable burst mode */ + outb(oldValue, dataPort); + + outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ + outb(0x06, dataPort ); + + outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */ + outb(0x02, dataPort); + + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); +} + +#if SMC_DEBUG +static void __init SMCReportDeviceStatus(unsigned long baseAddr) +{ + unsigned long indexPort; + unsigned long dataPort; + unsigned char currentControl; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(POWER_CONTROL, indexPort); + currentControl = inb(dataPort); + + printk(currentControl & (1 << FDC) + ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n"); + printk(currentControl & (1 << IDE1) + ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n"); + printk(currentControl & (1 << IDE2) + ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n"); + printk(currentControl & (1 << PARP) + ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n"); + printk(currentControl & (1 << SER1) + ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n"); + printk(currentControl & (1 << SER2) + ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n"); + + printk( "\n" ); +} +#endif + +int __init SMC93x_Init(void) +{ + unsigned long SMCUltraBase; + + if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) { + printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", + SMCUltraBase); +#if SMC_DEBUG + SMCReportDeviceStatus(SMCUltraBase); +#endif + SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT); + SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT); + SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT); + /* On PC164, IDE on the SMC is not enabled; + CMD646 (PCI) on MB */ + SMCEnableKYBD(SMCUltraBase); + SMCEnableFDC(SMCUltraBase); +#if SMC_DEBUG + SMCReportDeviceStatus(SMCUltraBase); +#endif + SMCRunState(SMCUltraBase); + return 1; + } + else { +#if SMC_DEBUG + printk("No SMC FDC37C93X Ultra I/O Controller found\n"); +#endif + return 0; + } +} diff -u --recursive --new-file v2.1.88/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c --- v2.1.88/linux/arch/i386/kernel/ldt.c Fri Nov 14 18:28:48 1997 +++ linux/arch/i386/kernel/ldt.c Sat Feb 21 12:42:28 1998 @@ -33,31 +33,6 @@ return copy_to_user(ptr, address, size) ? -EFAULT : size; } -static inline int limits_ok(struct modify_ldt_ldt_s *ldt_info) -{ - unsigned long base, limit; - /* linear address of first and last accessible byte */ - unsigned long first, last; - - base = ldt_info->base_addr; - limit = ldt_info->limit; - if (ldt_info->limit_in_pages) - limit = limit * PAGE_SIZE + PAGE_SIZE - 1; - - first = base; - last = limit + base; - - /* segment grows down? */ - if (ldt_info->contents == 1) { - /* data segment grows down */ - first = base+limit+1; - last = base+65535; - if (ldt_info->seg_32bit) - last = base-1; - } - return (last >= first && last < TASK_SIZE); -} - static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) { struct modify_ldt_ldt_s ldt_info; @@ -71,9 +46,6 @@ return -EFAULT; if ((ldt_info.contents == 3 && (oldmode || ldt_info.seg_not_present == 0)) || ldt_info.entry_number >= LDT_ENTRIES) - return -EINVAL; - - if (!limits_ok(&ldt_info) && (oldmode || ldt_info.seg_not_present == 0)) return -EINVAL; if (!current->ldt) { diff -u --recursive --new-file v2.1.88/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.1.88/linux/arch/i386/kernel/setup.c Wed Feb 4 11:36:00 1998 +++ linux/arch/i386/kernel/setup.c Tue Feb 24 22:38:57 1998 @@ -341,7 +341,7 @@ NULL, NULL, NULL, NULL }}, { X86_VENDOR_INTEL, 6, { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II", NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, + "Pentium II (0.25 um)", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_CYRIX, 4, { NULL, NULL, NULL, NULL, "MediaGX", NULL, NULL, NULL, NULL, "5x86", NULL, NULL, NULL, NULL, NULL, NULL }}, @@ -383,8 +383,7 @@ c->cpuid_level < 0) return; - if ((c->x86_vendor == X86_VENDOR_AMD && amd_model(c)) || - (c->x86_vendor == X86_VENDOR_CYRIX && cyrix_model(c))) + if (c->x86_vendor == X86_VENDOR_CYRIX && cyrix_model(c)) return; if (c->x86_model < 16) @@ -394,10 +393,15 @@ p = cpu_models[i].model_names[c->x86_model]; break; } - if (p) + if (p) { strcpy(c->x86_model_id, p); - else - sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model); + return; + } + + if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c)) + return; + + sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model); } static char *cpu_vendor_names[] __initdata = { diff -u --recursive --new-file v2.1.88/linux/arch/m68k/defconfig linux/arch/m68k/defconfig --- v2.1.88/linux/arch/m68k/defconfig Tue Feb 17 13:12:44 1998 +++ linux/arch/m68k/defconfig Tue Feb 24 22:08:01 1998 @@ -15,7 +15,7 @@ # CONFIG_KERNELD is not set # -# Platform dependant setup +# Platform-dependent setup # CONFIG_AMIGA=y # CONFIG_ATARI is not set diff -u --recursive --new-file v2.1.88/linux/arch/mips/Makefile linux/arch/mips/Makefile --- v2.1.88/linux/arch/mips/Makefile Wed Dec 10 10:31:09 1997 +++ linux/arch/mips/Makefile Tue Feb 24 22:08:01 1998 @@ -65,7 +65,7 @@ endif # -# CPU dependand compiler/assembler options for optimization. +# CPU-dependent compiler/assembler options for optimization. # ifdef CONFIG_CPU_R3000 CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1 @@ -93,7 +93,7 @@ endif # -# Board dependand options and extra files +# Board-dependent options and extra files # ifdef CONFIG_ALGOR_P4032 CORE_FILES += arch/mips/algor/algor.o diff -u --recursive --new-file v2.1.88/linux/arch/mips/dec/setup.c linux/arch/mips/dec/setup.c --- v2.1.88/linux/arch/mips/dec/setup.c Thu Jun 26 12:33:37 1997 +++ linux/arch/mips/dec/setup.c Tue Feb 24 22:08:01 1998 @@ -1,5 +1,5 @@ /* - * Setup pointers to hardware dependand routines. + * Setup pointers to hardware-dependent routines. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff -u --recursive --new-file v2.1.88/linux/arch/mips/deskstation/setup.c linux/arch/mips/deskstation/setup.c --- v2.1.88/linux/arch/mips/deskstation/setup.c Wed Dec 10 10:31:09 1997 +++ linux/arch/mips/deskstation/setup.c Tue Feb 24 22:08:01 1998 @@ -1,5 +1,5 @@ /* - * Setup pointers to hardware dependand routines. + * Setup pointers to hardware-dependent routines. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff -u --recursive --new-file v2.1.88/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c --- v2.1.88/linux/arch/ppc/kernel/residual.c Mon Feb 23 18:12:02 1998 +++ linux/arch/ppc/kernel/residual.c Tue Feb 24 22:08:01 1998 @@ -300,10 +300,10 @@ #undef p break; case StartDepFunc: - printk("Start dependant function:\n"); + printk("Start dependent function:\n"); break; case EndDepFunc: - printk("End dependant function\n"); + printk("End dependent function\n"); break; case IOPort: #define p pkt->S8_Pack diff -u --recursive --new-file v2.1.88/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c --- v2.1.88/linux/drivers/acorn/block/fd1772.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/block/fd1772.c Sat Feb 21 13:25:15 1998 @@ -116,7 +116,6 @@ * 16/11/96 - Fiddled and frigged for 2.0.18 */ -#include #include #include #include diff -u --recursive --new-file v2.1.88/linux/drivers/acorn/scsi/cumana_1.c linux/drivers/acorn/scsi/cumana_1.c --- v2.1.88/linux/drivers/acorn/scsi/cumana_1.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/cumana_1.c Sat Feb 21 13:25:15 1998 @@ -36,7 +36,6 @@ * $Log: cumana_NCR5380.c,v $ */ -#include #include #include #include diff -u --recursive --new-file v2.1.88/linux/drivers/acorn/scsi/ecoscsi.c linux/drivers/acorn/scsi/ecoscsi.c --- v2.1.88/linux/drivers/acorn/scsi/ecoscsi.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/ecoscsi.c Sat Feb 21 13:25:15 1998 @@ -35,7 +35,6 @@ * $Log: ecoscsi_NCR5380.c,v $ */ -#include #include #include #include diff -u --recursive --new-file v2.1.88/linux/drivers/acorn/scsi/oak.c linux/drivers/acorn/scsi/oak.c --- v2.1.88/linux/drivers/acorn/scsi/oak.c Mon Feb 23 18:12:03 1998 +++ linux/drivers/acorn/scsi/oak.c Sat Feb 21 13:25:15 1998 @@ -35,7 +35,6 @@ * $Log: oak.c,v $ */ -#include #include #include #include diff -u --recursive --new-file v2.1.88/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.88/linux/drivers/block/floppy.c Tue Feb 17 13:12:46 1998 +++ linux/drivers/block/floppy.c Sun Feb 22 10:48:45 1998 @@ -148,7 +148,7 @@ #include #include -static int can_use_virtual_dma=0; +static int can_use_virtual_dma=2; /* ======= * can use virtual DMA: * 0 = use of virtual DMA disallowed by config @@ -2083,7 +2083,7 @@ #define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2) #define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80) >>1)) -#define CT(x) ((x) | 0x40) +#define CT(x) ((x) | 0xc0) static void setup_format_params(int track) { struct fparm { @@ -2465,6 +2465,32 @@ } #endif +/* work around a bug in pseudo DMA + * (on some FDCs) pseudo DMA does not stop when the CPU stops + * sending data. Hence we need a different way to signal the + * transfer length: We use SECT_PER_TRACK. Unfortunately, this + * does not work with MT, hence we can only transfer one head at + * a time + */ +static int virtualdmabug_workaround() { + int hard_sectors, end_sector; + if(CT(COMMAND) == FD_WRITE) { + COMMAND &= ~0x80; /* switch off multiple track mode */ + + hard_sectors = raw_cmd->length >> (7 + SIZECODE); + end_sector = SECTOR + hard_sectors - 1; +#ifdef FLOPPY_SANITY_CHECK + if(end_sector > SECT_PER_TRACK) { + printk("too many sectors %d > %d\n", + end_sector, SECT_PER_TRACK); + return 0; + } +#endif + SECT_PER_TRACK = end_sector; /* make sure SECT_PER_TRACK points + * to end of transfer */ + } +} + /* * Formulate a read/write request. * this routine decides where to load the data (directly to buffer, or to @@ -2541,11 +2567,17 @@ CODE2SIZE; SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE; SECTOR = ((sector_t % _floppy->sect) << 2 >> SIZECODE) + 1; + + /* tracksize describes the size which can be filled up with sectors + * of size ssize. + */ tracksize = _floppy->sect - _floppy->sect % ssize; if (tracksize < _floppy->sect){ SECT_PER_TRACK ++; if (tracksize <= sector_t % _floppy->sect) SECTOR--; + + /* if we are beyond tracksize, fill up using smaller sectors */ while (tracksize <= sector_t % _floppy->sect){ while(tracksize + ssize > _floppy->sect){ SIZECODE--; @@ -2555,8 +2587,12 @@ tracksize += ssize; } max_sector = HEAD * _floppy->sect + tracksize; - } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) + } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) { + max_sector = _floppy->sect; + } else if (!HEAD && CT(COMMAND) == FD_WRITE) { + /* for virtual DMA bug workaround */ max_sector = _floppy->sect; + } aligned_sector_t = sector_t - (sector_t % _floppy->sect) % ssize; max_size = CURRENT->nr_sectors; @@ -2625,6 +2661,8 @@ /* check_dma_crossing(raw_cmd->kernel_data, raw_cmd->length, "end of make_raw_request [1]");*/ + + virtualdmabug_workaround(); return 2; } } @@ -2730,6 +2768,8 @@ return 0; } #endif + + virtualdmabug_workaround(); return 2; } diff -u --recursive --new-file v2.1.88/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.1.88/linux/drivers/char/Config.in Thu Feb 12 20:56:05 1998 +++ linux/drivers/char/Config.in Tue Feb 24 22:37:02 1998 @@ -89,6 +89,7 @@ bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK bool ' Power off on shutdown' CONFIG_APM_POWER_OFF + bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND fi bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then diff -u --recursive --new-file v2.1.88/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c --- v2.1.88/linux/drivers/char/apm_bios.c Mon Feb 23 18:12:04 1998 +++ linux/drivers/char/apm_bios.c Tue Feb 24 22:37:02 1998 @@ -27,6 +27,7 @@ * Version 1.0 and 1.1 * May 1996, Version 1.2 * Feb 1998, Version 1.3 + * Feb 1998, Version 1.4 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -46,8 +47,11 @@ * The new replacment for it is, but Linux doesn't yet support this. * Alan Cox Linux 2.1.55 * 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's + * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by + * Dean Gaudet . + * C. Scott Ananian Linux 2.1.87 * - * Reference: + * APM 1.1 Reference: * * Intel Corporation, Microsoft Corporation. Advanced Power Management * (APM) BIOS Interface Specification, Revision 1.1, September 1993. @@ -58,6 +62,15 @@ * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also * available from Microsoft by calling 206.882.8080.] * + * APM 1.2 Reference: + * Intel Corporation, Microsoft Corporation. Advanced Power Management + * (APM) BIOS Interface Specification, Revision 1.2, February 1996. + * + * [This document is available from Intel at: + * http://www.intel.com/IAL/powermgm + * or Microsoft at + * http://www.microsoft.com/windows/thirdparty/hardware/pcfuture.htm + * ] */ #include @@ -128,6 +141,11 @@ * problems have been reported when using this option with gpm (if you'd * like to debug this, please do so). * + * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist + * on returning multiple suspend/standby events whenever one occurs. We + * really only need one at a time, so just ignore any beyond the first. + * This is probably safe on most laptops. + * * If you are debugging the APM support for your laptop, note that code for * all of these options is contained in this file, so you can #define or * #undef these on the next line to avoid recompiling the whole kernel. @@ -341,6 +359,9 @@ #endif static int suspends_pending = 0; static int standbys_pending = 0; +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND +static int waiting_for_resume = 0; +#endif static long clock_cmos_diff; static int got_clock_diff = 0; @@ -350,7 +371,7 @@ static struct timer_list apm_timer; -static char driver_version[] = "1.3"; /* no spaces */ +static char driver_version[] = "1.4"; /* no spaces */ #ifdef APM_DEBUG static char * apm_event_name[] = { @@ -614,8 +635,15 @@ if (as == sender) continue; as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; - if (as->event_head == as->event_tail) + if (as->event_head == as->event_tail) { + static int notified; + + if (notified == 0) { + printk( "apm_bios: an event queue overflowed\n" ); + notified = 1; + } as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + } as->events[as->event_head] = event; if (!as->suser) continue; @@ -722,9 +750,23 @@ apm_event_t event; while ((event = get_event()) != 0) { +#ifdef APM_DEBUG + if (event <= NR_APM_EVENT_NAME) + printk(KERN_DEBUG "APM BIOS received %s notify\n", + apm_event_name[event - 1]); + else + printk(KERN_DEBUG "APM BIOS received unknown " + "event 0x%02x\n", event); +#endif switch (event) { case APM_SYS_STANDBY: case APM_USER_STANDBY: +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + if (waiting_for_resume) { + return; + } + waiting_for_resume = 1; +#endif send_event(event, APM_STANDBY_RESUME, NULL); if (standbys_pending <= 0) standby(); @@ -737,6 +779,12 @@ break; #endif case APM_SYS_SUSPEND: +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + if (waiting_for_resume) { + return; + } + waiting_for_resume = 1; +#endif send_event(event, APM_NORMAL_RESUME, NULL); if (suspends_pending <= 0) suspend(); @@ -745,6 +793,9 @@ case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: case APM_STANDBY_RESUME: +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + waiting_for_resume = 0; +#endif set_time(); send_event(event, 0, NULL); break; @@ -763,14 +814,6 @@ suspend(); break; } -#ifdef APM_DEBUG - if (event <= NR_APM_EVENT_NAME) - printk(KERN_DEBUG "APM BIOS received %s notify\n", - apm_event_name[event - 1]); - else - printk(KERN_DEBUG "APM BIOS received unknown event 0x%02x\n", - event); -#endif } } diff -u --recursive --new-file v2.1.88/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.1.88/linux/drivers/char/epca.c Thu Jan 15 14:33:06 1998 +++ linux/drivers/char/epca.c Tue Feb 24 22:08:01 1998 @@ -185,7 +185,7 @@ /* ---------------------------------------------------------------------- Begin generic memory functions. These functions will be alias - (point at) more specific functions dependant on the board being + (point at) more specific functions dependent on the board being configured. ----------------------------------------------------------------------- */ @@ -461,7 +461,7 @@ cards (Such as PCI) needs no windowing routines at all. We provide these do nothing routines so that the same code base can be used. The driver will ALWAYS call a windowing routine if it thinks it needs - to; regardless of the card. However, dependant on the card the routine + to; regardless of the card. However, dependent on the card the routine may or may not do anything. ---------------------------------------------------------------------------*/ @@ -4066,7 +4066,7 @@ base_addr5); /* ------------------------------------------------------------------------ - NOTE - The code below mask out either the 2 or 4 bits dependant on the + NOTE - The code below mask out either the 2 or 4 bits dependent on the space being addressed. (base_addr value reflecting io space, have their first 2 bits mask out, while base_addr value reflecting mem space, have their first 4 bits mask out.) These bits are flag bits and should always diff -u --recursive --new-file v2.1.88/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.88/linux/drivers/char/lp.c Thu Feb 12 20:56:06 1998 +++ linux/drivers/char/lp.c Tue Feb 24 22:33:03 1998 @@ -128,7 +128,7 @@ static __inline__ void lp_yield (int minor) { - if (parport_yield (lp_table[minor].dev, 1) == 1 && need_resched) + if (!parport_yield_blocking (lp_table[minor].dev) && need_resched) schedule (); } @@ -654,7 +654,14 @@ __initfunc(void lp_setup(char *str, int *ints)) { - if (!strncmp(str, "parport", 7)) { + if (!str) { + if (ints[0] == 0 || ints[1] == 0) { + /* disable driver on "lp=" or "lp=0" */ + parport[0] = LP_PARPORT_OFF; + } else { + printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]); + } + } else if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str+7, NULL, 10); if (parport_ptr < LP_NO) parport[parport_ptr++] = n; @@ -667,13 +674,6 @@ parport[parport_ptr++] = LP_PARPORT_NONE; } else if (!strcmp(str, "reset")) { reset = 1; - } else { - if (ints[0] == 0 || ints[1] == 0) { - /* disable driver on "lp=" or "lp=0" */ - parport[0] = LP_PARPORT_OFF; - } else { - printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]); - } } } diff -u --recursive --new-file v2.1.88/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.1.88/linux/drivers/char/rtc.c Mon Dec 8 23:58:04 1997 +++ linux/drivers/char/rtc.c Mon Feb 23 10:25:10 1998 @@ -28,9 +28,14 @@ * Based on other minimal char device drivers, like Alan's * watchdog, Ted's random, etc. etc. * + * 1.07 Paul Gortmaker. + * 1.08 Miquel van Smoorenburg: disallow certain things on the + * DEC Alpha as the CMOS clock is also used for other things. + * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. + * */ -#define RTC_VERSION "1.07" +#define RTC_VERSION "1.09" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -82,7 +87,7 @@ size_t count, loff_t *ppos); static int rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); + unsigned int cmd, unsigned long arg); static unsigned int rtc_poll(struct file *file, poll_table *wait); @@ -106,16 +111,27 @@ unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ unsigned long rtc_irq_data = 0; /* our output to the world */ +/* + * If this driver ever becomes modularised, it will be really nice + * to make the epoch retain its value across module reload... + */ + +static unsigned long epoch = 1900; /* year corresponding to 0x00 */ + unsigned char days_in_mo[] = - {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* * A very tiny interrupt handler. It runs with SA_INTERRUPT set, * so that there is no possibility of conflicting with the * set_rtc_mmss() call that happens during some timer interrupts. * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) + * + * On Alpha we won't get any interrupts anyway, as they all end up + * in the system timer code. */ +#ifndef __alpha__ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { /* @@ -136,9 +152,11 @@ add_timer(&rtc_irq_timer); } } +#endif /* * Now all the various file operations that we export. + * They are all useless on Alpha... *sigh*. */ static long long rtc_llseek(struct file *file, loff_t offset, int origin) @@ -149,6 +167,9 @@ static ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) { +#ifdef __alpha__ + return -EIO; +#else struct wait_queue wait = { current, NULL }; unsigned long data; ssize_t retval; @@ -175,239 +196,269 @@ retval = put_user(data, (unsigned long *)buf); if (!retval) retval = sizeof(unsigned long); -out: + out: current->state = TASK_RUNNING; remove_wait_queue(&rtc_wait, &wait); return retval; +#endif } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { unsigned long flags; struct rtc_time wtime; switch (cmd) { - case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ - { - mask_rtc_irq_bit(RTC_AIE); - return 0; - } - case RTC_AIE_ON: /* Allow alarm interrupts. */ - { - set_rtc_irq_bit(RTC_AIE); - return 0; - } - case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ - { - mask_rtc_irq_bit(RTC_PIE); - if (rtc_status & RTC_TIMER_ON) { - del_timer(&rtc_irq_timer); - rtc_status &= ~RTC_TIMER_ON; - } - return 0; +#ifndef __alpha__ + case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ + { + mask_rtc_irq_bit(RTC_AIE); + return 0; + } + case RTC_AIE_ON: /* Allow alarm interrupts. */ + { + set_rtc_irq_bit(RTC_AIE); + return 0; + } + case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ + { + mask_rtc_irq_bit(RTC_PIE); + if (rtc_status & RTC_TIMER_ON) { + del_timer(&rtc_irq_timer); + rtc_status &= ~RTC_TIMER_ON; } - case RTC_PIE_ON: /* Allow periodic ints */ - { + return 0; + } + case RTC_PIE_ON: /* Allow periodic ints */ + { - /* - * We don't really want Joe User enabling more - * than 64Hz of interrupts on a multi-user machine. - */ - if ((rtc_freq > 64) && (!suser())) - return -EACCES; - - if (!(rtc_status & RTC_TIMER_ON)) { - rtc_status |= RTC_TIMER_ON; - rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; - add_timer(&rtc_irq_timer); - } - set_rtc_irq_bit(RTC_PIE); - return 0; - } - case RTC_UIE_OFF: /* Mask ints from RTC updates. */ - { - mask_rtc_irq_bit(RTC_UIE); - return 0; + /* + * We don't really want Joe User enabling more + * than 64Hz of interrupts on a multi-user machine. + */ + if ((rtc_freq > 64) && (!suser())) + return -EACCES; + + if (!(rtc_status & RTC_TIMER_ON)) { + rtc_status |= RTC_TIMER_ON; + rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; + add_timer(&rtc_irq_timer); } - case RTC_UIE_ON: /* Allow ints for RTC updates. */ - { - set_rtc_irq_bit(RTC_UIE); - return 0; - } - case RTC_ALM_READ: /* Read the present alarm time */ - { - /* - * This returns a struct rtc_time. Reading >= 0xc0 - * means "don't care" or "match all". Only the tm_hour, - * tm_min, and tm_sec values are filled in. - */ + set_rtc_irq_bit(RTC_PIE); + return 0; + } + case RTC_UIE_OFF: /* Mask ints from RTC updates. */ + { + mask_rtc_irq_bit(RTC_UIE); + return 0; + } + case RTC_UIE_ON: /* Allow ints for RTC updates. */ + { + set_rtc_irq_bit(RTC_UIE); + return 0; + } +#endif + case RTC_ALM_READ: /* Read the present alarm time */ + { + /* + * This returns a struct rtc_time. Reading >= 0xc0 + * means "don't care" or "match all". Only the tm_hour, + * tm_min, and tm_sec values are filled in. + */ - get_rtc_alm_time(&wtime); - break; - } - case RTC_ALM_SET: /* Store a time into the alarm */ - { - /* - * This expects a struct rtc_time. Writing 0xff means - * "don't care" or "match all". Only the tm_hour, - * tm_min and tm_sec are used. - */ - unsigned char hrs, min, sec; - struct rtc_time alm_tm; - - if (copy_from_user(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) - return -EFAULT; - - hrs = alm_tm.tm_hour; - min = alm_tm.tm_min; - sec = alm_tm.tm_sec; - - if (hrs >= 24) - hrs = 0xff; - - if (min >= 60) - min = 0xff; - - if (sec >= 60) - sec = 0xff; - - save_flags(flags); - cli(); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - } - CMOS_WRITE(hrs, RTC_HOURS_ALARM); - CMOS_WRITE(min, RTC_MINUTES_ALARM); - CMOS_WRITE(sec, RTC_SECONDS_ALARM); - restore_flags(flags); + get_rtc_alm_time(&wtime); + break; + } + case RTC_ALM_SET: /* Store a time into the alarm */ + { + /* + * This expects a struct rtc_time. Writing 0xff means + * "don't care" or "match all". Only the tm_hour, + * tm_min and tm_sec are used. + */ + unsigned char hrs, min, sec; + struct rtc_time alm_tm; + + if (copy_from_user(&alm_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + hrs = alm_tm.tm_hour; + min = alm_tm.tm_min; + sec = alm_tm.tm_sec; + + if (hrs >= 24) + hrs = 0xff; + + if (min >= 60) + min = 0xff; + + if (sec >= 60) + sec = 0xff; + + save_flags(flags); + cli(); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || + RTC_ALWAYS_BCD) + { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + } + CMOS_WRITE(hrs, RTC_HOURS_ALARM); + CMOS_WRITE(min, RTC_MINUTES_ALARM); + CMOS_WRITE(sec, RTC_SECONDS_ALARM); + restore_flags(flags); - return 0; - } - case RTC_RD_TIME: /* Read the time/date from RTC */ - { - get_rtc_time(&wtime); - break; - } - case RTC_SET_TIME: /* Set the RTC */ - { - struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control, save_freq_select; - unsigned int yrs; - unsigned long flags; + return 0; + } + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + get_rtc_time(&wtime); + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control, save_freq_select; + unsigned int yrs; + unsigned long flags; - if (!suser()) - return -EACCES; - - if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) - return -EFAULT; + if (!suser()) + return -EACCES; - yrs = rtc_tm.tm_year + 1900 + ARCFUDGE; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900 + ARCFUDGE; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; - if ((yrs < 1970) || (yrs > 2069)) - return -EINVAL; + if (yrs < 1970) + return -EINVAL; - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - if ((mon > 12) || (day == 0)) - return -EINVAL; + if ((mon > 12) || (day == 0)) + return -EINVAL; - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; - if (yrs >= 2000) - yrs -= 2000; /* RTC (0, 1, ... 69) */ - else - yrs -= 1900; /* RTC (70, 71, ... 99) */ - - save_flags(flags); - cli(); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + save_flags(flags); + cli(); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) + || RTC_ALWAYS_BCD) { + if (yrs > 169) { + restore_flags(flags); + return -EINVAL; } + if (yrs >= 100) + yrs -= 100; - save_control = CMOS_READ(RTC_CONTROL); - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DAY_OF_MONTH); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + } + + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - restore_flags(flags); - return 0; - } - case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ - { - return put_user(rtc_freq, (unsigned long *)arg); - } - case RTC_IRQP_SET: /* Set periodic IRQ rate. */ - { - int tmp = 0; - unsigned char val; + restore_flags(flags); + return 0; + } + case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ + { + return put_user(rtc_freq, (unsigned long *)arg); + } +#ifndef __alpha__ + case RTC_IRQP_SET: /* Set periodic IRQ rate. */ + { + int tmp = 0; + unsigned char val; - /* - * The max we can do is 8192Hz. - */ - if ((arg < 2) || (arg > 8192)) - return -EINVAL; - /* - * We don't really want Joe User generating more - * than 64Hz of interrupts on a multi-user machine. - */ - if ((arg > 64) && (!suser())) - return -EACCES; - - while (arg > (1< 8192)) + return -EINVAL; + /* + * We don't really want Joe User generating more + * than 64Hz of interrupts on a multi-user machine. + */ + if ((arg > 64) && (!suser())) + return -EACCES; + + while (arg > (1< 10 && year < 44) { + epoch = 1980; + guess = "ARC console"; + } else if (year < 96) { + epoch = 1952; + guess = "Digital UNIX"; + } + if (guess) + printk("rtc: %s epoch (%ld) detected\n", guess, epoch); +#else init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; rtc_wait = NULL; @@ -514,6 +610,7 @@ CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); restore_flags(flags); rtc_freq = 1024; +#endif return 0; } @@ -529,6 +626,7 @@ * for something that requires a steady > 1KHz signal anyways.) */ +#ifndef __alpha__ void rtc_dropped_irq(unsigned long data) { unsigned long flags; @@ -545,6 +643,7 @@ rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ restore_flags(flags); } +#endif /* * Info exported via "/proc/rtc". @@ -572,10 +671,10 @@ * time or for Universal Standard Time (GMT). Probably local though. */ p += sprintf(p, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); get_rtc_alm_time(&tm); @@ -601,24 +700,24 @@ p += sprintf(p, "**\n"); p += sprintf(p, - "DST_enable\t: %s\n" - "BCD\t\t: %s\n" - "24hr\t\t: %s\n" - "square_wave\t: %s\n" - "alarm_IRQ\t: %s\n" - "update_IRQ\t: %s\n" - "periodic_IRQ\t: %s\n" - "periodic_freq\t: %ld\n" - "batt_status\t: %s\n", - (ctrl & RTC_DST_EN) ? "yes" : "no", - (ctrl & RTC_DM_BINARY) ? "no" : "yes", - (ctrl & RTC_24H) ? "yes" : "no", - (ctrl & RTC_SQWE) ? "yes" : "no", - (ctrl & RTC_AIE) ? "yes" : "no", - (ctrl & RTC_UIE) ? "yes" : "no", - (ctrl & RTC_PIE) ? "yes" : "no", - rtc_freq, - batt ? "okay" : "dead"); + "DST_enable\t: %s\n" + "BCD\t\t: %s\n" + "24hr\t\t: %s\n" + "square_wave\t: %s\n" + "alarm_IRQ\t: %s\n" + "update_IRQ\t: %s\n" + "periodic_IRQ\t: %s\n" + "periodic_freq\t: %ld\n" + "batt_status\t: %s\n", + (ctrl & RTC_DST_EN) ? "yes" : "no", + (ctrl & RTC_DM_BINARY) ? "no" : "yes", + (ctrl & RTC_24H) ? "yes" : "no", + (ctrl & RTC_SQWE) ? "yes" : "no", + (ctrl & RTC_AIE) ? "yes" : "no", + (ctrl & RTC_UIE) ? "yes" : "no", + (ctrl & RTC_PIE) ? "yes" : "no", + rtc_freq, + batt ? "okay" : "dead"); return p - buf; } @@ -689,7 +788,7 @@ * Account for differences between how the RTC uses the values * and how they are defined in a struct rtc_time; */ - if (rtc_tm->tm_year <= 69) + if ((rtc_tm->tm_year += epoch - 1900) <= 69) rtc_tm->tm_year += 100; /* if ARCFUDGE == 0, the optimizer should do away with this */ @@ -732,6 +831,8 @@ * We also clear out any old irq data after an ioctl() that * meddles with the interrupt enable/disable bits. */ + +#ifndef __alpha__ void mask_rtc_irq_bit(unsigned char bit) { unsigned char val; @@ -761,4 +862,4 @@ rtc_irq_data = 0; restore_flags(flags); } - +#endif diff -u --recursive --new-file v2.1.88/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.88/linux/drivers/char/tty_io.c Tue Feb 17 13:12:46 1998 +++ linux/drivers/char/tty_io.c Tue Feb 24 22:37:02 1998 @@ -1961,8 +1961,10 @@ return kmem_start; } -static struct tty_driver dev_tty_driver, dev_console_driver, - dev_syscons_driver, dev_ptmx_driver; +static struct tty_driver dev_tty_driver, dev_syscons_driver, dev_ptmx_driver; +#ifdef CONFIG_VT +static struct tty_driver dev_console_driver; +#endif /* * Ok, now we can initialize the rest of the tty devices and can count diff -u --recursive --new-file v2.1.88/linux/drivers/macintosh/aty.c linux/drivers/macintosh/aty.c --- v2.1.88/linux/drivers/macintosh/aty.c Mon Feb 23 18:12:05 1998 +++ linux/drivers/macintosh/aty.c Tue Feb 24 22:08:01 1998 @@ -39,11 +39,11 @@ typedef struct aty_regvals { int offset[3]; /* first pixel address */ - int crtc_h_sync_strt_wid[3]; /* depth dependant */ + int crtc_h_sync_strt_wid[3]; /* depth dependent */ int crtc_gen_cntl[3]; int mem_cntl[3]; - int crtc_h_tot_disp; /* mode dependant */ + int crtc_h_tot_disp; /* mode dependent */ int crtc_v_tot_disp; int crtc_v_sync_strt_wid; int crtc_off_pitch; diff -u --recursive --new-file v2.1.88/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c --- v2.1.88/linux/drivers/misc/parport_arc.c Fri Jan 30 11:28:07 1998 +++ linux/drivers/misc/parport_arc.c Tue Feb 24 22:33:03 1998 @@ -31,15 +31,15 @@ #define DATA_LATCH 0x3350010 /* ARC can't read from the data latch, so we must use a soft copy. */ -static unsigned int data_copy; +static unsigned char data_copy; -static void arc_write_data(struct parport *p, unsigned int data) +static void arc_write_data(struct parport *p, unsigned char data) { data_copy = data; outb(data, DATA_LATCH); } -static unsigned int arc_read_data(struct parport *p) +static unsigned char arc_read_data(struct parport *p) { return data_copy; } diff -u --recursive --new-file v2.1.88/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c --- v2.1.88/linux/drivers/misc/parport_ax.c Mon Feb 23 18:12:05 1998 +++ linux/drivers/misc/parport_ax.c Tue Feb 24 22:33:03 1998 @@ -55,83 +55,83 @@ } void -parport_ax_write_epp(struct parport *p, unsigned int d) +parport_ax_write_epp(struct parport *p, unsigned char d) { outb(d, p->base + EPPREG); } -unsigned int +unsigned char parport_ax_read_epp(struct parport *p) { - return (unsigned int)inb(p->base + EPPREG); + return inb(p->base + EPPREG); } -unsigned int +unsigned char parport_ax_read_configb(struct parport *p) { - return (unsigned int)inb(p->base + CONFIGB); + return inb(p->base + CONFIGB); } void -parport_ax_write_data(struct parport *p, unsigned int d) +parport_ax_write_data(struct parport *p, unsigned char d) { outb(d, p->base + DATA); } -unsigned int +unsigned char parport_ax_read_data(struct parport *p) { - return (unsigned int)inb(p->base + DATA); + return inb(p->base + DATA); } void -parport_ax_write_control(struct parport *p, unsigned int d) +parport_ax_write_control(struct parport *p, unsigned char d) { outb(d, p->base + CONTROL); } -unsigned int +unsigned char parport_ax_read_control(struct parport *p) { - return (unsigned int)inb(p->base + CONTROL); + return inb(p->base + CONTROL); } -unsigned int -parport_ax_frob_control(struct parport *p, unsigned int mask, unsigned int val) +unsigned char +parport_ax_frob_control(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base + CONTROL); + unsigned char old = inb(p->base + CONTROL); outb(((old & ~mask) ^ val), p->base + CONTROL); return old; } void -parport_ax_write_status(struct parport *p, unsigned int d) +parport_ax_write_status(struct parport *p, unsigned char d) { outb(d, p->base + STATUS); } -unsigned int +unsigned char parport_ax_read_status(struct parport *p) { - return (unsigned int)inb(p->base + STATUS); + return inb(p->base + STATUS); } void -parport_ax_write_econtrol(struct parport *p, unsigned int d) +parport_ax_write_econtrol(struct parport *p, unsigned char d) { outb(d, p->base + ECONTROL); } -unsigned int +unsigned char parport_ax_read_econtrol(struct parport *p) { - return (unsigned int)inb(p->base + ECONTROL); + return inb(p->base + ECONTROL); } -unsigned int -parport_ax_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val) +unsigned char +parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base + ECONTROL); + unsigned char old = inb(p->base + ECONTROL); outb(((old & ~mask) ^ val), p->base + ECONTROL); return old; } @@ -143,12 +143,12 @@ } void -parport_ax_write_fifo(struct parport *p, unsigned int v) +parport_ax_write_fifo(struct parport *p, unsigned char v) { outb(v, p->base + DFIFO); } -unsigned int +unsigned char parport_ax_read_fifo(struct parport *p) { return inb(p->base + DFIFO); @@ -221,29 +221,29 @@ parport_ax_write_econtrol(p, s->u.pc.ecr); } -unsigned int -parport_ax_epp_read_block(struct parport *p, void *buf, unsigned int length) +size_t +parport_ax_epp_read_block(struct parport *p, void *buf, size_t length) { return 0; /* FIXME */ } -unsigned int -parport_ax_epp_write_block(struct parport *p, void *buf, unsigned int length) +size_t +parport_ax_epp_write_block(struct parport *p, void *buf, size_t length) { return 0; /* FIXME */ } -unsigned int -parport_ax_ecp_read_block(struct parport *p, void *buf, unsigned int length, - void (*fn)(struct parport *, void *, unsigned int), +int +parport_ax_ecp_read_block(struct parport *p, void *buf, size_t length, + void (*fn)(struct parport *, void *, size_t), void *handle) { return 0; /* FIXME */ } -unsigned int -parport_ax_ecp_write_block(struct parport *p, void *buf, unsigned int length, - void (*fn)(struct parport *, void *, unsigned int), +int +parport_ax_ecp_write_block(struct parport *p, void *buf, size_t length, + void (*fn)(struct parport *, void *, size_t), void *handle) { return 0; /* FIXME */ @@ -331,7 +331,8 @@ */ static int parport_ECR_present(struct parport *pb) { - unsigned int r, octr = pb->ops->read_control(pb), + unsigned int r; + unsigned char octr = pb->ops->read_control(pb), oecr = pb->ops->read_econtrol(pb); r = pb->ops->read_control(pb); @@ -360,7 +361,8 @@ static int parport_ECP_supported(struct parport *pb) { - int i, oecr = pb->ops->read_econtrol(pb); + int i; + unsigned char oecr = pb->ops->read_econtrol(pb); /* If there is no ECONTROL, we have no hope of supporting ECP. */ if (!(pb->modes & PARPORT_MODE_PCECR)) @@ -398,7 +400,8 @@ static int parport_PS2_supported(struct parport *pb) { - int ok = 0, octr = pb->ops->read_control(pb); + int ok = 0; + unsigned char octr = pb->ops->read_control(pb); pb->ops->write_control(pb, octr | 0x20); /* try to tri-state buffer */ @@ -415,7 +418,8 @@ static int parport_ECPPS2_supported(struct parport *pb) { - int mode, oecr = pb->ops->read_econtrol(pb); + int mode; + unsigned char oecr = pb->ops->read_econtrol(pb); if (!(pb->modes & PARPORT_MODE_PCECR)) return 0; diff -u --recursive --new-file v2.1.88/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.1.88/linux/drivers/misc/parport_pc.c Mon Feb 23 18:12:05 1998 +++ linux/drivers/misc/parport_pc.c Tue Feb 24 22:33:03 1998 @@ -58,71 +58,71 @@ /* Null function - does nothing */ } -void parport_pc_write_epp(struct parport *p, unsigned int d) +void parport_pc_write_epp(struct parport *p, unsigned char d) { outb(d, p->base+EPPREG); } -unsigned int parport_pc_read_epp(struct parport *p) +unsigned char parport_pc_read_epp(struct parport *p) { - return (unsigned int)inb(p->base+EPPREG); + return inb(p->base+EPPREG); } -unsigned int parport_pc_read_configb(struct parport *p) +unsigned char parport_pc_read_configb(struct parport *p) { - return (unsigned int)inb(p->base+CONFIGB); + return inb(p->base+CONFIGB); } -void parport_pc_write_data(struct parport *p, unsigned int d) +void parport_pc_write_data(struct parport *p, unsigned char d) { outb(d, p->base+DATA); } -unsigned int parport_pc_read_data(struct parport *p) +unsigned char parport_pc_read_data(struct parport *p) { - return (unsigned int)inb(p->base+DATA); + return inb(p->base+DATA); } -void parport_pc_write_control(struct parport *p, unsigned int d) +void parport_pc_write_control(struct parport *p, unsigned char d) { outb(d, p->base+CONTROL); } -unsigned int parport_pc_read_control(struct parport *p) +unsigned char parport_pc_read_control(struct parport *p) { - return (unsigned int)inb(p->base+CONTROL); + return inb(p->base+CONTROL); } -unsigned int parport_pc_frob_control(struct parport *p, unsigned int mask, unsigned int val) +unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base+CONTROL); + unsigned char old = inb(p->base+CONTROL); outb(((old & ~mask) ^ val), p->base+CONTROL); return old; } -void parport_pc_write_status(struct parport *p, unsigned int d) +void parport_pc_write_status(struct parport *p, unsigned char d) { outb(d, p->base+STATUS); } -unsigned int parport_pc_read_status(struct parport *p) +unsigned char parport_pc_read_status(struct parport *p) { - return (unsigned int)inb(p->base+STATUS); + return inb(p->base+STATUS); } -void parport_pc_write_econtrol(struct parport *p, unsigned int d) +void parport_pc_write_econtrol(struct parport *p, unsigned char d) { outb(d, p->base+ECONTROL); } -unsigned int parport_pc_read_econtrol(struct parport *p) +unsigned char parport_pc_read_econtrol(struct parport *p) { - return (unsigned int)inb(p->base+ECONTROL); + return inb(p->base+ECONTROL); } -unsigned int parport_pc_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val) +unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base+ECONTROL); + unsigned char old = inb(p->base+ECONTROL); outb(((old & ~mask) ^ val), p->base+ECONTROL); return old; } @@ -132,12 +132,12 @@ /* FIXME */ } -void parport_pc_write_fifo(struct parport *p, unsigned int v) +void parport_pc_write_fifo(struct parport *p, unsigned char v) { /* FIXME */ } -unsigned int parport_pc_read_fifo(struct parport *p) +unsigned char parport_pc_read_fifo(struct parport *p) { return 0; /* FIXME */ } @@ -184,22 +184,22 @@ parport_pc_write_econtrol(p, s->u.pc.ecr); } -unsigned int parport_pc_epp_read_block(struct parport *p, void *buf, unsigned int length) +size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length) { return 0; /* FIXME */ } -unsigned int parport_pc_epp_write_block(struct parport *p, void *buf, unsigned int length) +size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length) { return 0; /* FIXME */ } -unsigned int parport_pc_ecp_read_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle) +int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle) { return 0; /* FIXME */ } -unsigned int parport_pc_ecp_write_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle) +int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle) { return 0; /* FIXME */ } @@ -337,7 +337,7 @@ /* Only if supports ECP mode */ static int programmable_dma_support(struct parport *pb) { - int dma, oldstate = parport_pc_read_econtrol(pb); + unsigned char dma, oldstate = parport_pc_read_econtrol(pb); parport_pc_write_econtrol(pb, 0xe0); /* Configuration MODE */ @@ -375,7 +375,7 @@ static int parport_dma_probe(struct parport *pb) { int dma,retv; - int dsr,dsr_read; + unsigned char dsr,dsr_read; char *buff; retv = programmable_dma_support(pb); @@ -424,7 +424,7 @@ */ static int epp_clear_timeout(struct parport *pb) { - int r; + unsigned char r; if (!(parport_pc_read_status(pb) & 0x01)) return 1; @@ -470,7 +470,7 @@ */ static int parport_ECR_present(struct parport *pb) { - unsigned int r, octr = parport_pc_read_control(pb), + unsigned char r, octr = parport_pc_read_control(pb), oecr = parport_pc_read_econtrol(pb); r = parport_pc_read_control(pb); @@ -499,7 +499,8 @@ static int parport_ECP_supported(struct parport *pb) { - int i, oecr = parport_pc_read_econtrol(pb); + int i; + unsigned char oecr = parport_pc_read_econtrol(pb); /* If there is no ECR, we have no hope of supporting ECP. */ if (!(pb->modes & PARPORT_MODE_PCECR)) @@ -553,7 +554,8 @@ static int parport_ECPEPP_supported(struct parport *pb) { - int mode, oecr = parport_pc_read_econtrol(pb); + int mode; + unsigned char oecr = parport_pc_read_econtrol(pb); if (!(pb->modes & PARPORT_MODE_PCECR)) return 0; @@ -587,7 +589,8 @@ static int parport_PS2_supported(struct parport *pb) { - int ok = 0, octr = parport_pc_read_control(pb); + int ok = 0; + unsigned char octr = parport_pc_read_control(pb); epp_clear_timeout(pb); @@ -606,7 +609,8 @@ static int parport_ECPPS2_supported(struct parport *pb) { - int mode, oecr = parport_pc_read_econtrol(pb); + int mode; + unsigned char oecr = parport_pc_read_econtrol(pb); if (!(pb->modes & PARPORT_MODE_PCECR)) return 0; @@ -676,33 +680,25 @@ /* Only if supports ECP mode */ static int programmable_irq_support(struct parport *pb) { - int irq, oecr = parport_pc_read_econtrol(pb); + int irq, intrLine; + unsigned char oecr = parport_pc_read_econtrol(pb); + static const int lookup[8] = { + PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 + }; parport_pc_write_econtrol(pb,0xE0); /* Configuration MODE */ - irq = (parport_pc_read_configb(pb) >> 3) & 0x07; + intrLine = (parport_pc_read_configb(pb) >> 3) & 0x07; + irq = lookup[intrLine]; - switch(irq){ - case 2: - irq = 9; - break; - case 7: - irq = 5; - break; - case 0: - irq = PARPORT_IRQ_NONE; - break; - default: - irq += 7; - } - parport_pc_write_econtrol(pb, oecr); return irq; } static int irq_probe_ECP(struct parport *pb) { - int irqs, i, oecr = parport_pc_read_econtrol(pb); + int irqs, i; + unsigned char oecr = parport_pc_read_econtrol(pb); probe_irq_off(probe_irq_on()); /* Clear any interrupts */ irqs = open_intr_election(); @@ -725,7 +721,8 @@ */ static int irq_probe_EPP(struct parport *pb) { - int irqs, octr = parport_pc_read_control(pb); + int irqs; + unsigned char octr = parport_pc_read_control(pb); #ifndef ADVANCED_DETECT return PARPORT_IRQ_NONE; @@ -755,7 +752,8 @@ static int irq_probe_SPP(struct parport *pb) { - int irqs, octr = parport_pc_read_control(pb); + int irqs; + unsigned char octr = parport_pc_read_control(pb); #ifndef ADVANCED_DETECT return PARPORT_IRQ_NONE; diff -u --recursive --new-file v2.1.88/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c --- v2.1.88/linux/drivers/misc/parport_share.c Fri Jan 30 11:28:07 1998 +++ linux/drivers/misc/parport_share.c Tue Feb 24 22:40:44 1998 @@ -90,6 +90,7 @@ tmp->devices = tmp->cad = NULL; tmp->flags = 0; tmp->ops = ops; + tmp->number = portcount; spin_lock_init (&tmp->lock); tmp->name = kmalloc(15, GFP_KERNEL); diff -u --recursive --new-file v2.1.88/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.1.88/linux/drivers/net/dgrs.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/dgrs.c Tue Feb 24 22:08:01 1998 @@ -21,7 +21,7 @@ * When compiled as a loadable module, this driver can operate * the board as either a 4/6 port switch with a 5th or 7th port * that is a conventional NIC interface as far as the host is - * concerned, OR as 4/6 independant NICs. To select multi-NIC + * concerned, OR as 4/6 independent NICs. To select multi-NIC * mode, add "nicmode=1" on the insmod load line for the driver. * * This driver uses the "dev" common ethernet device structure diff -u --recursive --new-file v2.1.88/linux/drivers/sbus/audio/Makefile linux/drivers/sbus/audio/Makefile --- v2.1.88/linux/drivers/sbus/audio/Makefile Mon Jan 12 15:15:45 1998 +++ linux/drivers/sbus/audio/Makefile Tue Feb 24 22:43:58 1998 @@ -16,37 +16,37 @@ M_OBJS := ifeq ($(CONFIG_SPARCAUDIO),y) -M=y +SBUS_AUDIO=y else ifeq ($(CONFIG_SPARCAUDIO),m) - MM=y + SBUS_AUDIO_MODULE=y endif endif ifeq ($(CONFIG_SPARCAUDIO_AMD7930),y) -M=y +SBUS_AUDIO=y OX_OBJS += amd7930.o else ifeq ($(CONFIG_SPARCAUDIO_AMD7930),m) - MM=y + SBUS_AUDIO_MODULE=y MX_OBJS += amd7930.o endif endif ifeq ($(CONFIG_SPARCAUDIO_CS4231),y) -M=y +SBUS_AUDIO=y O_OBJS += cs4231.o else ifeq ($(CONFIG_SPARCAUDIO_CS4231),m) - MM=y + SBUS_AUDIO_MODULE=y M_OBJS += cs4231.o endif endif -ifdef M +ifdef SBUS_AUDIO OX_OBJS += audio.o else - ifdef MM + ifdef SBUS_AUDIO_MODULE MX_OBJS += audio.o endif endif diff -u --recursive --new-file v2.1.88/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c --- v2.1.88/linux/drivers/sbus/char/flash.c Mon Jan 12 15:15:45 1998 +++ linux/drivers/sbus/char/flash.c Tue Feb 24 22:08:01 1998 @@ -134,7 +134,7 @@ flash_llseek, flash_read, NULL, /* no write to the Flash, use mmap - * and play flash dependant tricks. + * and play flash dependent tricks. */ NULL, /* readdir */ NULL, /* poll */ diff -u --recursive --new-file v2.1.88/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.88/linux/drivers/scsi/Config.in Thu Feb 12 20:56:09 1998 +++ linux/drivers/scsi/Config.in Mon Feb 23 13:01:55 1998 @@ -123,7 +123,7 @@ # The actual configuration in any kernel release could change at any time as I hack it to # simulate various conditions that I am testing. # -if [ "`whoami`" = "eric" ]; then +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI fi if [ "$CONFIG_PPC" = "y" ]; then diff -u --recursive --new-file v2.1.88/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.1.88/linux/drivers/scsi/README.ncr53c8xx Mon Jan 12 15:05:27 1998 +++ linux/drivers/scsi/README.ncr53c8xx Tue Feb 24 22:08:01 1998 @@ -941,7 +941,7 @@ Change to linux source directory Configure with NCR53C7,8XX support = N Configure with NCR53C8XX support = Y (or m) - Make dependancies + Make dependencies Make the kernel (use make zdisk first) Make and install modules if you have configured with 'm' diff -u --recursive --new-file v2.1.88/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.1.88/linux/drivers/scsi/sr.c Mon Feb 23 18:12:08 1998 +++ linux/drivers/scsi/sr.c Sat Feb 21 12:34:38 1998 @@ -471,7 +471,7 @@ { spin_unlock_irqrestore(&io_request_lock, flags); scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); - /* scsi_ioctl may allow CURRENT to change, so start over. * + /* scsi_ioctl may allow CURRENT to change, so start over. */ SDev->was_reset = 0; continue; } diff -u --recursive --new-file v2.1.88/linux/drivers/sound/sound_firmware.c linux/drivers/sound/sound_firmware.c --- v2.1.88/linux/drivers/sound/sound_firmware.c Mon Dec 1 10:34:11 1997 +++ linux/drivers/sound/sound_firmware.c Mon Feb 23 10:25:15 1998 @@ -5,8 +5,6 @@ #include #include -static int errno; - static int do_mod_firmware_load(const char *fn, char **fp) { int fd; diff -u --recursive --new-file v2.1.88/linux/fs/affs/Changes linux/fs/affs/Changes --- v2.1.88/linux/fs/affs/Changes Tue Jan 6 13:33:29 1998 +++ linux/fs/affs/Changes Mon Feb 23 22:01:26 1998 @@ -28,6 +28,44 @@ Please direct bug reports to: hjw@zvw.de +Version 3.8 +----------- +Bill Hawes kindly reviewed the affs and sent me the +patches he did. They're marked (BH). Thanks, Bill! + +- Cleanup of error handling in read_super(). + Didn't release all ressources in case of an + error. (BH) + +- put_inode() releases the ext cache only if it's + no longer needed. (BH) + +- One set of dentry callbacks is enough. (BH) + +- Cleanup of error handling in namei.c. (BH) + +- Cleanup of error handling in file.c. (BH) + +- The original blocksize of the device is + restored when the fs is unmounted. (BH) + +- getblock() did not invalidate the key cache + when it allocated a new block. + +- Removed some unneccessary locks as Bill + suggested. + +- Simplified match_name(), changed all hashing + and case insensitive name comparisons to use + uppercase. This makes the tolower() routines + obsolete. + +- Added mount option 'mufs' to force muFS + uid/gid interpretation. + +- File mode changes were not updated on disk. + This was fixed before, but somehow got lost. + Version 3.7 ----------- diff -u --recursive --new-file v2.1.88/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c --- v2.1.88/linux/fs/affs/bitmap.c Tue Dec 2 22:25:07 1997 +++ linux/fs/affs/bitmap.c Mon Feb 23 22:01:26 1998 @@ -7,6 +7,7 @@ * block allocation, deallocation, calculation of free space. */ +#define DEBUG 0 #include #include #include diff -u --recursive --new-file v2.1.88/linux/fs/affs/file.c linux/fs/affs/file.c --- v2.1.88/linux/fs/affs/file.c Tue Jan 6 13:33:29 1998 +++ linux/fs/affs/file.c Mon Feb 23 22:01:26 1998 @@ -309,7 +309,7 @@ for (;;) { bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); - if (!bh) + if (!bh) return 0; index = seqnum_to_index(ext); if (index > inode->u.affs_i.i_ec->max_ext && @@ -360,57 +360,57 @@ static struct buffer_head * affs_getblock(struct inode *inode, s32 block) { - struct buffer_head *bh; - struct buffer_head *ebh; - struct buffer_head *pbh; + struct super_block *sb = inode->i_sb; + int ofs = sb->u.affs_sb.s_flags & SF_OFS; + int ext = block / AFFS_I2HSIZE(inode); + struct buffer_head *bh, *ebh, *pbh = NULL; struct key_cache *kc; s32 key, nkey; - int ext; int cf, j, pt; int index; - int ofs; + int err; pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block); if (block < 0) - return NULL; + goto out_fail; - /* Writers always use cache line 3. In almost all cases, files - * will be written by only one process at the same time, and - * they also will be written in strict sequential order. Thus - * there is not much sense in looking whether the key of the - * requested block is available - it won't be there. - */ - kc = &inode->u.affs_i.i_ec->kc[3]; - ofs = inode->i_sb->u.affs_sb.s_flags & SF_OFS; - ext = block / AFFS_I2HSIZE(inode); key = calc_key(inode,&ext); block -= ext * AFFS_I2HSIZE(inode); pt = ext ? T_LIST : T_SHORT; - pbh = NULL; + /* Key refers now to the last known extension block, + * ext is its sequence number (if 0, key refers to the + * header block), and block is the block number relative + * to the first block stored in that extension block. + */ for (;;) { /* Loop over header block and extension blocks */ + struct file_front *fdp; + bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); if (!bh) - return NULL; - if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j) || - cf != pt || j != ST_FILE) { - affs_error(inode->i_sb,"getblock","Inode %d is not a valid %s",key, - pt == T_SHORT ? "file header" : "extension block"); - affs_brelse(bh); - return NULL; + goto out_fail; + fdp = (struct file_front *) bh->b_data; + err = affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cf,&j); + if (err || cf != pt || j != ST_FILE) { + affs_error(sb, "getblock", + "Block %d is not a valid %s", key, + pt == T_SHORT ? "file header" : "ext block"); + goto out_free_bh; } j = be32_to_cpu(((struct file_front *)bh->b_data)->block_count); - cf = 0; - while (j < AFFS_I2HSIZE(inode) && j <= block) { + for (cf = 0; j < AFFS_I2HSIZE(inode) && j <= block; j++) { if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) { - if (j > 0) - pbh = affs_bread(inode->i_dev,cpu_to_be32(AFFS_BLOCK(bh->b_data,inode,j - 1)), - AFFS_I2BSIZE(inode)); - else + if (j > 0) { + s32 k = AFFS_BLOCK(bh->b_data, inode, + j - 1); + pbh = affs_bread(inode->i_dev, + be32_to_cpu(k), + AFFS_I2BSIZE(inode)); + } else pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock); if (!pbh) { - affs_error(inode->i_sb,"getblock", + affs_error(sb,"getblock", "Cannot get last block in file"); break; } @@ -419,46 +419,44 @@ if (!nkey) break; inode->u.affs_i.i_lastblock++; - lock_super(inode->i_sb); if (AFFS_BLOCK(bh->b_data,inode,j)) { - unlock_super(inode->i_sb); - affs_warning(inode->i_sb,"getblock","Block already allocated"); - affs_free_block(inode->i_sb,nkey); - j++; + affs_warning(sb,"getblock","Block already allocated"); + affs_free_block(sb,nkey); continue; } - unlock_super(inode->i_sb); AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey); if (ofs) { ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode)); if (!ebh) { - affs_error(inode->i_sb,"getblock", + affs_error(sb,"getblock", "Cannot get block %d",nkey); - affs_free_block(inode->i_sb,nkey); + affs_free_block(sb,nkey); AFFS_BLOCK(bh->b_data,inode,j) = 0; break; } DATA_FRONT(ebh)->primary_type = cpu_to_be32(T_DATA); DATA_FRONT(ebh)->header_key = cpu_to_be32(inode->i_ino); DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1); + affs_fix_checksum(AFFS_I2BSIZE(inode), + ebh->b_data, 5); + mark_buffer_dirty(ebh, 0); if (pbh) { DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24); DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey); affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5); mark_buffer_dirty(pbh,0); - mark_buffer_dirty(ebh,0); affs_brelse(pbh); } pbh = ebh; } - j++; cf = 1; } + /* N.B. May need to release pbh after here */ + if (cf) { if (pt == T_SHORT) - ((struct file_front *)bh->b_data)->first_data = - AFFS_BLOCK(bh->b_data,inode,0); - ((struct file_front *)bh->b_data)->block_count = cpu_to_be32(j); + fdp->first_data = AFFS_BLOCK(bh->b_data,inode,0); + fdp->block_count = cpu_to_be32(j); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); } @@ -469,52 +467,63 @@ break; } if (j < AFFS_I2HSIZE(inode)) { - affs_brelse(bh); - return NULL; + /* N.B. What about pbh here? */ + goto out_free_bh; } block -= AFFS_I2HSIZE(inode); key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension); if (!key) { key = affs_new_header(inode); - if (!key) { - affs_brelse(bh); - return NULL; - } + if (!key) + goto out_free_bh; ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); if (!ebh) { - affs_free_block(inode->i_sb,key); - return NULL; + /* N.B. must free bh here */ + goto out_free_block; } ((struct file_front *)ebh->b_data)->primary_type = cpu_to_be32(T_LIST); ((struct file_front *)ebh->b_data)->own_key = cpu_to_be32(key); FILE_END(ebh->b_data,inode)->secondary_type = cpu_to_be32(ST_FILE); FILE_END(ebh->b_data,inode)->parent = cpu_to_be32(inode->i_ino); affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5); + mark_buffer_dirty(ebh, 1); FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); affs_brelse(bh); bh = ebh; } - affs_brelse(bh); pt = T_LIST; ext++; - if ((index = seqnum_to_index(ext)) > inode->u.affs_i.i_ec->max_ext && - AFFS_ISINDEX(ext) && inode->u.affs_i.i_ec) { + index = seqnum_to_index(ext); + if (index > inode->u.affs_i.i_ec->max_ext && + AFFS_ISINDEX(ext)) { inode->u.affs_i.i_ec->ec[index] = key; inode->u.affs_i.i_ec->max_ext = index; } + affs_brelse(bh); + } + + /* Invalidate key cache */ + for (j = 0; j < 4; j++) { + kc = &inode->u.affs_i.i_ec->kc[j]; + kc->kc_last = -1; } - kc->kc_this_key = key; - kc->kc_this_seq = ext; - kc->kc_next_key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension); key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block)); affs_brelse(bh); if (!key) - return NULL; - - return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); + goto out_fail; + + bh = affs_bread(inode->i_dev, key, AFFS_I2BSIZE(inode)); + return bh; + +out_free_block: + affs_free_block(sb, key); +out_free_bh: + affs_brelse(bh); +out_fail: + return NULL; } static ssize_t @@ -592,14 +601,11 @@ inode->i_mode); return -EINVAL; } - if (!inode->u.affs_i.i_ec) { - if (alloc_ext_cache(inode)) { - return -ENOMEM; - } - } - if (filp->f_flags & O_APPEND) { + if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) + return -ENOMEM; + if (filp->f_flags & O_APPEND) pos = inode->i_size; - } else + else pos = *ppos; written = 0; blocksize = AFFS_I2BSIZE(inode); @@ -734,6 +740,23 @@ return written; } +/* Free any preallocated blocks */ +void +affs_free_prealloc(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + int block; + + pr_debug("AFFS: free_prealloc(ino=%lu)\n", inode->i_ino); + + while (inode->u.affs_i.i_pa_cnt) { + block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]; + inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1; + inode->u.affs_i.i_pa_cnt--; + affs_free_block(sb, block); + } +} + void affs_truncate(struct inode *inode) { @@ -764,12 +787,7 @@ } bh = affs_getblock(inode,first - 1); - while (inode->u.affs_i.i_pa_cnt) { /* Free any preallocated blocks */ - affs_free_block(inode->i_sb, - inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]); - inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1; - inode->u.affs_i.i_pa_cnt--; - } + affs_free_prealloc(inode); if (inode->u.affs_i.i_zone) { lock_super(inode->i_sb); zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone]; @@ -868,56 +886,66 @@ static int affs_release_file(struct inode *inode, struct file *filp) { + struct super_block *sb = inode->i_sb; struct affs_zone *zone; pr_debug("AFFS: release_file(ino=%lu)\n",inode->i_ino); if (filp->f_mode & 2) { /* Free preallocated blocks */ - while (inode->u.affs_i.i_pa_cnt) { - affs_free_block(inode->i_sb, - inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]); - inode->u.affs_i.i_pa_next &= AFFS_MAX_PREALLOC - 1; - inode->u.affs_i.i_pa_cnt--; - } + affs_free_prealloc(inode); if (inode->u.affs_i.i_zone) { - lock_super(inode->i_sb); - zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone]; + zone = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone]; if (zone->z_ino == inode->i_ino) zone->z_ino = 0; - unlock_super(inode->i_sb); } } return 0; } +/* + * Called only when we need to allocate the extension cache. + */ static int alloc_ext_cache(struct inode *inode) { s32 key; int i; + unsigned long cache_page; + int error = 0; pr_debug("AFFS: alloc_ext_cache(ino=%lu)\n",inode->i_ino); - lock_super(inode->i_sb); - if (!inode->u.affs_i.i_ec) { - inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL); - if (inode->u.affs_i.i_ec) { - /* We only have to initialize non-zero values. - * get_free_page() zeroed the page already. - */ - key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino; - inode->u.affs_i.i_ec->ec[0] = key; - for (i = 0; i < 4; i++) { - inode->u.affs_i.i_ec->kc[i].kc_this_key = key; - inode->u.affs_i.i_ec->kc[i].kc_last = -1; - } - } - } - unlock_super(inode->i_sb); - - if (!inode->u.affs_i.i_ec) { - affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed"); - return -ENOMEM; - } - return 0; + cache_page = get_free_page(GFP_KERNEL); + /* + * Check whether somebody else allocated it for us ... + */ + if (inode->u.affs_i.i_ec) + goto out_free; + if (!cache_page) + goto out_error; + + inode->u.affs_i.i_ec = (struct ext_cache *) cache_page; + /* We only have to initialize non-zero values. + * get_free_page() zeroed the page already. + */ + key = inode->u.affs_i.i_original; + if (!inode->u.affs_i.i_original) + key = inode->i_ino; + inode->u.affs_i.i_ec->ec[0] = key; + for (i = 0; i < 4; i++) { + inode->u.affs_i.i_ec->kc[i].kc_this_key = key; + inode->u.affs_i.i_ec->kc[i].kc_last = -1; + } +out: + return error; + +out_free: + if (cache_page) + free_page(cache_page); + goto out; + +out_error: + affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed"); + error = -ENOMEM; + goto out; } diff -u --recursive --new-file v2.1.88/linux/fs/affs/inode.c linux/fs/affs/inode.c --- v2.1.88/linux/fs/affs/inode.c Sun Jan 4 00:53:42 1998 +++ linux/fs/affs/inode.c Mon Feb 23 22:01:26 1998 @@ -229,36 +229,40 @@ error = inode_change_ok(inode,attr); if (error) - return error; + goto out; if (((attr->ia_valid & ATTR_UID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) || ((attr->ia_valid & ATTR_GID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) || ((attr->ia_valid & ATTR_MODE) && - (inode->i_sb->u.affs_sb.s_flags & (SF_SETMODE | SF_IMMUTABLE)))) - error = -EPERM; - - if (error) - return (inode->i_sb->u.affs_sb.s_flags & SF_QUIET) ? 0 : error; + (inode->i_sb->u.affs_sb.s_flags & (SF_SETMODE | SF_IMMUTABLE)))) { + if (!(inode->i_sb->u.affs_sb.s_flags & SF_QUIET)) + error = -EPERM; + goto out; + } if (attr->ia_valid & ATTR_MODE) inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode); - inode_setattr(inode,attr); - - return 0; + inode_setattr(inode, attr); + mark_inode_dirty(inode); + error = 0; +out: + return error; } void affs_put_inode(struct inode *inode) { - pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink); - lock_super(inode->i_sb); - if (inode->u.affs_i.i_ec) { - pr_debug("AFFS: freeing ext cache\n"); - free_page((unsigned long)inode->u.affs_i.i_ec); - inode->u.affs_i.i_ec = NULL; + pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", + inode->i_ino,inode->i_nlink); + if (inode->i_count == 1) { + unsigned long cache_page = (unsigned long) inode->u.affs_i.i_ec; + if (cache_page) { + pr_debug("AFFS: freeing ext cache\n"); + inode->u.affs_i.i_ec = NULL; + free_page(cache_page); + } } - unlock_super(inode->i_sb); } void diff -u --recursive --new-file v2.1.88/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v2.1.88/linux/fs/affs/namei.c Thu Feb 12 20:56:10 1998 +++ linux/fs/affs/namei.c Mon Feb 23 22:01:26 1998 @@ -21,23 +21,17 @@ #include -/* Simple toupper()/tolower() for DOS\1 */ +/* Simple toupper() for DOS\1 */ -static inline unsigned int +static unsigned int affs_toupper(unsigned int ch) { return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch; } -static inline unsigned int -affs_tolower(unsigned int ch) -{ - return ch >= 'A' && ch <= 'Z' ? ch + ('a' - 'A') : ch; -} +/* International toupper() for DOS\3 ("international") */ -/* International toupper()/tolower() for DOS\3 ("international") */ - -static inline unsigned int +static unsigned int affs_intl_toupper(unsigned int ch) { return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0 @@ -45,23 +39,8 @@ ch - ('a' - 'A') : ch; } -static inline unsigned int -affs_intl_tolower(unsigned int ch) -{ - return (ch >= 'A' && ch <= 'Z') || (ch >= 0xC0 - && ch <= 0xDE && ch != 0xD7) ? - ch + ('a' - 'A') : ch; -} - -/* We need 2 sets of dentry operations, since we cannot - * determine the fs flavour in the callback routines. - */ - static int affs_hash_dentry(struct dentry *, struct qstr *); static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); -static int affs_hash_dentry_intl(struct dentry *, struct qstr *); -static int affs_compare_dentry_intl(struct dentry *, struct qstr *, struct qstr *); - struct dentry_operations affs_dentry_operations = { NULL, /* d_validate */ affs_hash_dentry, /* d_hash */ @@ -69,24 +48,25 @@ NULL /* d_delete */ }; -struct dentry_operations affs_dentry_operations_intl = { - NULL, /* d_validate */ - affs_hash_dentry_intl, /* d_hash */ - affs_compare_dentry_intl, /* d_compare */ - NULL /* d_delete */ -}; - +/* + * Note: the dentry argument is the parent dentry. + */ static int affs_hash_dentry(struct dentry *dentry, struct qstr *qstr) { + unsigned int (*toupper)(unsigned int) = affs_toupper; unsigned long hash; int i; if ((i = affs_check_name(qstr->name,qstr->len))) return i; + + /* Check whether to use the international 'toupper' routine */ + if (AFFS_I2FSTYPE(dentry->d_inode)) + toupper = affs_intl_toupper; hash = init_name_hash(); for (i = 0; i < qstr->len && i < 30; i++) - hash = partial_name_hash(affs_tolower(qstr->name[i]),hash); + hash = partial_name_hash(toupper(qstr->name[i]), hash); qstr->hash = end_name_hash(hash); return 0; @@ -95,6 +75,9 @@ static int affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) { + unsigned int (*toupper)(unsigned int) = affs_toupper; + int alen = a->len; + int blen = b->len; int i; /* 'a' is the qstr of an already existing dentry, so the name @@ -107,45 +90,19 @@ /* If the names are longer than the allowed 30 chars, * the excess is ignored, so their length may differ. */ - - if ((a->len < 30 || b->len < 30) && a->len != b->len) + if (alen > 30) + alen = 30; + if (blen > 30) + blen = 30; + if (alen != blen) return 1; - for (i = 0; i < a->len && i < 30; i++) - if (affs_tolower(a->name[i]) != affs_tolower(b->name[i])) - return 1; - - return 0; -} - -static int -affs_hash_dentry_intl(struct dentry *dentry, struct qstr *qstr) -{ - unsigned long hash; - int i; + /* Check whether to use the international 'toupper' routine */ + if (AFFS_I2FSTYPE(dentry->d_inode)) + toupper = affs_intl_toupper; - if ((i = affs_check_name(qstr->name,qstr->len))) - return i; - hash = init_name_hash(); - for (i = 0; i < qstr->len && i < 30; i++) - hash = partial_name_hash(affs_intl_tolower(qstr->name[i]),hash); - qstr->hash = end_name_hash(hash); - - return 0; -} - -static int -affs_compare_dentry_intl(struct dentry *dentry, struct qstr *a, struct qstr *b) -{ - int i; - - if (affs_check_name(b->name,b->len)) - return 1; - if ((a->len < 30 || b->len < 30) && a->len != b->len) - return 1; - - for (i = 0; i < a->len && i < 30; i++) - if (affs_intl_tolower(a->name[i]) != affs_intl_tolower(b->name[i])) + for (i = 0; i < alen; i++) + if (toupper(a->name[i]) != toupper(b->name[i])) return 1; return 0; @@ -158,6 +115,9 @@ static int affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl) { + unsigned int (*toupper)(unsigned int) = intl ? affs_intl_toupper : affs_toupper; + int i; + if (!compare) return 0; @@ -171,21 +131,9 @@ return 1; if (dlen != len) return 0; - if (intl) { - while (dlen--) { - if (affs_intl_toupper(*name) != affs_intl_toupper(*compare)) - return 0; - name++; - compare++; - } - } else { - while (dlen--) { - if (affs_toupper(*name) != affs_toupper(*compare)) - return 0; - name++; - compare++; - } - } + for (i = 0; i < len; i++) + if (toupper(name[i]) != toupper(compare[i])) + return 0; return 1; } @@ -211,23 +159,22 @@ affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino) { struct buffer_head *bh; - int intl; + int intl = AFFS_I2FSTYPE(dir); s32 key; const char *name = dentry->d_name.name; int namelen = dentry->d_name.len; pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name); - intl = AFFS_I2FSTYPE(dir); - bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); + bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); if (!bh) return NULL; - if (affs_match(name,namelen,".",1,intl)) { + if (namelen == 1 && name[0] == '.') { *ino = dir->i_ino; return bh; } - if (affs_match(name,namelen,"..",2,intl)) { + if (namelen == 2 && name[0] == '.' && name[1] == '.') { *ino = affs_parent_ino(dir); return bh; } @@ -239,10 +186,9 @@ int cnamelen; affs_brelse(bh); - if (key == 0) { - bh = NULL; + bh = NULL; + if (key == 0) break; - } bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir)); if (!bh) break; @@ -274,8 +220,7 @@ if (!inode) return -EACCES; } - dentry->d_op = AFFS_I2FSTYPE(dir) ? &affs_dentry_operations_intl - : &affs_dentry_operations; + dentry->d_op = &affs_dentry_operations; d_add(dentry,inode); return 0; } @@ -291,10 +236,7 @@ pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name); - bh = NULL; retval = -ENOENT; - if (!dir) - goto unlink_done; if (!(bh = affs_find_entry(dir,dentry,&ino))) goto unlink_done; @@ -312,8 +254,10 @@ inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(inode); - retval = 0; d_delete(dentry); + mark_inode_dirty(dir); + retval = 0; + unlink_done: affs_brelse(bh); return retval; @@ -328,11 +272,10 @@ pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len, dentry->d_name.name,mode); - if (!dir) - return -ENOENT; + error = -ENOSPC; inode = affs_new_inode(dir); if (!inode) - return -ENOSPC; + goto out; pr_debug(" -- ino=%lu\n",inode->i_ino); if (dir->i_sb->u.affs_sb.s_flags & SF_OFS) @@ -341,19 +284,22 @@ inode->i_op = &affs_file_inode_operations; error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE); - if (error) { - inode->i_nlink = 0; - mark_inode_dirty(inode); - iput(inode); - return error; - } + if (error) + goto out_iput; inode->i_mode = mode; inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); + d_instantiate(dentry,inode); + mark_inode_dirty(inode); dir->i_version = ++event; mark_inode_dirty(dir); - d_instantiate(dentry,inode); +out: + return error; - return 0; +out_iput: + inode->i_nlink = 0; + mark_inode_dirty(inode); + iput(inode); + goto out; } int @@ -365,25 +311,29 @@ pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name,mode); + error = -ENOSPC; inode = affs_new_inode(dir); if (!inode) - return -ENOSPC; + goto out; inode->i_op = &affs_dir_inode_operations; error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR); - if (error) { - inode->i_nlink = 0; - mark_inode_dirty(inode); - iput(inode); - return error; - } + if (error) + goto out_iput; inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask); inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); + d_instantiate(dentry,inode); + mark_inode_dirty(inode); dir->i_version = ++event; mark_inode_dirty(dir); - d_instantiate(dentry,inode); +out: + return error; - return 0; +out_iput: + inode->i_nlink = 0; + mark_inode_dirty(inode); + iput(inode); + goto out; } static int @@ -399,24 +349,18 @@ int affs_rmdir(struct inode *dir, struct dentry *dentry) { + struct inode *inode = dentry->d_inode; int retval; unsigned long ino; - struct inode *inode; struct buffer_head *bh; pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name); - inode = NULL; - bh = NULL; retval = -ENOENT; - if (!dir) - goto rmdir_done; if (!(bh = affs_find_entry(dir,dentry,&ino))) goto rmdir_done; - inode = dentry->d_inode; - retval = -EPERM; if (current->fsuid != inode->i_uid && current->fsuid != dir->i_uid && !fsuser()) @@ -425,31 +369,31 @@ goto rmdir_done; if (inode == dir) /* we may not delete ".", but "../dir" is ok */ goto rmdir_done; - if (!S_ISDIR(inode->i_mode)) { - retval = -ENOTDIR; + retval = -ENOTDIR; + if (!S_ISDIR(inode->i_mode)) goto rmdir_done; - } - down(&inode->i_sem); - if (dentry->d_count > 1) { + /* + * Make sure the directory is empty and the dentry isn't busy. + */ + if (dentry->d_count > 1) shrink_dcache_parent(dentry); - } - up(&inode->i_sem); - if (!empty_dir(bh,AFFS_I2HSIZE(inode))) { - retval = -ENOTEMPTY; + retval = -ENOTEMPTY; + if (!empty_dir(bh,AFFS_I2HSIZE(inode))) goto rmdir_done; - } - if (inode->i_count > 1) { - retval = -EBUSY; + retval = -EBUSY; + if (dentry->d_count > 1) goto rmdir_done; - } + if ((retval = affs_remove_header(bh,inode)) < 0) goto rmdir_done; inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; retval = 0; + mark_inode_dirty(dir); mark_inode_dirty(inode); d_delete(dentry); + rmdir_done: affs_brelse(bh); return retval; @@ -462,27 +406,25 @@ struct inode *inode; char *p; unsigned long tmp; - int i, maxlen; + int i, maxlen, error; char c, lc; pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name,symname); maxlen = 4 * AFFS_I2HSIZE(dir) - 1; + error = -ENOSPC; inode = affs_new_inode(dir); if (!inode) - return -ENOSPC; + goto out; inode->i_op = &affs_symlink_inode_operations; inode->i_mode = S_IFLNK | 0777; inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); + error = -EIO; bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); - if (!bh) { - inode->i_nlink = 0; - mark_inode_dirty(inode); - iput(inode); - return -EIO; - } + if (!bh) + goto out_iput; i = 0; p = ((struct slink_front *)bh->b_data)->symname; lc = '/'; @@ -514,25 +456,30 @@ mark_buffer_dirty(bh,1); affs_brelse(bh); mark_inode_dirty(inode); + + /* N.B. This test shouldn't be necessary ... dentry must be negative */ + error = -EEXIST; bh = affs_find_entry(dir,dentry,&tmp); - if (bh) { - inode->i_nlink = 0; - iput(inode); - affs_brelse(bh); - return -EEXIST; - } - i = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK); - if (i) { - inode->i_nlink = 0; - mark_inode_dirty(inode); - iput(inode); - affs_brelse(bh); - return i; - } - dir->i_version = ++event; + if (bh) + goto out_release; + /* N.B. Shouldn't we add the entry before dirtying the buffer? */ + error = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK); + if (error) + goto out_release; d_instantiate(dentry,inode); - - return 0; + dir->i_version = ++event; + mark_inode_dirty(dir); + +out: + return error; + +out_release: + affs_brelse(bh); +out_iput: + inode->i_nlink = 0; + mark_inode_dirty(inode); + iput(inode); + goto out; } int @@ -547,6 +494,7 @@ pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino, (int)dentry->d_name.len,dentry->d_name.name); + /* N.B. Do we need this test? The dentry must be negative ... */ bh = affs_find_entry(dir,dentry,&i); if (bh) { affs_brelse(bh); @@ -556,8 +504,9 @@ affs_warning(dir->i_sb,"link","Impossible link to link"); return -EINVAL; } + error = -ENOSPC; if (!(inode = affs_new_inode(dir))) - return -ENOSPC; + goto out; inode->i_op = oldinode->i_op; inode->u.affs_i.i_protect = mode_to_prot(oldinode->i_mode); @@ -573,6 +522,7 @@ inode->i_nlink = 0; else { dir->i_version = ++event; + mark_inode_dirty(dir); mark_inode_dirty(oldinode); oldinode->i_count++; d_instantiate(dentry,oldinode); @@ -580,6 +530,7 @@ mark_inode_dirty(inode); iput(inode); +out: return error; } @@ -600,7 +551,7 @@ new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode); if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len))) - return retval; + goto out; new_bh = NULL; retval = -ENOENT; @@ -630,8 +581,10 @@ if (!S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (is_subdir(new_dentry,old_dentry)) + if (is_subdir(new_dentry, old_dentry)) goto end_rename; + if (new_dentry->d_count > 1) + shrink_dcache_parent(new_dentry); retval = -ENOTEMPTY; if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode))) goto end_rename; @@ -644,7 +597,7 @@ if (new_inode && !S_ISDIR(new_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (is_subdir(new_dentry,old_dentry)) + if (is_subdir(new_dentry, old_dentry)) goto end_rename; if (affs_parent_ino(old_inode) != old_dir->i_ino) goto end_rename; @@ -681,6 +634,6 @@ end_rename: affs_brelse(old_bh); affs_brelse(new_bh); - +out: return retval; } diff -u --recursive --new-file v2.1.88/linux/fs/affs/super.c linux/fs/affs/super.c --- v2.1.88/linux/fs/affs/super.c Tue Jan 6 13:33:29 1998 +++ linux/fs/affs/super.c Mon Feb 23 22:01:26 1998 @@ -62,12 +62,10 @@ kfree(sb->u.affs_sb.s_bitmap); affs_brelse(sb->u.affs_sb.s_root_bh); - /* I'm not happy with this. It would be better to save the previous - * value of this devices blksize_size[][] in the super block and - * restore it here, but with the affs superblock being quite large - * already ... + /* + * Restore the previous value of this device's blksize_size[][] */ - set_blocksize(sb->s_dev,BLOCK_SIZE); + set_blocksize(sb->s_dev, sb->u.affs_sb.s_blksize); sb->s_dev = 0; unlock_super(sb); @@ -100,7 +98,7 @@ } else sb->s_dirt = 0; - pr_debug("AFFS: write_super() at %d, clean=%d\n",CURRENT_TIME,clean); + pr_debug("AFFS: write_super() at %lu, clean=%d\n", CURRENT_TIME, clean); } static struct super_operations affs_sops = { @@ -119,7 +117,7 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root, int *blocksize, char **prefix, char *volume, unsigned long *mount_opts) { - char *this_char, *value; + char *this_char, *value, *optn; int f; /* Fill in defaults */ @@ -138,18 +136,18 @@ f = 0; if ((value = strchr(this_char,'=')) != NULL) *value++ = 0; - if (!strcmp(this_char,"protect")) { - if (value) { - printk("AFFS: Option protect does not take an argument\n"); - return 0; - } + if ((optn = "protect") && !strcmp(this_char, optn)) { + if (value) + goto out_inv_arg; *mount_opts |= SF_IMMUTABLE; - } else if (!strcmp(this_char,"verbose")) { - if (value) { - printk("AFFS: Option verbose does not take an argument\n"); - return 0; - } + } else if ((optn = "verbose") && !strcmp(this_char, optn)) { + if (value) + goto out_inv_arg; *mount_opts |= SF_VERBOSE; + } else if ((optn = "mufs") && !strcmp(this_char, optn)) { + if (value) + goto out_inv_arg; + *mount_opts |= SF_MUFS; } else if ((f = !strcmp(this_char,"setuid")) || !strcmp(this_char,"setgid")) { if (value) { if (!*value) { @@ -165,55 +163,51 @@ } } } else if (!strcmp(this_char,"prefix")) { - if (!value || !*value) { - printk("AFFS: The prefix option requires an argument\n"); - return 0; - } - if (*prefix) /* Free any previous prefix */ + optn = "prefix"; + if (!value || !*value) + goto out_no_arg; + if (*prefix) { /* Free any previous prefix */ kfree(*prefix); + *prefix = NULL; + } *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL); if (!*prefix) return 0; strcpy(*prefix,value); *mount_opts |= SF_PREFIX; } else if (!strcmp(this_char,"volume")) { - if (!value || !*value) { - printk("AFFS: The volume option requires an argument\n"); - return 0; - } + optn = "volume"; + if (!value || !*value) + goto out_no_arg; if (strlen(value) > 30) value[30] = 0; strncpy(volume,value,30); } else if (!strcmp(this_char,"mode")) { - if (!value || !*value) { - printk("AFFS: The mode option requires an argument\n"); - return 0; - } + optn = "mode"; + if (!value || !*value) + goto out_no_arg; *mode = simple_strtoul(value,&value,8) & 0777; if (*value) return 0; *mount_opts |= SF_SETMODE; } else if (!strcmp(this_char,"reserved")) { - if (!value || !*value) { - printk("AFFS: The reserved option requires an argument\n"); - return 0; - } + optn = "reserved"; + if (!value || !*value) + goto out_no_arg; *reserved = simple_strtoul(value,&value,0); if (*value) return 0; } else if (!strcmp(this_char,"root")) { - if (!value || !*value) { - printk("AFFS: The root option requires an argument\n"); - return 0; - } + optn = "root"; + if (!value || !*value) + goto out_no_arg; *root = simple_strtoul(value,&value,0); if (*value) return 0; } else if (!strcmp(this_char,"bs")) { - if (!value || !*value) { - printk("AFFS: The bs option requires an argument\n"); - return 0; - } + optn = "bs"; + if (!value || !*value) + goto out_no_arg; *blocksize = simple_strtoul(value,&value,0); if (*value) return 0; @@ -234,6 +228,13 @@ } } return 1; + +out_no_arg: + printk("AFFS: The %s option requires an argument\n", optn); + return 0; +out_inv_arg: + printk("AFFS: Option %s does not take an argument\n", optn); + return 0; } /* This function definitely needs to be split up. Some fine day I'll @@ -241,14 +242,14 @@ */ static struct super_block * -affs_read_super(struct super_block *s,void *data, int silent) +affs_read_super(struct super_block *s, void *data, int silent) { struct buffer_head *bh = NULL; struct buffer_head *bb; struct inode *root_inode; kdev_t dev = s->s_dev; s32 root_block; - int size; + int blocks, size, blocksize; u32 chksum; u32 *bm; s32 ptype, stype; @@ -256,7 +257,6 @@ int num_bm; int i, j; s32 key; - int blocksize; uid_t uid; gid_t gid; int reserved; @@ -268,57 +268,55 @@ pr_debug("affs_read_super(%s)\n",data ? (const char *)data : "no options"); MOD_INC_USE_COUNT; - - s->u.affs_sb.s_prefix = NULL; - if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, - &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) { - s->s_dev = 0; - printk(KERN_ERR "AFFS: Error parsing options\n"); - MOD_DEC_USE_COUNT; - return NULL; - } lock_super(s); - - /* Get the size of the device in 512-byte blocks. - * If we later see that the partition uses bigger - * blocks, we will have to change it. - */ - - size = blksize_size[MAJOR(dev)][MINOR(dev)]; - size = (size ? size : BLOCK_SIZE) / 512 * blk_size[MAJOR(dev)][MINOR(dev)]; - + s->s_magic = AFFS_SUPER_MAGIC; + s->s_op = &affs_sops; s->u.affs_sb.s_bitmap = NULL; s->u.affs_sb.s_root_bh = NULL; + s->u.affs_sb.s_prefix = NULL; + s->u.affs_sb.s_hashsize= 0; + + if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, + &blocksize,&s->u.affs_sb.s_prefix, + s->u.affs_sb.s_volume, &mount_flags)) + goto out_bad_opts; + /* N.B. after this point s_prefix must be released */ + s->u.affs_sb.s_flags = mount_flags; s->u.affs_sb.s_mode = i; s->u.affs_sb.s_uid = uid; s->u.affs_sb.s_gid = gid; + s->u.affs_sb.s_reserved= reserved; - if (size == 0) { - s->s_dev = 0; - unlock_super(s); - printk(KERN_ERR "AFFS: Could not determine device size\n"); - goto out; - } - s->u.affs_sb.s_partition_size = size; - s->u.affs_sb.s_reserved = reserved; + /* Get the size of the device in 512-byte blocks. + * If we later see that the partition uses bigger + * blocks, we will have to change it. + */ + + blocks = blk_size[MAJOR(dev)][MINOR(dev)]; + if (blocks == 0) + goto out_bad_size; + s->u.affs_sb.s_blksize = blksize_size[MAJOR(dev)][MINOR(dev)]; + if (!s->u.affs_sb.s_blksize) + s->u.affs_sb.s_blksize = BLOCK_SIZE; + size = (s->u.affs_sb.s_blksize / 512) * blocks; + pr_debug("AFFS: initial blksize=%d, blocks=%d\n", + s->u.affs_sb.s_blksize, blocks); /* Try to find root block. Its location depends on the block size. */ - s->u.affs_sb.s_hashsize = 0; + i = 512; + j = 4096; if (blocksize > 0) { - i = blocksize; - j = blocksize; - } else { - i = 512; - j = 4096; + i = j = blocksize; + size = size / (blocksize / 512); } for (blocksize = i, key = 0; blocksize <= j; blocksize <<= 1, size >>= 1) { + s->u.affs_sb.s_root_block = root_block; if (root_block < 0) s->u.affs_sb.s_root_block = (reserved + size - 1) / 2; - else - s->u.affs_sb.s_root_block = root_block; - set_blocksize(dev,blocksize); + pr_debug("AFFS: setting blocksize to %d\n", blocksize); + set_blocksize(dev, blocksize); /* The root block location that was calculated above is not * correct if the partition size is an odd number of 512- @@ -331,35 +329,31 @@ * block behind the calculated one. So we check this one, too. */ for (num_bm = 0; num_bm < 2; num_bm++) { - pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %u, " - "size=%d blocks, %d reserved\n",kdevname(dev),blocksize, - s->u.affs_sb.s_root_block + num_bm,size,reserved); - bh = affs_bread(dev,s->u.affs_sb.s_root_block + num_bm,blocksize); - if (!bh) { - printk(KERN_ERR "AFFS: Cannot read root block\n"); - goto out; - } + pr_debug("AFFS: Dev %s, trying root=%u, bs=%d, " + "size=%d, reserved=%d\n", + kdevname(dev), + s->u.affs_sb.s_root_block + num_bm, + blocksize, size, reserved); + bh = affs_bread(dev, s->u.affs_sb.s_root_block + num_bm, + blocksize); + if (!bh) + continue; if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) && ptype == T_SHORT && stype == ST_ROOT) { s->s_blocksize = blocksize; s->u.affs_sb.s_hashsize = blocksize / 4 - 56; s->u.affs_sb.s_root_block += num_bm; key = 1; - break; + goto got_root; } + affs_brelse(bh); + bh = NULL; } - if (key) - break; - affs_brelse(bh); - bh = NULL; - } - if (!key) { - affs_brelse(bh); - if (!silent) - printk(KERN_ERR "AFFS: Cannot find a valid root block on device %s\n", - kdevname(dev)); - goto out; } + goto out_no_valid_block; + + /* N.B. after this point bh must be released */ +got_root: root_block = s->u.affs_sb.s_root_block; s->u.affs_sb.s_partition_size = size; @@ -369,59 +363,54 @@ /* Find out which kind of FS we have */ bb = affs_bread(dev,0,s->s_blocksize); - if (bb) { - chksum = be32_to_cpu(*(u32 *)bb->b_data); - - /* Dircache filesystems are compatible with non-dircache ones - * when reading. As long as they aren't supported, writing is - * not recommended. - */ - if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS - || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) { - printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n", - kdevname(dev)); - s->s_flags |= MS_RDONLY; - s->u.affs_sb.s_flags |= SF_READONLY; - } - switch (chksum) { - case MUFS_FS: - case MUFS_INTLFFS: - s->u.affs_sb.s_flags |= SF_MUFS; - /* fall thru */ - case FS_INTLFFS: - s->u.affs_sb.s_flags |= SF_INTL; - break; - case MUFS_DCFFS: - case MUFS_FFS: - s->u.affs_sb.s_flags |= SF_MUFS; - break; - case FS_DCFFS: - case FS_FFS: - break; - case MUFS_OFS: - s->u.affs_sb.s_flags |= SF_MUFS; - /* fall thru */ - case FS_OFS: - s->u.affs_sb.s_flags |= SF_OFS; - break; - case MUFS_DCOFS: - case MUFS_INTLOFS: - s->u.affs_sb.s_flags |= SF_MUFS; - case FS_DCOFS: - case FS_INTLOFS: - s->u.affs_sb.s_flags |= SF_INTL | SF_OFS; - break; - default: - printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n", - kdevname(dev),chksum); - affs_brelse(bb); - goto out; - } - affs_brelse(bb); - } else { - printk(KERN_ERR "AFFS: Cannot read boot block\n"); - goto out; + if (!bb) + goto out_no_root_block; + chksum = be32_to_cpu(*(u32 *)bb->b_data); + affs_brelse(bb); + + /* Dircache filesystems are compatible with non-dircache ones + * when reading. As long as they aren't supported, writing is + * not recommended. + */ + if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS + || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) { + printk(KERN_NOTICE "AFFS: Dircache FS - mounting %s read only\n", + kdevname(dev)); + s->s_flags |= MS_RDONLY; + s->u.affs_sb.s_flags |= SF_READONLY; + } + switch (chksum) { + case MUFS_FS: + case MUFS_INTLFFS: + s->u.affs_sb.s_flags |= SF_MUFS; + /* fall thru */ + case FS_INTLFFS: + s->u.affs_sb.s_flags |= SF_INTL; + break; + case MUFS_DCFFS: + case MUFS_FFS: + s->u.affs_sb.s_flags |= SF_MUFS; + break; + case FS_DCFFS: + case FS_FFS: + break; + case MUFS_OFS: + s->u.affs_sb.s_flags |= SF_MUFS; + /* fall thru */ + case FS_OFS: + s->u.affs_sb.s_flags |= SF_OFS; + break; + case MUFS_DCOFS: + case MUFS_INTLOFS: + s->u.affs_sb.s_flags |= SF_MUFS; + case FS_DCOFS: + case FS_INTLOFS: + s->u.affs_sb.s_flags |= SF_INTL | SF_OFS; + break; + default: + goto out_unknown_fs; } + if (mount_flags & SF_VERBOSE) { chksum = cpu_to_be32(chksum); printk(KERN_NOTICE "AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n", @@ -430,14 +419,14 @@ (char *)&chksum,((char *)&chksum)[3] + '0',blocksize); } - s->s_magic = AFFS_SUPER_MAGIC; s->s_flags |= MS_NODEV | MS_NOSUID; /* Keep super block in cache */ - if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) { - printk(KERN_ERR "AFFS: Cannot read root block\n"); - goto out; - } + bb = affs_bread(dev,root_block,s->s_blocksize); + if (!bb) + goto out_no_root_block; + s->u.affs_sb.s_root_bh = bb; + /* N.B. after this point s_root_bh must be released */ /* Allocate space for bitmaps, zones and others */ @@ -448,11 +437,10 @@ az_no * sizeof(struct affs_alloc_zone) + MAX_ZONES * sizeof(struct affs_zone); pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype); - if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) { - printk(KERN_ERR "AFFS: Not enough memory\n"); - goto out; - } + if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype, GFP_KERNEL))) + goto out_no_bitmap; memset(s->u.affs_sb.s_bitmap,0,ptype); + /* N.B. after the point s_bitmap must be released */ s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm]; s->u.affs_sb.s_alloc = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES]; @@ -490,91 +478,79 @@ s->u.affs_sb.s_flags |= SF_READONLY; continue; } - bb = affs_bread(s->s_dev,be32_to_cpu(bm[i]),s->s_blocksize); - if (bb) { - if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) && - !(s->s_flags & MS_RDONLY)) { - printk(KERN_WARNING "AFFS: Bitmap (%d,key=%u) invalid - " - "mounting %s read only.\n",mapidx,be32_to_cpu(bm[i]), - kdevname(dev)); - s->s_flags |= MS_RDONLY; - s->u.affs_sb.s_flags |= SF_READONLY; - } - /* Mark unused bits in the last word as allocated */ - if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */ - ptype = size / 32 + 1; /* word number */ - key = size & 0x1F; /* used bits */ - if (key && !(s->s_flags & MS_RDONLY)) { - chksum = cpu_to_be32(0x7FFFFFFF >> (31 - key)); - ((u32 *)bb->b_data)[ptype] &= chksum; - affs_fix_checksum(s->s_blocksize,bb->b_data,0); - mark_buffer_dirty(bb,1); - bmalt = 1; - } - ptype = (size + 31) & ~0x1F; - size = 0; - s->u.affs_sb.s_flags |= SF_BM_VALID; - } else { - ptype = s->s_blocksize * 8 - 32; - size -= ptype; - } - s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset; - s->u.affs_sb.s_bitmap[mapidx].bm_bh = NULL; - s->u.affs_sb.s_bitmap[mapidx].bm_key = be32_to_cpu(bm[i]); - s->u.affs_sb.s_bitmap[mapidx].bm_count = 0; - offset += ptype; - - for (j = 0; ptype > 0; j++, az_no++, ptype -= key) { - key = MIN(ptype,AFFS_ZONE_SIZE); /* size in bits */ - s->u.affs_sb.s_alloc[az_no].az_size = key / 32; - s->u.affs_sb.s_alloc[az_no].az_free = - affs_count_free_bits(key / 8,bb->b_data + - j * (AFFS_ZONE_SIZE / 8) + 4); + bb = affs_bread(dev,be32_to_cpu(bm[i]),s->s_blocksize); + if (!bb) + goto out_no_read_bm; + if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) && + !(s->s_flags & MS_RDONLY)) { + printk(KERN_WARNING "AFFS: Bitmap (%d,key=%u) invalid - " + "mounting %s read only.\n",mapidx,be32_to_cpu(bm[i]), + kdevname(dev)); + s->s_flags |= MS_RDONLY; + s->u.affs_sb.s_flags |= SF_READONLY; + } + /* Mark unused bits in the last word as allocated */ + if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */ + ptype = size / 32 + 1; /* word number */ + key = size & 0x1F; /* used bits */ + if (key && !(s->s_flags & MS_RDONLY)) { + chksum = cpu_to_be32(0x7FFFFFFF >> (31 - key)); + ((u32 *)bb->b_data)[ptype] &= chksum; + affs_fix_checksum(s->s_blocksize,bb->b_data,0); + mark_buffer_dirty(bb,1); + bmalt = 1; } - affs_brelse(bb); + ptype = (size + 31) & ~0x1F; + size = 0; + s->u.affs_sb.s_flags |= SF_BM_VALID; } else { - printk(KERN_ERR "AFFS: Cannot read bitmap\n"); - goto out; + ptype = s->s_blocksize * 8 - 32; + size -= ptype; + } + s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset; + s->u.affs_sb.s_bitmap[mapidx].bm_bh = NULL; + s->u.affs_sb.s_bitmap[mapidx].bm_key = be32_to_cpu(bm[i]); + s->u.affs_sb.s_bitmap[mapidx].bm_count = 0; + offset += ptype; + + for (j = 0; ptype > 0; j++, az_no++, ptype -= key) { + key = MIN(ptype,AFFS_ZONE_SIZE); /* size in bits */ + s->u.affs_sb.s_alloc[az_no].az_size = key / 32; + s->u.affs_sb.s_alloc[az_no].az_free = + affs_count_free_bits(key / 8,bb->b_data + + j * (AFFS_ZONE_SIZE / 8) + 4); } + affs_brelse(bb); } key = be32_to_cpu(bm[stype]); /* Next block of bitmap pointers */ ptype = 0; stype = s->s_blocksize / 4 - 1; affs_brelse(bh); + bh = NULL; if (key) { - if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) { - printk(KERN_ERR "AFFS: Cannot read bitmap extension\n"); - goto out; - } - } else - bh = NULL; - } - if (mapidx < num_bm) { - printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm); - goto out; + bh = affs_bread(dev,key,s->s_blocksize); + if (!bh) + goto out_no_bm_ext; + } } + if (mapidx < num_bm) + goto out_bad_num; + nobitmap: s->u.affs_sb.s_bm_count = num_bm; /* set up enough so that it can read an inode */ - s->s_dev = dev; - s->s_op = &affs_sops; s->s_dirt = 1; root_inode = iget(s,root_block); - s->s_root = d_alloc_root(root_inode,NULL); - unlock_super(s); - - if (!(s->s_root)) { - s->s_dev = 0; - affs_brelse(s->u.affs_sb.s_root_bh); - printk(KERN_ERR "AFFS: get root inode failed\n"); - MOD_DEC_USE_COUNT; - return NULL; - } - s->s_root->d_op = (s->u.affs_sb.s_flags & SF_INTL) ? &affs_dentry_operations_intl - : &affs_dentry_operations; + if (!root_inode) + goto out_no_root; + s->s_root = d_alloc_root(root_inode, NULL); + if (!s->s_root) + goto out_no_root; + s->s_root->d_op = &affs_dentry_operations; + unlock_super(s); /* Record date of last change if the bitmap was truncated and * create data zones if the volume is writable. */ @@ -592,12 +568,56 @@ pr_debug("AFFS: s_flags=%lX\n",s->s_flags); return s; - out: /* Kick out for various error conditions */ - affs_brelse (bh); +out_bad_opts: + printk(KERN_ERR "AFFS: Error parsing options\n"); + goto out_fail; +out_bad_size: + printk(KERN_ERR "AFFS: Could not determine device size\n"); + goto out_free_prefix; +out_no_valid_block: + if (!silent) + printk(KERN_ERR "AFFS: No valid root block on device %s\n", + kdevname(dev)); + goto out_restore; +out_unknown_fs: + printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n", + kdevname(dev), chksum); + goto out_free_bh; +out_no_root_block: + printk(KERN_ERR "AFFS: Cannot read root block\n"); + goto out_free_bh; +out_no_bitmap: + printk(KERN_ERR "AFFS: Bitmap allocation failed\n"); + goto out_free_root_block; +out_no_read_bm: + printk(KERN_ERR "AFFS: Cannot read bitmap\n"); + goto out_free_bitmap; +out_no_bm_ext: + printk(KERN_ERR "AFFS: Cannot read bitmap extension\n"); + goto out_free_bitmap; +out_bad_num: + printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n", + mapidx, num_bm); + goto out_free_bitmap; +out_no_root: + printk(KERN_ERR "AFFS: get root inode failed\n"); + + /* + * Begin the cascaded cleanup ... + */ + iput(root_inode); +out_free_bitmap: + kfree(s->u.affs_sb.s_bitmap); +out_free_root_block: affs_brelse(s->u.affs_sb.s_root_bh); - if (s->u.affs_sb.s_bitmap) - kfree(s->u.affs_sb.s_bitmap); - set_blocksize(dev,BLOCK_SIZE); +out_free_bh: + affs_brelse(bh); +out_restore: + set_blocksize(dev, s->u.affs_sb.s_blksize); +out_free_prefix: + if (s->u.affs_sb.s_prefix) + kfree(s->u.affs_sb.s_prefix); +out_fail: s->s_dev = 0; unlock_super(s); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v2.1.88/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.88/linux/fs/buffer.c Mon Feb 23 18:12:10 1998 +++ linux/fs/buffer.c Mon Feb 23 15:24:32 1998 @@ -1321,14 +1321,13 @@ /* Run the hooks that have to be done when a page I/O has completed. */ static inline void after_unlock_page (struct page * page) { - if (test_and_clear_bit(PG_decr_after, &page->flags)) + if (test_and_clear_bit(PG_decr_after, &page->flags)) { atomic_dec(&nr_async_pages); - if (test_and_clear_bit(PG_swap_unlock_after, &page->flags)) { - /* - * We're doing a swap, so check that this page is - * swap-cached and do the necessary cleanup. - */ - swap_after_unlock_page(page->offset); +#ifdef DEBUG_SWAP + printk ("DebugVM: Finished IO on page %p, nr_async_pages %d\n", + (char *) page_address(page), + atomic_read(&nr_async_pages)); +#endif } if (test_and_clear_bit(PG_free_after, &page->flags)) __free_page(page); diff -u --recursive --new-file v2.1.88/linux/fs/fat/file.c linux/fs/fat/file.c --- v2.1.88/linux/fs/fat/file.c Fri Jan 23 18:10:32 1998 +++ linux/fs/fat/file.c Sun Feb 22 10:48:11 1998 @@ -105,7 +105,7 @@ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ - NULL, /* readpage */ + generic_readpage, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ fat_truncate, /* truncate */ diff -u --recursive --new-file v2.1.88/linux/fs/inode.c linux/fs/inode.c --- v2.1.88/linux/fs/inode.c Thu Feb 12 20:56:12 1998 +++ linux/fs/inode.c Mon Feb 23 12:56:37 1998 @@ -701,19 +701,22 @@ list_add(&inode->i_list, inode_in_use.prev); } #ifdef INODE_PARANOIA +if (inode->i_flock) +printk(KERN_ERR "iput: inode %s/%ld still has locks!\n", +kdevname(inode->i_dev), inode->i_ino); if (!list_empty(&inode->i_dentry)) -printk("iput: device %s inode %ld still has aliases!\n", +printk(KERN_ERR "iput: device %s inode %ld still has aliases!\n", kdevname(inode->i_dev), inode->i_ino); if (inode->i_count) -printk("iput: device %s inode %ld count changed, count=%d\n", +printk(KERN_ERR "iput: device %s inode %ld count changed, count=%d\n", kdevname(inode->i_dev), inode->i_ino, inode->i_count); if (atomic_read(&inode->i_sem.count) != 1) -printk("iput: Aieee, semaphore in use device %s, count=%d\n", +printk(KERN_ERR "iput: Aieee, semaphore in use device %s, count=%d\n", kdevname(inode->i_dev), atomic_read(&inode->i_sem.count)); #endif } - if (inode->i_count > (1<<15)) { - printk("iput: device %s inode %ld count wrapped\n", + if (inode->i_count > (1<<31)) { + printk(KERN_ERR "iput: inode %s/%ld count wrapped\n", kdevname(inode->i_dev), inode->i_ino); } spin_unlock(&inode_lock); diff -u --recursive --new-file v2.1.88/linux/fs/ioctl.c linux/fs/ioctl.c --- v2.1.88/linux/fs/ioctl.c Sun Jul 13 21:20:10 1997 +++ linux/fs/ioctl.c Mon Feb 23 12:55:58 1998 @@ -13,6 +13,7 @@ #include #include #include /* for f_flags values */ +#include #include @@ -52,7 +53,8 @@ int on, error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) + filp = fget(fd); + if (!filp) goto out; error = 0; switch (cmd) { @@ -90,13 +92,16 @@ break; default: - if (filp->f_dentry && filp->f_dentry->d_inode && S_ISREG(filp->f_dentry->d_inode->i_mode)) + error = -ENOTTY; + if (!filp->f_dentry || !filp->f_dentry->d_inode) + error = -ENOENT; + else if (S_ISREG(filp->f_dentry->d_inode->i_mode)) error = file_ioctl(filp, cmd, arg); else if (filp->f_op && filp->f_op->ioctl) error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg); - else - error = -ENOTTY; } + fput(filp); + out: unlock_kernel(); return error; diff -u --recursive --new-file v2.1.88/linux/fs/isofs/dir.c linux/fs/isofs/dir.c --- v2.1.88/linux/fs/isofs/dir.c Thu Dec 18 16:37:02 1997 +++ linux/fs/isofs/dir.c Sat Feb 21 13:19:29 1998 @@ -101,11 +101,12 @@ unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); unsigned char bufbits = ISOFS_BUFFER_BITS(inode); unsigned int block, offset; - int inode_number; + int inode_number = 0; /* Quiet GCC */ struct buffer_head *bh; int len; int map; - int high_sierra = 0; + int high_sierra; + int first_de = 1; char *p = NULL; /* Quiet GCC */ struct iso_directory_record *de; @@ -114,6 +115,7 @@ offset = filp->f_pos & (bufsize - 1); block = isofs_bmap(inode, filp->f_pos >> bufbits); + high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; if (!block) return 0; @@ -129,7 +131,7 @@ printk("inode->i_size = %x\n",inode->i_size); #endif de = (struct iso_directory_record *) (bh->b_data + offset); - inode_number = (block << bufbits) + (offset & (bufsize - 1)); + if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1)); de_len = *(unsigned char *) de; #ifdef DEBUG @@ -177,6 +179,13 @@ break; } + if(de->flags[-high_sierra] & 0x80) { + first_de = 0; + filp->f_pos += de_len; + continue; + } + first_de = 1; + /* Handle the case of the '.' directory */ if (de->name_len[0] == 1 && de->name[0] == 0) { if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0) @@ -200,7 +209,6 @@ is no Rock Ridge NM field. */ if (inode->i_sb->u.isofs_sb.s_unhide == 'n') { /* Do not report hidden or associated files */ - high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra; if (de->flags[-high_sierra] & 5) { filp->f_pos += de_len; continue; diff -u --recursive --new-file v2.1.88/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v2.1.88/linux/fs/isofs/inode.c Thu Feb 12 20:56:12 1998 +++ linux/fs/isofs/inode.c Sat Feb 21 13:19:29 1998 @@ -5,7 +5,8 @@ * 1992, 1993, 1994 Eric Youngdale Modified for ISO9660 filesystem. * 1994 Eberhard Moenkeberg - multi session handling. * 1995 Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs. - * + * 1997 Gordon Chaffee - Joliet CDs + * 1998 Eric Lammerts - ISO9660 Level 3 */ #include @@ -655,17 +656,24 @@ int isofs_bmap(struct inode * inode,int block) { + off_t b_off, offset, size; + struct inode *ino; + unsigned int firstext; + unsigned long nextino; + int i; if (block<0) { printk("_isofs_bmap: block<0"); return 0; } + b_off = block << ISOFS_BUFFER_BITS(inode); + /* * If we are beyond the end of this file, don't give out any * blocks. */ - if( (block << ISOFS_BUFFER_BITS(inode)) >= inode->i_size ) + if( b_off > inode->i_size ) { off_t max_legal_read_offset; @@ -679,7 +687,7 @@ */ max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - if( (block << ISOFS_BUFFER_BITS(inode)) >= max_legal_read_offset ) + if( b_off >= max_legal_read_offset ) { printk("_isofs_bmap: block>= EOF(%d, %ld)\n", block, @@ -688,7 +696,42 @@ return 0; } - return (inode->u.isofs_i.i_first_extent >> ISOFS_BUFFER_BITS(inode)) + block; + offset = 0; + firstext = inode->u.isofs_i.i_first_extent; + size = inode->u.isofs_i.i_section_size; + nextino = inode->u.isofs_i.i_next_section_ino; +#ifdef DEBUG + printk("first inode: inode=%lu nextino=%lu firstext=%u size=%lu\n", + inode->i_ino, nextino, firstext, size); +#endif + i = 0; + while(b_off >= offset + size) { + offset += size; + + if(nextino == 0) return 0; + ino = iget(inode->i_sb, nextino); + if(!ino) return 0; + firstext = ino->u.isofs_i.i_first_extent; + size = ino->u.isofs_i.i_section_size; +#ifdef DEBUG + printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n", + inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size); +#endif + nextino = ino->u.isofs_i.i_next_section_ino; + iput(ino); + + if(++i > 100) { + printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n"); + printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n", + inode->i_ino, block, firstext, (unsigned)size, nextino); + return 0; + } + } +#ifdef DEBUG + printk("isofs_bmap: mapped inode:block %lu:%d to block %lu\n", + inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode)); +#endif + return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode); } @@ -702,6 +745,82 @@ } } +static int isofs_read_level3_size(struct inode * inode) +{ + unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); + struct buffer_head * bh = NULL; + struct iso_directory_record * raw_inode = NULL; /* quiet gcc */ + unsigned char *pnt = NULL; + void *cpnt = NULL; + int block = 0; /* Quiet GCC */ + unsigned long ino; + int i; + + inode->i_size = 0; + inode->u.isofs_i.i_next_section_ino = 0; + ino = inode->i_ino; + i = 0; + do { + if(i > 100) { + printk("isofs_read_level3_size: More than 100 file sections ?!?, aborting...\n" + "isofs_read_level3_size: inode=%lu ino=%lu\n", inode->i_ino, ino); + return 0; + } + + if(bh == NULL || block != ino >> ISOFS_BUFFER_BITS(inode)) { + if(bh) brelse(bh); + block = ino >> ISOFS_BUFFER_BITS(inode); + if (!(bh=bread(inode->i_dev,block, bufsize))) { + printk("unable to read i-node block"); + return 1; + } + } + pnt = ((unsigned char *) bh->b_data + + (ino & (bufsize - 1))); + + if ((ino & (bufsize - 1)) + *pnt > bufsize){ + int frag1, offset; + + offset = (ino & (bufsize - 1)); + frag1 = bufsize - offset; + cpnt = kmalloc(*pnt,GFP_KERNEL); + if (cpnt == NULL) { + printk(KERN_INFO "NoMem ISO inode %lu\n",inode->i_ino); + brelse(bh); + return 1; + } + memcpy(cpnt, bh->b_data + offset, frag1); + brelse(bh); + if (!(bh = bread(inode->i_dev,++block, bufsize))) { + kfree(cpnt); + printk("unable to read i-node block"); + return 1; + } + offset += *pnt - bufsize; + memcpy((char *)cpnt+frag1, bh->b_data, offset); + pnt = ((unsigned char *) cpnt); + } + + if(*pnt == 0) { + ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE; + continue; + } + raw_inode = ((struct iso_directory_record *) pnt); + + inode->i_size += isonum_733 (raw_inode->size); + if(i == 1) inode->u.isofs_i.i_next_section_ino = ino; + + ino += *pnt; + if (cpnt) { + kfree (cpnt); + cpnt = NULL; + } + i++; + } while(raw_inode->flags[-inode->i_sb->u.isofs_sb.s_high_sierra] & 0x80); + brelse(bh); + return 0; +} + void isofs_read_inode(struct inode * inode) { unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); @@ -744,8 +863,15 @@ } inode->i_uid = inode->i_sb->u.isofs_sb.s_uid; inode->i_gid = inode->i_sb->u.isofs_sb.s_gid; - inode->i_size = isonum_733 (raw_inode->size); inode->i_blocks = inode->i_blksize = 0; + + + inode->u.isofs_i.i_section_size = isonum_733 (raw_inode->size); + if(raw_inode->flags[-high_sierra] & 0x80) { + if(isofs_read_level3_size(inode)) goto fail; + } else { + inode->i_size = isonum_733 (raw_inode->size); + } /* There are defective discs out there - we do this to protect ourselves. A cdrom will never contain more than 800Mb */ diff -u --recursive --new-file v2.1.88/linux/fs/locks.c linux/fs/locks.c --- v2.1.88/linux/fs/locks.c Mon Feb 23 18:12:10 1998 +++ linux/fs/locks.c Mon Feb 23 12:55:58 1998 @@ -111,6 +111,7 @@ #include #include #include +#include #include #include @@ -289,15 +290,21 @@ int error; lock_kernel(); - if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - error = -EBADF; - else if (!flock_make_lock(filp, &file_lock, cmd)) - error = -EINVAL; - else if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3)) - error = -EBADF; - else - error = flock_lock_file(filp, &file_lock, - (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + error = -EINVAL; + if (!flock_make_lock(filp, &file_lock, cmd)) + goto out_putf; + error = -EBADF; + if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3)) + goto out_putf; + error = flock_lock_file(filp, &file_lock, + (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); +out_putf: + fput(filp); +out: unlock_kernel(); return (error); } @@ -307,36 +314,34 @@ */ int fcntl_getlk(unsigned int fd, struct flock *l) { - struct flock flock; struct file *filp; - struct dentry *dentry; - struct inode *inode; struct file_lock *fl,file_lock; + struct flock flock; int error; - if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - return -EBADF; + error = -EFAULT; if (copy_from_user(&flock, l, sizeof(flock))) - return -EFAULT; - + goto out; + error = -EINVAL; if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) - return -EINVAL; + goto out; - dentry = filp->f_dentry; - if (!dentry) - return -EINVAL; - - inode = dentry->d_inode; - if (!inode) - return -EINVAL; + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + + error = -EINVAL; + if (!filp->f_dentry || !filp->f_dentry->d_inode) + goto out_putf; if (!posix_make_lock(filp, &file_lock, &flock)) - return -EINVAL; + goto out_putf; if (filp->f_op->lock) { error = filp->f_op->lock(filp, F_GETLK, &file_lock); if (error < 0) - return error; + goto out_putf; fl = &file_lock; } else { fl = posix_test_lock(filp, &file_lock); @@ -351,8 +356,14 @@ flock.l_whence = 0; flock.l_type = fl->fl_type; } + error = -EFAULT; + if (!copy_to_user(l, &flock, sizeof(flock))) + error = 0; - return (copy_to_user(l, &flock, sizeof(flock)) ? -EFAULT : 0); +out_putf: + fput(filp); +out: + return error; } /* Apply the lock described by l to an open file descriptor. @@ -367,22 +378,26 @@ struct inode *inode; int error; + /* + * This might block, so we do it before checking the inode. + */ + error = -EFAULT; + if (copy_from_user(&flock, l, sizeof(flock))) + goto out; + /* Get arguments and validate them ... */ - if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd])) - return -EBADF; + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + error = -EINVAL; if (!(dentry = filp->f_dentry)) - return -EINVAL; - + goto out_putf; if (!(inode = dentry->d_inode)) - return -EINVAL; - /* - * This might block, so we do it before checking the inode. - */ - if (copy_from_user(&flock, l, sizeof(flock))) - return (-EFAULT); + goto out_putf; /* Don't allow mandatory locks on files that may be memory mapped * and shared. @@ -391,23 +406,26 @@ (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && inode->i_mmap) { struct vm_area_struct *vma = inode->i_mmap; + error = -EAGAIN; do { if (vma->vm_flags & VM_MAYSHARE) - return (-EAGAIN); + goto out_putf; } while ((vma = vma->vm_next_share) != NULL); } + error = -EINVAL; if (!posix_make_lock(filp, &file_lock, &flock)) - return (-EINVAL); + goto out_putf; + error = -EBADF; switch (flock.l_type) { case F_RDLCK: if (!(filp->f_mode & FMODE_READ)) - return (-EBADF); + goto out_putf; break; case F_WRLCK: if (!(filp->f_mode & FMODE_WRITE)) - return (-EBADF); + goto out_putf; break; case F_UNLCK: break; @@ -425,20 +443,25 @@ } } if (!(filp->f_mode & 3)) - return (-EBADF); + goto out_putf; break; #endif default: - return (-EINVAL); + error = -EINVAL; + goto out_putf; } if (filp->f_op->lock != NULL) { error = filp->f_op->lock(filp, cmd, &file_lock); if (error < 0) - return (error); + goto out_putf; } + error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW); - return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW)); +out_putf: + fput(filp); +out: + return error; } /* diff -u --recursive --new-file v2.1.88/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c --- v2.1.88/linux/fs/ntfs/fs.c Fri Jan 23 18:10:32 1998 +++ linux/fs/ntfs/fs.c Tue Feb 24 23:24:00 1998 @@ -668,7 +668,11 @@ static void ntfs_put_inode(struct inode *ino) { - ntfs_debug(DEBUG_OTHER, "ntfs_put_inode %lx\n",ino->i_ino); +} + +static void _ntfs_clear_inode(struct inode *ino) +{ + ntfs_debug(DEBUG_OTHER, "ntfs_clear_inode %lx\n",ino->i_ino); #ifdef NTFS_IN_LINUX_KERNEL if(ino->i_ino!=FILE_MFT) ntfs_clear_inode(&ino->u.ntfs_i); @@ -680,7 +684,7 @@ ino->u.generic_ip=0; } #endif - clear_inode(ino); + return; } /* Called when umounting a filesystem by do_umount() in fs/super.c */ @@ -753,6 +757,7 @@ NULL, /* write_super */ ntfs_statfs, ntfs_remount_fs, /* remount */ + _ntfs_clear_inode, /* clear_inode */ }; /* Called to mount a filesystem by read_super() in fs/super.c diff -u --recursive --new-file v2.1.88/linux/fs/ntfs/inode.c linux/fs/ntfs/inode.c --- v2.1.88/linux/fs/ntfs/inode.c Fri Jan 2 01:42:59 1998 +++ linux/fs/ntfs/inode.c Tue Feb 24 23:24:00 1998 @@ -289,8 +289,14 @@ void ntfs_clear_inode(ntfs_inode *ino) { int i; + if(!ino->attr){ + ntfs_error("ntfs_clear_inode: double free\n"); + return; + } ntfs_free(ino->attr); + ino->attr=0; ntfs_free(ino->records); + ino->records=0; for(i=0;iattr_count;i++) { if(ino->attrs[i].name) @@ -305,6 +311,7 @@ } } ntfs_free(ino->attrs); + ino->attrs=0; } /* Check and fixup a MFT record */ diff -u --recursive --new-file v2.1.88/linux/fs/open.c linux/fs/open.c --- v2.1.88/linux/fs/open.c Mon Feb 23 18:12:10 1998 +++ linux/fs/open.c Mon Feb 23 12:55:58 1998 @@ -47,24 +47,31 @@ asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf) { + struct file * file; struct inode * inode; struct dentry * dentry; - struct file * file; + struct super_block * sb; int error; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - error = -EBADF; - else if (!(dentry = file->f_dentry)) - error = -ENOENT; - else if (!(inode = dentry->d_inode)) - error = -ENOENT; - else if (!inode->i_sb) - error = -ENODEV; - else if (!inode->i_sb->s_op->statfs) - error = -ENOSYS; - else - error = inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs)); + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + error = -ENOENT; + if (!(dentry = file->f_dentry)) + goto out_putf; + if (!(inode = dentry->d_inode)) + goto out_putf; + error = -ENODEV; + if (!(sb = inode->i_sb)) + goto out_putf; + error = -ENOSYS; + if (sb->s_op->statfs) + error = sb->s_op->statfs(sb, buf, sizeof(struct statfs)); +out_putf: + fput(file); +out: unlock_kernel(); return error; } @@ -147,23 +154,29 @@ int error; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - error = -EBADF; - else if (!(dentry = file->f_dentry)) - error = -ENOENT; - else if (!(inode = dentry->d_inode)) - error = -ENOENT; - else if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) - error = -EACCES; - else if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - error = -EPERM; - else { - error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, - lengthi_size ? length : inode->i_size, - abs(inode->i_size - length)); - if (!error) - error = do_truncate(dentry, length); - } + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + error = -ENOENT; + if (!(dentry = file->f_dentry)) + goto out_putf; + if (!(inode = dentry->d_inode)) + goto out_putf; + error = -EACCES; + if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE)) + goto out_putf; + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto out_putf; + error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, + lengthi_size ? length : inode->i_size, + abs(inode->i_size - length)); + if (!error) + error = do_truncate(dentry, length); +out_putf: + fput(file); +out: unlock_kernel(); return error; } @@ -347,30 +360,28 @@ lock_kernel(); error = -EBADF; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; error = -ENOENT; if (!(dentry = file->f_dentry)) - goto out; + goto out_putf; if (!(inode = dentry->d_inode)) - goto out; + goto out_putf; error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) - goto out; - - error = permission(inode,MAY_EXEC); - if (error) - goto out; + goto out_putf; - { - struct dentry *tmp; - - tmp = current->fs->pwd; + error = permission(inode, MAY_EXEC); + if (!error) { + struct dentry *tmp = current->fs->pwd; current->fs->pwd = dget(dentry); dput(tmp); } +out_putf: + fput(file); out: unlock_kernel(); return error; @@ -421,28 +432,34 @@ struct inode * inode; struct dentry * dentry; struct file * file; - struct iattr newattrs; int err = -EBADF; + struct iattr newattrs; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; + err = -ENOENT; if (!(dentry = file->f_dentry)) - goto out; + goto out_putf; if (!(inode = dentry->d_inode)) - goto out; + goto out_putf; + err = -EROFS; if (IS_RDONLY(inode)) - goto out; + goto out_putf; err = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - goto out; + goto out_putf; if (mode == (mode_t) -1) mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); + +out_putf: + fput(file); out: unlock_kernel(); return err; @@ -487,8 +504,8 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) { struct inode * inode; - struct iattr newattrs; int error; + struct iattr newattrs; error = -ENOENT; if (!(inode = dentry->d_inode)) { @@ -581,13 +598,13 @@ int error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + file = fget(fd); + if (!file) goto out; error = -ENOENT; - if (!(dentry = file->f_dentry)) - goto out; - - error = chown_common(dentry, user, group); + if ((dentry = file->f_dentry) != NULL) + error = chown_common(dentry, user, group); + fput(file); out: unlock_kernel(); @@ -608,16 +625,17 @@ * for the internal routines (ie open_namei()/follow_link() etc). 00 is * used by symlinks. */ -static int do_open(const char * filename,int flags,int mode, int fd) +static int do_open(const char * filename, int flags, int mode, int fd) { struct inode * inode; struct dentry * dentry; struct file * f; int flag,error; + error = -ENFILE; f = get_empty_filp(); if (!f) - return -ENFILE; + goto out; f->f_flags = flag = flags; f->f_mode = (flag+1) & O_ACCMODE; if (f->f_mode) @@ -648,7 +666,7 @@ } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - current->files->fd[fd] = f; + fd_install(fd, f); return 0; cleanup_all: @@ -658,6 +676,7 @@ dput(dentry); cleanup_file: put_filp(f); +out: return error; } @@ -670,6 +689,10 @@ struct files_struct * files = current->files; fd = find_first_zero_bit(&files->open_fds, NR_OPEN); + /* + * N.B. For clone tasks sharing a files structure, this test + * will limit the total number of files that can be opened. + */ if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) { FD_SET(fd, &files->open_fds); FD_CLR(fd, &files->close_on_exec); @@ -678,36 +701,37 @@ return -EMFILE; } -inline void put_unused_fd(int fd) +inline void put_unused_fd(unsigned int fd) { FD_CLR(fd, ¤t->files->open_fds); } -asmlinkage int sys_open(const char * filename,int flags,int mode) +asmlinkage int sys_open(const char * filename, int flags, int mode) { char * tmp; int fd, error; lock_kernel(); - error = get_unused_fd(); - if (error < 0) + fd = get_unused_fd(); + if (fd < 0) goto out; - fd = error; tmp = getname(filename); error = PTR_ERR(tmp); - if (!IS_ERR(tmp)) { - error = do_open(tmp,flags,mode,fd); - putname(tmp); - if (!error) { - error = fd; - goto out; - } - } - put_unused_fd(fd); + if (IS_ERR(tmp)) + goto out_fail; + error = do_open(tmp, flags, mode, fd); + putname(tmp); + if (error) + goto out_fail; out: unlock_kernel(); - return error; + return fd; + +out_fail: + put_unused_fd(fd); + fd = error; + goto out; } #ifndef __alpha__ @@ -728,11 +752,14 @@ #endif +/* + * Called when retiring the last use of a file pointer. + */ int __fput(struct file *filp) { - int error = 0; struct dentry * dentry = filp->f_dentry; struct inode * inode = dentry->d_inode; + int error = 0; if (filp->f_op && filp->f_op->release) error = filp->f_op->release(inode, filp); @@ -756,6 +783,11 @@ return fput(filp); } +/* + * Careful here! We test whether the file pointer is NULL before + * releasing the fd. This ensures that one clone task can't release + * an fd while another clone is opening it. + */ asmlinkage int sys_close(unsigned int fd) { int error; diff -u --recursive --new-file v2.1.88/linux/fs/read_write.c linux/fs/read_write.c --- v2.1.88/linux/fs/read_write.c Tue Oct 21 08:57:29 1997 +++ linux/fs/read_write.c Mon Feb 23 12:55:58 1998 @@ -62,14 +62,18 @@ lock_kernel(); retval = -EBADF; - if (fd >= NR_OPEN || - !(file = current->files->fd[fd]) || - !(dentry = file->f_dentry) || - !(inode = dentry->d_inode)) + file = fget(fd); + if (!file) goto bad; + /* N.B. Shouldn't this be ENOENT?? */ + if (!(dentry = file->f_dentry) || + !(inode = dentry->d_inode)) + goto out_putf; retval = -EINVAL; if (origin <= 2) retval = llseek(file, offset, origin); +out_putf: + fput(file); bad: unlock_kernel(); return retval; @@ -88,24 +92,28 @@ lock_kernel(); retval = -EBADF; - if (fd >= NR_OPEN || - !(file = current->files->fd[fd]) || - !(dentry = file->f_dentry) || - !(inode = dentry->d_inode)) + file = fget(fd); + if (!file) goto bad; + /* N.B. Shouldn't this be ENOENT?? */ + if (!(dentry = file->f_dentry) || + !(inode = dentry->d_inode)) + goto out_putf; retval = -EINVAL; if (origin > 2) - goto bad; + goto out_putf; offset = llseek(file, ((loff_t) offset_high << 32) | offset_low, origin); retval = (int)offset & INT_MAX; if (offset >= 0) { - retval = copy_to_user(result, &offset, sizeof(offset)); - if (retval) - retval = -EFAULT; + retval = -EFAULT; + if (!copy_to_user(result, &offset, sizeof(offset))) + retval = 0; } +out_putf: + fput(file); bad: unlock_kernel(); return retval; @@ -201,9 +209,10 @@ if (count > UIO_MAXIOV) goto out_nofree; if (count > UIO_FASTIOV) { - iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); ret = -ENOMEM; - if (!iov) goto out_nofree; + iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); + if (!iov) + goto out_nofree; } ret = -EFAULT; if (copy_from_user(iov, vector, count*sizeof(*vector))) @@ -280,11 +289,10 @@ file = fget(fd); if (!file) goto bad_file; - if (!(file->f_mode & FMODE_READ)) - goto out; - ret = do_readv_writev(VERIFY_WRITE, file, vector, count); -out: + if (file->f_mode & FMODE_READ) + ret = do_readv_writev(VERIFY_WRITE, file, vector, count); fput(file); + bad_file: unlock_kernel(); return ret; @@ -302,15 +310,13 @@ file = fget(fd); if (!file) goto bad_file; - if (!(file->f_mode & FMODE_WRITE)) - goto out; - - down(&file->f_dentry->d_inode->i_sem); - ret = do_readv_writev(VERIFY_READ, file, vector, count); - up(&file->f_dentry->d_inode->i_sem); - -out: + if (file->f_mode & FMODE_WRITE) { + down(&file->f_dentry->d_inode->i_sem); + ret = do_readv_writev(VERIFY_READ, file, vector, count); + up(&file->f_dentry->d_inode->i_sem); + } fput(file); + bad_file: unlock_kernel(); return ret; diff -u --recursive --new-file v2.1.88/linux/fs/readdir.c linux/fs/readdir.c --- v2.1.88/linux/fs/readdir.c Sat Sep 20 12:21:34 1997 +++ linux/fs/readdir.c Mon Feb 23 12:55:58 1998 @@ -4,12 +4,13 @@ * Copyright (C) 1995 Linus Torvalds */ +#include +#include #include #include #include +#include #include -#include -#include #include #include @@ -65,27 +66,24 @@ lock_kernel(); error = -EBADF; - if (fd >= NR_OPEN) - goto out; - - file = current->files->fd[fd]; + file = fget(fd); if (!file) goto out; dentry = file->f_dentry; if (!dentry) - goto out; + goto out_putf; inode = dentry->d_inode; if (!inode) - goto out; + goto out_putf; buf.count = 0; buf.dirent = dirent; error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - goto out; + goto out_putf; /* * Get the inode's semaphore to prevent changes @@ -95,8 +93,11 @@ error = file->f_op->readdir(file, &buf, fillonedir); up(&inode->i_sem); if (error < 0) - goto out; + goto out_putf; error = buf.count; + +out_putf: + fput(file); out: unlock_kernel(); return error; @@ -155,20 +156,17 @@ lock_kernel(); error = -EBADF; - if (fd >= NR_OPEN) - goto out; - - file = current->files->fd[fd]; + file = fget(fd); if (!file) goto out; dentry = file->f_dentry; if (!dentry) - goto out; + goto out_putf; inode = dentry->d_inode; if (!inode) - goto out; + goto out_putf; buf.current_dir = (struct linux_dirent *) dirent; buf.previous = NULL; @@ -177,7 +175,7 @@ error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) - goto out; + goto out_putf; /* * Get the inode's semaphore to prevent changes @@ -187,13 +185,16 @@ error = file->f_op->readdir(file, &buf, filldir); up(&inode->i_sem); if (error < 0) - goto out; - lastdirent = buf.previous; + goto out_putf; error = buf.error; + lastdirent = buf.previous; if (lastdirent) { put_user(file->f_pos, &lastdirent->d_off); error = count - buf.count; } + +out_putf: + fput(file); out: unlock_kernel(); return error; diff -u --recursive --new-file v2.1.88/linux/fs/stat.c linux/fs/stat.c --- v2.1.88/linux/fs/stat.c Sun Jan 4 00:53:41 1998 +++ linux/fs/stat.c Mon Feb 23 12:55:58 1998 @@ -4,13 +4,14 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include +#include #include #include #include #include -#include +#include #include -#include #include #include @@ -220,12 +221,14 @@ int err = -EBADF; lock_kernel(); - if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) { + f = fget(fd); + if (f) { struct dentry * dentry = f->f_dentry; err = do_revalidate(dentry); if (!err) err = cp_old_stat(dentry->d_inode, statbuf); + fput(f); } unlock_kernel(); return err; @@ -239,12 +242,14 @@ int err = -EBADF; lock_kernel(); - if (fd < NR_OPEN && (f = current->files->fd[fd]) != NULL) { + f = fget(fd); + if (f) { struct dentry * dentry = f->f_dentry; err = do_revalidate(dentry); if (!err) err = cp_new_stat(dentry->d_inode, statbuf); + fput(f); } unlock_kernel(); return err; diff -u --recursive --new-file v2.1.88/linux/include/asm-alpha/hwrpb.h linux/include/asm-alpha/hwrpb.h --- v2.1.88/linux/include/asm-alpha/hwrpb.h Mon Jan 12 14:51:14 1998 +++ linux/include/asm-alpha/hwrpb.h Mon Feb 23 10:25:10 1998 @@ -15,6 +15,8 @@ #define EV45_CPU 6 /* EV4.5 (21064/xxx) */ #define EV56_CPU 7 /* EV5.6 (21164) */ #define EV6_CPU 8 /* EV6 (21164) */ +#define PCA56_CPU 9 /* PCA56 (21164PC) */ +#define PCA57_CPU 10 /* PCA57 (??) */ /* * DEC system types for Alpha systems. Found in HWRPB. @@ -39,8 +41,26 @@ #define ST_DEC_EB64P 20 /* EB64+ systype */ #define ST_DEC_EB66P -19 /* EB66 systype */ #define ST_DEC_EBPC64 -20 /* Cabriolet (AlphaPC64) systype */ +#define ST_DEC_BURNS 21 /* Laptop systype */ +#define ST_DEC_RAWHIDE 22 /* Rawhide systype */ +#define ST_DEC_K2 23 /* K2 systype */ +#define ST_DEC_LYNX 24 /* Lynx systype */ +#define ST_DEC_XL 25 /* Alpha XL systype */ #define ST_DEC_EB164 26 /* EB164 systype */ +#define ST_DEC_NORITAKE 27 /* Noritake systype */ +#define ST_DEC_CORTEX 28 /* Cortex systype */ #define ST_DEC_MIATA 30 /* MIATA systype */ +#define ST_DEC_XXM 31 /* XXM systype */ +#define ST_DEC_TAKARA 32 /* Takara systype */ +#define ST_DEC_YUKON 33 /* Yukon systype */ +#define ST_DEC_TSUNAMI 34 /* Tsunami systype */ +#define ST_DEC_WILDFIRE 35 /* Wildfire systype */ +#define ST_DEC_CUSCO 36 /* CUSCO systype */ + +/* UNOFFICIAL!!! */ +#define ST_UNOFFICIAL_BIAS 100 +#define ST_DTI_RUFFIAN 101 /* RUFFIAN systype */ + struct pcb_struct { unsigned long ksp; diff -u --recursive --new-file v2.1.88/linux/include/asm-alpha/irq.h linux/include/asm-alpha/irq.h --- v2.1.88/linux/include/asm-alpha/irq.h Mon Jan 12 14:51:14 1998 +++ linux/include/asm-alpha/irq.h Mon Feb 23 10:25:10 1998 @@ -10,13 +10,18 @@ #include #include -#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164) +#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || \ + defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164) || \ + defined(CONFIG_ALPHA_LX164) # define NR_IRQS 33 -#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) || defined(CONFIG_ALPHA_MIKASA) +#elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) || \ + defined(CONFIG_ALPHA_MIKASA) # define NR_IRQS 32 -#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) || defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_NORITAKE) +#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) || \ + defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_NORITAKE) || \ + defined(CONFIG_ALPHA_RUFFIAN) # define NR_IRQS 48 -#elif defined(CONFIG_ALPHA_SABLE) +#elif defined(CONFIG_ALPHA_SABLE) || defined(CONFIG_ALPHA_SX164) # define NR_IRQS 40 #else # define NR_IRQS 16 diff -u --recursive --new-file v2.1.88/linux/include/asm-alpha/pyxis.h linux/include/asm-alpha/pyxis.h --- v2.1.88/linux/include/asm-alpha/pyxis.h Mon Jan 12 14:51:14 1998 +++ linux/include/asm-alpha/pyxis.h Mon Feb 23 10:25:10 1998 @@ -178,6 +178,20 @@ * Translate physical memory address as seen on (PCI) bus into * a kernel virtual address and vv. */ + +#if defined(CONFIG_ALPHA_RUFFIAN) +/* Ruffian doesn't do 1G PCI window. */ + +extern inline unsigned long virt_to_bus(void * address) +{ + return virt_to_phys(address); +} + +extern inline void * bus_to_virt(unsigned long address) +{ + return phys_to_virt(address); +} +#else extern inline unsigned long virt_to_bus(void * address) { return virt_to_phys(address) + PYXIS_DMA_WIN_BASE; @@ -187,6 +201,7 @@ { return phys_to_virt(address - PYXIS_DMA_WIN_BASE); } +#endif /* RUFFIAN */ /* * I/O functions: diff -u --recursive --new-file v2.1.88/linux/include/asm-i386/floppy.h linux/include/asm-i386/floppy.h --- v2.1.88/linux/include/asm-i386/floppy.h Mon Feb 23 18:12:11 1998 +++ linux/include/asm-i386/floppy.h Tue Feb 24 11:17:04 1998 @@ -29,7 +29,6 @@ #define SW fd_routine[use_virtual_dma&1] #define CSW fd_routine[can_use_virtual_dma & 1] -#define NCSW fd_routine[(can_use_virtual_dma >> 1)& 1] #define fd_inb(port) inb_p(port) @@ -39,9 +38,6 @@ #define fd_free_dma() CSW._free_dma(FLOPPY_DMA) #define fd_enable_irq() enable_irq(FLOPPY_IRQ) #define fd_disable_irq() disable_irq(FLOPPY_IRQ) -#define fd_request_irq() NCSW._request_irq(FLOPPY_IRQ, floppy_interrupt,\ - SA_INTERRUPT|SA_SAMPLE_RANDOM,\ - "floppy", NULL) #define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) #define fd_get_dma_residue() SW._get_dma_residue(FLOPPY_DMA) #define fd_dma_mem_alloc(size) SW._dma_mem_alloc(size) @@ -180,14 +176,15 @@ } -static int vdma_request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, - const char *device, - void *dev_id) +static int fd_request_irq(void) { - return request_irq(irq, floppy_hardint,SA_INTERRUPT,device, - dev_id); + if(can_use_virtual_dma) + return request_irq(FLOPPY_IRQ, floppy_hardint,SA_INTERRUPT, + "floppy", NULL); + else + return request_irq(FLOPPY_IRQ, floppy_interrupt, + SA_INTERRUPT|SA_SAMPLE_RANDOM, + "floppy", NULL); } @@ -265,11 +262,6 @@ int (*_request_dma)(unsigned int dmanr, const char * device_id); void (*_free_dma)(unsigned int dmanr); int (*_get_dma_residue)(unsigned int dummy); - int (*_request_irq)(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, - const char *device, - void *dev_id); unsigned long (*_dma_mem_alloc) (unsigned long size); int (*_dma_setup)(char *addr, unsigned long size, int mode, int io); } fd_routine[] = { @@ -277,7 +269,6 @@ request_dma, free_dma, get_dma_residue, - request_irq, dma_mem_alloc, hard_dma_setup }, @@ -285,7 +276,6 @@ vdma_request_dma, vdma_nop, vdma_get_dma_residue, - vdma_request_irq, vdma_mem_alloc, vdma_dma_setup } diff -u --recursive --new-file v2.1.88/linux/include/asm-mips/ng1.h linux/include/asm-mips/ng1.h --- v2.1.88/linux/include/asm-mips/ng1.h Tue Dec 16 12:46:10 1997 +++ linux/include/asm-mips/ng1.h Tue Feb 24 22:39:30 1998 @@ -46,29 +46,3 @@ unsigned char green [256]; unsigned char blue [256]; }; - - - -#define GFX_NAME_NEWPORT "NG1" - -/* ioctls */ -#define NG1_SET_CURSOR_HOTSPOT 21001 -struct ng1_set_cursor_hotspot { - unsigned short xhot; - unsigned short yhot; -}; - -#define NG1_SETDISPLAYMODE 21006 -struct ng1_setdisplaymode_args { - int wid; - unsigned int mode; -}; - -#define NG1_SETGAMMARAMP0 21007 -struct ng1_setgammaramp_args { - unsigned char red [256]; - unsigned char green [256]; - unsigned char blue [256]; -}; - - diff -u --recursive --new-file v2.1.88/linux/include/asm-mips/prctl.h linux/include/asm-mips/prctl.h --- v2.1.88/linux/include/asm-mips/prctl.h Tue Dec 16 12:46:11 1997 +++ linux/include/asm-mips/prctl.h Tue Feb 24 22:39:30 1998 @@ -3,48 +3,6 @@ * * The IRIX kernel maps a page at PRDA_ADDRESS with the * contents of prda and fills it the bits on prda_sys. - * $Id: prctl.h,v 1.1 1997/09/21 22:27:19 miguel Exp $ - */ - -#ifndef __PRCTL_H__ -#define __PRCTL_H__ - -#define PRDA_ADDRESS 0x200000L -#define PRDA ((struct prda *) PRDA_ADDRESS) - -struct prda_sys { - pid_t t_pid; - u32 t_hint; - u32 t_dlactseq; - u32 t_fpflags; - u32 t_prid; /* processor type, $prid CP0 register */ - u32 t_dlendseq; - u64 t_unused1[5]; - pid_t t_rpid; - s32 t_resched; - u32 t_unused[8]; - u32 t_cpu; /* current/last cpu */ - - /* FIXME: The signal information, not supported by Linux now */ - u32 t_flags; /* if true, then the sigprocmask is in userspace */ - u32 t_sigprocmask [1]; /* the sigprocmask */ -}; - -struct prda { - char fill [0xe00]; - struct prda_sys prda_sys; -}; - -#define t_sys prda_sys - -ptrdiff_t prctl (int op, int v1, int v2); - -#endif -/* - * IRIX prctl interface - * - * The IRIX kernel maps a page at PRDA_ADDRESS with the - * contents of prda and fills it the bits on prda_sys. * $Id: prctl.h,v 1.1 1997/12/02 02:28:28 ralf Exp $ */ diff -u --recursive --new-file v2.1.88/linux/include/asm-sparc/svr4.h linux/include/asm-sparc/svr4.h --- v2.1.88/linux/include/asm-sparc/svr4.h Sat Nov 9 00:30:13 1996 +++ linux/include/asm-sparc/svr4.h Tue Feb 24 22:08:01 1998 @@ -69,7 +69,7 @@ caddr_t ptr; } svr4_xrs_t; -/* Machine dependant context */ +/* Machine dependent context */ typedef struct { svr4_gregset_t greg; /* registers 0..19 (see top) */ svr4_gwindows_t *gwin; /* may point to register windows */ diff -u --recursive --new-file v2.1.88/linux/include/asm-sparc64/svr4.h linux/include/asm-sparc64/svr4.h --- v2.1.88/linux/include/asm-sparc64/svr4.h Thu Sep 4 12:54:49 1997 +++ linux/include/asm-sparc64/svr4.h Tue Feb 24 22:08:02 1998 @@ -70,7 +70,7 @@ u32 ptr; } svr4_xrs_t; -/* Machine dependant context */ +/* Machine dependent context */ typedef struct { svr4_gregset_t greg; /* registers 0..19 (see top) */ u32 gwin; /* may point to register windows */ diff -u --recursive --new-file v2.1.88/linux/include/linux/affs_fs_sb.h linux/include/linux/affs_fs_sb.h --- v2.1.88/linux/include/linux/affs_fs_sb.h Tue Dec 2 22:25:07 1997 +++ linux/include/linux/affs_fs_sb.h Mon Feb 23 22:01:26 1998 @@ -37,6 +37,7 @@ struct affs_sb_info { int s_partition_size; /* Partition size in blocks. */ + int s_blksize; /* Initial device blksize */ s32 s_root_block; /* FFS root block number. */ int s_hashsize; /* Size of hash table. */ unsigned long s_flags; /* See below. */ diff -u --recursive --new-file v2.1.88/linux/include/linux/elf.h linux/include/linux/elf.h --- v2.1.88/linux/include/linux/elf.h Thu Feb 12 20:56:13 1998 +++ linux/include/linux/elf.h Tue Feb 24 22:08:02 1998 @@ -128,7 +128,7 @@ #define AT_GID 13 /* real gid */ #define AT_EGID 14 /* effective gid */ #define AT_PLATFORM 15 /* string identifying cpu for optimizations */ -#define AT_HWCAP 16 /* arch dependant hints at cpu capabilities */ +#define AT_HWCAP 16 /* arch dependent hints at cpu capabilities */ typedef struct dynamic{ Elf32_Sword d_tag; diff -u --recursive --new-file v2.1.88/linux/include/linux/file.h linux/include/linux/file.h --- v2.1.88/linux/include/linux/file.h Mon Feb 23 18:12:11 1998 +++ linux/include/linux/file.h Mon Feb 23 12:55:58 1998 @@ -47,4 +47,12 @@ } } +/* + * Install a file pointer in the files structure. + */ +extern inline void fd_install(unsigned long fd, struct file *file) +{ + current->files->fd[fd] = file; +} + #endif diff -u --recursive --new-file v2.1.88/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.88/linux/include/linux/fs.h Mon Feb 23 18:12:12 1998 +++ linux/include/linux/fs.h Tue Feb 24 11:16:52 1998 @@ -638,14 +638,20 @@ extern int register_filesystem(struct file_system_type *); extern int unregister_filesystem(struct file_system_type *); +/* fs/open.c */ + asmlinkage int sys_open(const char *, int, int); asmlinkage int sys_close(unsigned int); /* yes, it's really unsigned */ - -extern void kill_fasync(struct fasync_struct *fa, int sig); +extern int do_truncate(struct dentry *, unsigned long); +extern int get_unused_fd(void); +extern void put_unused_fd(unsigned int); +extern int __fput(struct file *); +extern int close_fp(struct file *); extern char * getname(const char * filename); extern void putname(char * name); -extern int do_truncate(struct dentry *, unsigned long); + +extern void kill_fasync(struct fasync_struct *fa, int sig); extern int register_blkdev(unsigned int, const char *, struct file_operations *); extern int unregister_blkdev(unsigned int major, const char * name); extern int blkdev_open(struct inode * inode, struct file * filp); @@ -755,32 +761,6 @@ #define namei(pathname) __namei(pathname, 1) #define lnamei(pathname) __namei(pathname, 0) -#include - -/* Intended for short locks of the global data structures in inode.c. - * Could be replaced with spinlocks completely, since there is - * no blocking during manipulation of the static data; however the - * lock in invalidate_inodes() may last relatively long. - */ -extern struct semaphore vfs_sem; -extern inline void vfs_lock(void) -{ -#if 0 -#ifdef __SMP__ - down(&vfs_sem); -#endif -#endif -} - -extern inline void vfs_unlock(void) -{ -#if 0 -#ifdef __SMP__ - up(&vfs_sem); -#endif -#endif -} - extern void iput(struct inode *); extern struct inode * iget(struct super_block *, unsigned long); extern void clear_inode(struct inode *); @@ -788,10 +768,7 @@ extern void insert_inode_hash(struct inode *); extern void remove_inode_hash(struct inode *); -extern int get_unused_fd(void); -extern void put_unused_fd(int); extern struct file * get_empty_filp(void); -extern int close_fp(struct file *); extern struct buffer_head * get_hash_table(kdev_t, int, int); extern struct buffer_head * getblk(kdev_t, int, int); extern struct buffer_head * find_buffer(kdev_t dev, int block, int size); diff -u --recursive --new-file v2.1.88/linux/include/linux/if_shaper.h linux/include/linux/if_shaper.h --- v2.1.88/linux/include/linux/if_shaper.h Mon Jan 12 15:28:18 1998 +++ linux/include/linux/if_shaper.h Tue Feb 24 22:08:02 1998 @@ -5,7 +5,7 @@ #define SHAPER_QLEN 10 /* - * This is a bit speed dependant (read it shouldnt be a constant!) + * This is a bit speed dependent (read it shouldn't be a constant!) * * 5 is about right for 28.8 upwards. Below that double for every * halving of speed or so. - ie about 20 for 9600 baud. diff -u --recursive --new-file v2.1.88/linux/include/linux/iso_fs_i.h linux/include/linux/iso_fs_i.h --- v2.1.88/linux/include/linux/iso_fs_i.h Thu Feb 12 20:56:13 1998 +++ linux/include/linux/iso_fs_i.h Sat Feb 21 13:19:29 1998 @@ -6,6 +6,9 @@ */ struct iso_inode_info { unsigned int i_first_extent; + unsigned char i_file_format; + unsigned long i_next_section_ino; + off_t i_section_size; }; #endif diff -u --recursive --new-file v2.1.88/linux/include/linux/kerneld.h linux/include/linux/kerneld.h --- v2.1.88/linux/include/linux/kerneld.h Sat Nov 29 10:33:21 1997 +++ linux/include/linux/kerneld.h Mon Feb 23 10:25:15 1998 @@ -48,8 +48,10 @@ }; #ifdef __KERNEL__ +#include + extern int kerneld_send(int msgtype, int ret_size, int msgsz, - const char *text, const char *ret_val); + const char *text, const char *ret_val); /* * Request that a module should be loaded. @@ -59,8 +61,8 @@ static inline int request_module(const char *name) { return kerneld_send(KERNELD_REQUEST_MODULE, - 0 | KERNELD_WAIT, - strlen(name), name, NULL); + 0 | KERNELD_WAIT, + strlen(name), name, NULL); } /* @@ -70,8 +72,8 @@ static inline int release_module(const char *name, int waitflag) { return kerneld_send(KERNELD_RELEASE_MODULE, - 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT), - strlen(name), name, NULL); + 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT), + strlen(name), name, NULL); } /* @@ -81,8 +83,8 @@ static inline int delayed_release_module(const char *name) { return kerneld_send(KERNELD_DELAYED_RELEASE_MODULE, - 0 | KERNELD_NOWAIT, - strlen(name), name, NULL); + 0 | KERNELD_NOWAIT, + strlen(name), name, NULL); } /* @@ -94,8 +96,8 @@ static inline int cancel_release_module(const char *name) { return kerneld_send(KERNELD_CANCEL_RELEASE_MODULE, - 0 | KERNELD_NOWAIT, - strlen(name), name, NULL); + 0 | KERNELD_NOWAIT, + strlen(name), name, NULL); } /* @@ -104,8 +106,8 @@ static inline int ksystem(const char *cmd, int waitflag) { return kerneld_send(KERNELD_SYSTEM, - 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT), - strlen(cmd), cmd, NULL); + 0 | (waitflag?KERNELD_WAIT:KERNELD_NOWAIT), + strlen(cmd), cmd, NULL); } /* @@ -114,18 +116,19 @@ static inline int kerneld_route(const char *ip_route) { return kerneld_send(KERNELD_REQUEST_ROUTE, - 0 | KERNELD_WAIT, - strlen(ip_route), ip_route, NULL); + 0 | KERNELD_WAIT, + strlen(ip_route), ip_route, NULL); } /* * Handle an external screen blanker */ -static inline int kerneld_blanker(int on_off) /* 0 => "off", else "on" */ +static inline int kerneld_blanker(int on_off) { + char *s = on_off ? "on" : "off"; return kerneld_send(KERNELD_BLANKER, - 0 | (on_off?KERNELD_NOWAIT:KERNELD_WAIT), - strlen(on_off?"on":"off"), on_off?"on":"off", NULL); + 0 | (on_off ? KERNELD_NOWAIT : KERNELD_WAIT), + strlen(s), s, NULL); } #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.88/linux/include/linux/mc146818rtc.h linux/include/linux/mc146818rtc.h --- v2.1.88/linux/include/linux/mc146818rtc.h Fri Feb 6 15:33:06 1998 +++ linux/include/linux/mc146818rtc.h Tue Feb 24 11:17:04 1998 @@ -142,6 +142,8 @@ #define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ #define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ #define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ +#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ +#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ #endif /* _MC146818RTC_H */ diff -u --recursive --new-file v2.1.88/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.1.88/linux/include/linux/mm.h Fri Feb 6 15:32:54 1998 +++ linux/include/linux/mm.h Tue Feb 24 11:16:52 1998 @@ -133,7 +133,7 @@ #define PG_uptodate 3 #define PG_free_after 4 #define PG_decr_after 5 -#define PG_swap_unlock_after 6 +/* Unused 6 */ #define PG_DMA 7 #define PG_Slab 8 #define PG_swap_cache 9 @@ -146,7 +146,6 @@ #define PageUptodate(page) (test_bit(PG_uptodate, &(page)->flags)) #define PageFreeAfter(page) (test_bit(PG_free_after, &(page)->flags)) #define PageDecrAfter(page) (test_bit(PG_decr_after, &(page)->flags)) -#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags)) #define PageDMA(page) (test_bit(PG_DMA, &(page)->flags)) #define PageSlab(page) (test_bit(PG_Slab, &(page)->flags)) #define PageSwapCache(page) (test_bit(PG_swap_cache, &(page)->flags)) @@ -252,6 +251,7 @@ } /* memory.c & swap.c*/ +extern int free_memory_available(void); #define free_page(addr) free_pages((addr),0) extern void FASTCALL(free_pages(unsigned long addr, unsigned long order)); diff -u --recursive --new-file v2.1.88/linux/include/linux/parport.h linux/include/linux/parport.h --- v2.1.88/linux/include/linux/parport.h Fri Jan 30 11:28:10 1998 +++ linux/include/linux/parport.h Tue Feb 24 22:40:45 1998 @@ -3,6 +3,64 @@ #ifndef _PARPORT_H_ #define _PARPORT_H_ +/* Start off with user-visible constants */ + +/* Maximum of 8 ports per machine */ +#define PARPORT_MAX 8 + +/* Magic numbers */ +#define PARPORT_IRQ_NONE -1 +#define PARPORT_DMA_NONE -1 +#define PARPORT_IRQ_AUTO -2 +#define PARPORT_DMA_AUTO -2 +#define PARPORT_DISABLE -2 + +#define PARPORT_CONTROL_STROBE 0x1 +#define PARPORT_CONTROL_AUTOFD 0x2 +#define PARPORT_CONTROL_INIT 0x4 +#define PARPORT_CONTROL_SELECT 0x8 +#define PARPORT_CONTROL_INTEN 0x10 +#define PARPORT_CONTROL_DIRECTION 0x20 + +#define PARPORT_STATUS_ERROR 0x8 +#define PARPORT_STATUS_SELECT 0x10 +#define PARPORT_STATUS_PAPEROUT 0x20 +#define PARPORT_STATUS_ACK 0x40 +#define PARPORT_STATUS_BUSY 0x80 + +/* Type classes for Plug-and-Play probe. */ +typedef enum { + PARPORT_CLASS_LEGACY = 0, /* Non-IEEE1284 device */ + PARPORT_CLASS_PRINTER, + PARPORT_CLASS_MODEM, + PARPORT_CLASS_NET, + PARPORT_CLASS_HDC, /* Hard disk controller */ + PARPORT_CLASS_PCMCIA, + PARPORT_CLASS_MEDIA, /* Multimedia device */ + PARPORT_CLASS_FDC, /* Floppy disk controller */ + PARPORT_CLASS_PORTS, + PARPORT_CLASS_SCANNER, + PARPORT_CLASS_DIGCAM, + PARPORT_CLASS_OTHER, /* Anything else */ + PARPORT_CLASS_UNSPEC /* No CLS field in ID */ +} parport_device_class; + +/* The "modes" entry in parport is a bit field representing the following + * modes. + * Note that PARPORT_MODE_PCECPEPP is for the SMC EPP+ECP mode which is NOT + * 100% compatible with EPP. + */ +#define PARPORT_MODE_PCSPP 0x0001 +#define PARPORT_MODE_PCPS2 0x0002 +#define PARPORT_MODE_PCEPP 0x0004 +#define PARPORT_MODE_PCECP 0x0008 +#define PARPORT_MODE_PCECPEPP 0x0010 +#define PARPORT_MODE_PCECR 0x0020 /* ECR Register Exists */ +#define PARPORT_MODE_PCECPPS2 0x0040 + +/* The rest is for the kernel only */ +#ifdef __KERNEL__ + #include #include #include @@ -11,16 +69,6 @@ #define PARPORT_NEED_GENERIC_OPS -/* Maximum of 8 ports per machine */ -#define PARPORT_MAX 8 - -/* Magic numbers */ -#define PARPORT_IRQ_NONE -2 -#define PARPORT_DMA_NONE -2 -#define PARPORT_IRQ_AUTO -1 -#define PARPORT_DMA_AUTO -1 -#define PARPORT_DISABLE -2 - /* Define this later. */ struct parport; @@ -39,29 +87,29 @@ }; struct parport_operations { - void (*write_data)(struct parport *, unsigned int); - unsigned int (*read_data)(struct parport *); - void (*write_control)(struct parport *, unsigned int); - unsigned int (*read_control)(struct parport *); - unsigned int (*frob_control)(struct parport *, unsigned int mask, unsigned int val); - void (*write_econtrol)(struct parport *, unsigned int); - unsigned int (*read_econtrol)(struct parport *); - unsigned int (*frob_econtrol)(struct parport *, unsigned int mask, unsigned int val); - void (*write_status)(struct parport *, unsigned int); - unsigned int (*read_status)(struct parport *); - void (*write_fifo)(struct parport *, unsigned int); - unsigned int (*read_fifo)(struct parport *); + void (*write_data)(struct parport *, unsigned char); + unsigned char (*read_data)(struct parport *); + void (*write_control)(struct parport *, unsigned char); + unsigned char (*read_control)(struct parport *); + unsigned char (*frob_control)(struct parport *, unsigned char mask, unsigned char val); + void (*write_econtrol)(struct parport *, unsigned char); + unsigned char (*read_econtrol)(struct parport *); + unsigned char (*frob_econtrol)(struct parport *, unsigned char mask, unsigned char val); + void (*write_status)(struct parport *, unsigned char); + unsigned char (*read_status)(struct parport *); + void (*write_fifo)(struct parport *, unsigned char); + unsigned char (*read_fifo)(struct parport *); void (*change_mode)(struct parport *, int); void (*release_resources)(struct parport *); int (*claim_resources)(struct parport *); - unsigned int (*epp_write_block)(struct parport *, void *, unsigned int); - unsigned int (*epp_read_block)(struct parport *, void *, unsigned int); + size_t (*epp_write_block)(struct parport *, void *, size_t); + size_t (*epp_read_block)(struct parport *, void *, size_t); - unsigned int (*ecp_write_block)(struct parport *, void *, unsigned int, void (*fn)(struct parport *, void *, unsigned int), void *); - unsigned int (*ecp_read_block)(struct parport *, void *, unsigned int, void (*fn)(struct parport *, void *, unsigned int), void *); + int (*ecp_write_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *); + int (*ecp_read_block)(struct parport *, void *, size_t, void (*fn)(struct parport *, void *, size_t), void *); void (*save_state)(struct parport *, struct parport_state *); void (*restore_state)(struct parport *, struct parport_state *); @@ -74,36 +122,6 @@ void (*dec_use_count)(void); }; -#define PARPORT_CONTROL_STROBE 0x1 -#define PARPORT_CONTROL_AUTOFD 0x2 -#define PARPORT_CONTROL_INIT 0x4 -#define PARPORT_CONTROL_SELECT 0x8 -#define PARPORT_CONTROL_INTEN 0x10 -#define PARPORT_CONTROL_DIRECTION 0x20 - -#define PARPORT_STATUS_ERROR 0x8 -#define PARPORT_STATUS_SELECT 0x10 -#define PARPORT_STATUS_PAPEROUT 0x20 -#define PARPORT_STATUS_ACK 0x40 -#define PARPORT_STATUS_BUSY 0x80 - -/* Type classes for Plug-and-Play probe. */ -typedef enum { - PARPORT_CLASS_LEGACY = 0, /* Non-IEEE1284 device */ - PARPORT_CLASS_PRINTER, - PARPORT_CLASS_MODEM, - PARPORT_CLASS_NET, - PARPORT_CLASS_HDC, /* Hard disk controller */ - PARPORT_CLASS_PCMCIA, - PARPORT_CLASS_MEDIA, /* Multimedia device */ - PARPORT_CLASS_FDC, /* Floppy disk controller */ - PARPORT_CLASS_PORTS, - PARPORT_CLASS_SCANNER, - PARPORT_CLASS_DIGCAM, - PARPORT_CLASS_OTHER, /* Anything else */ - PARPORT_CLASS_UNSPEC /* No CLS field in ID */ -} parport_device_class; - struct parport_device_info { parport_device_class class; char *mfr; @@ -178,7 +196,7 @@ struct parport_operations *ops; void *private_data; /* for lowlevel driver */ - + int number; /* port index - the `n' in `parportn' */ spinlock_t lock; }; @@ -243,28 +261,29 @@ extern void parport_release(struct pardevice *dev); -extern __inline__ unsigned int parport_yield(struct pardevice *dev, - unsigned int block) +/* parport_yield relinquishes the port if it would be helpful to other + * drivers. The return value is the same as for parport_claim. + */ +extern __inline__ unsigned int parport_yield(struct pardevice *dev) { unsigned long int timeslip = (jiffies - dev->time); if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice)) - return 1; + return 0; parport_release(dev); - return (block)?parport_claim_or_block(dev):parport_claim(dev); + return parport_claim(dev); } -/* The "modes" entry in parport is a bit field representing the following - * modes. - * Note that LP_ECPEPP is for the SMC EPP+ECP mode which is NOT - * 100% compatible with EPP. +/* parport_yield_blocking is the same but uses parport_claim_or_block + * instead of parport_claim. */ -#define PARPORT_MODE_PCSPP 0x0001 -#define PARPORT_MODE_PCPS2 0x0002 -#define PARPORT_MODE_PCEPP 0x0004 -#define PARPORT_MODE_PCECP 0x0008 -#define PARPORT_MODE_PCECPEPP 0x0010 -#define PARPORT_MODE_PCECR 0x0020 /* ECR Register Exists */ -#define PARPORT_MODE_PCECPPS2 0x0040 +extern __inline__ unsigned int parport_yield_blocking(struct pardevice *dev) +{ + unsigned long int timeslip = (jiffies - dev->time); + if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice)) + return 0; + parport_release(dev); + return parport_claim_or_block(dev); +} /* Flags used to identify what a device does. */ #define PARPORT_DEV_TRAN 0x0000 /* We're transient. */ @@ -329,4 +348,5 @@ #define parport_claim_resources(p) (p)->ops->claim_resources(p) #endif +#endif /* __KERNEL__ */ #endif /* _PARPORT_H_ */ diff -u --recursive --new-file v2.1.88/linux/include/linux/parport_pc.h linux/include/linux/parport_pc.h --- v2.1.88/linux/include/linux/parport_pc.h Fri Jan 30 11:28:10 1998 +++ linux/include/linux/parport_pc.h Tue Feb 24 22:33:04 1998 @@ -13,80 +13,80 @@ #define STATUS 0x1 #define DATA 0 -extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned int d) +extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d) { outb(d, p->base+EPPREG); } -extern __inline__ unsigned int parport_pc_read_epp(struct parport *p) +extern __inline__ unsigned char parport_pc_read_epp(struct parport *p) { - return (unsigned int)inb(p->base+EPPREG); + return inb(p->base+EPPREG); } -extern __inline__ unsigned int parport_pc_read_configb(struct parport *p) +extern __inline__ unsigned char parport_pc_read_configb(struct parport *p) { - return (unsigned int)inb(p->base+CONFIGB); + return inb(p->base+CONFIGB); } -extern __inline__ void parport_pc_write_data(struct parport *p, unsigned int d) +extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d) { outb(d, p->base+DATA); } -extern __inline__ unsigned int parport_pc_read_data(struct parport *p) +extern __inline__ unsigned char parport_pc_read_data(struct parport *p) { - return (unsigned int)inb(p->base+DATA); + return inb(p->base+DATA); } -extern __inline__ void parport_pc_write_control(struct parport *p, unsigned int d) +extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d) { outb(d, p->base+CONTROL); } -extern __inline__ unsigned int parport_pc_read_control(struct parport *p) +extern __inline__ unsigned char parport_pc_read_control(struct parport *p) { - return (unsigned int)inb(p->base+CONTROL); + return inb(p->base+CONTROL); } -extern __inline__ unsigned int parport_pc_frob_control(struct parport *p, unsigned int mask, unsigned int val) +extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base+CONTROL); + unsigned char old = inb(p->base+CONTROL); outb(((old & ~mask) ^ val), p->base+CONTROL); return old; } -extern __inline__ void parport_pc_write_status(struct parport *p, unsigned int d) +extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d) { outb(d, p->base+STATUS); } -extern __inline__ unsigned int parport_pc_read_status(struct parport *p) +extern __inline__ unsigned char parport_pc_read_status(struct parport *p) { - return (unsigned int)inb(p->base+STATUS); + return inb(p->base+STATUS); } -extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned int d) +extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned char d) { outb(d, p->base+ECONTROL); } -extern __inline__ unsigned int parport_pc_read_econtrol(struct parport *p) +extern __inline__ unsigned char parport_pc_read_econtrol(struct parport *p) { - return (unsigned int)inb(p->base+ECONTROL); + return inb(p->base+ECONTROL); } -extern __inline__ unsigned int parport_pc_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val) +extern __inline__ unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base+ECONTROL); + unsigned char old = inb(p->base+ECONTROL); outb(((old & ~mask) ^ val), p->base+ECONTROL); return old; } extern void parport_pc_change_mode(struct parport *p, int m); -extern void parport_pc_write_fifo(struct parport *p, unsigned int v); +extern void parport_pc_write_fifo(struct parport *p, unsigned char v); -extern unsigned int parport_pc_read_fifo(struct parport *p); +extern unsigned char parport_pc_read_fifo(struct parport *p); extern void parport_pc_disable_irq(struct parport *p); @@ -100,13 +100,13 @@ extern void parport_pc_restore_state(struct parport *p, struct parport_state *s); -extern unsigned int parport_pc_epp_read_block(struct parport *p, void *buf, unsigned int length); +extern size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length); -extern unsigned int parport_pc_epp_write_block(struct parport *p, void *buf, unsigned int length); +extern size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length); -extern unsigned int parport_pc_ecp_read_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle); +extern int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle); -extern unsigned int parport_pc_ecp_write_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle); +extern int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle); extern int parport_pc_examine_irq(struct parport *p); diff -u --recursive --new-file v2.1.88/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.88/linux/include/linux/pci.h Tue Feb 17 13:12:49 1998 +++ linux/include/linux/pci.h Mon Feb 23 10:25:10 1998 @@ -503,6 +503,7 @@ #define PCI_VENDOR_ID_CONTAQ 0x1080 #define PCI_DEVICE_ID_CONTAQ_82C599 0x0600 +/* ??? Alpha SX164 has reference to device nr 0xc693 as a CYPRESS bridge. */ #define PCI_VENDOR_ID_FOREX 0x1083 diff -u --recursive --new-file v2.1.88/linux/include/linux/sdla_x25.h linux/include/linux/sdla_x25.h --- v2.1.88/linux/include/linux/sdla_x25.h Mon Jan 12 14:46:26 1998 +++ linux/include/linux/sdla_x25.h Tue Feb 24 22:08:02 1998 @@ -159,7 +159,7 @@ #define X25RES_PROTO_VIOLATION 0x41 /* protocol violation occured */ #define X25RES_PKT_TIMEOUT 0x42 /* X.25 packet time out */ #define X25RES_PKT_RETRY_LIMIT 0x43 /* X.25 packet retry limit exceeded */ -/*----- Command-dependant results -----*/ +/*----- Command-dependent results -----*/ #define X25RES_LINK_DISC 0x00 /* HDLC_LINK_STATUS */ #define X25RES_LINK_IN_ABM 0x01 /* HDLC_LINK_STATUS */ #define X25RES_NO_DATA 0x01 /* HDLC_READ/READ_TRACE_DATA*/ diff -u --recursive --new-file v2.1.88/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.1.88/linux/include/linux/swap.h Mon Feb 23 18:12:12 1998 +++ linux/include/linux/swap.h Mon Feb 23 15:24:32 1998 @@ -9,6 +9,8 @@ #ifdef __KERNEL__ +#undef DEBUG_SWAP + #include #define SWP_USED 1 @@ -21,7 +23,6 @@ kdev_t swap_device; struct dentry * swap_file; unsigned char * swap_map; - unsigned char * swap_lockmap; unsigned int lowest_bit; unsigned int highest_bit; unsigned int cluster_next; @@ -53,11 +54,7 @@ /* linux/mm/page_io.c */ extern void rw_swap_page(int, unsigned long, char *, int); -#define read_swap_page(nr,buf) \ - rw_swap_page(READ,(nr),(buf),1) -#define write_swap_page(nr,buf) \ - rw_swap_page(WRITE,(nr),(buf),1) -extern void swap_after_unlock_page (unsigned long entry); +extern void rw_swap_page_nocache(int, unsigned long, char *); /* linux/mm/page_alloc.c */ extern void swap_in(struct task_struct *, struct vm_area_struct *, @@ -68,6 +65,8 @@ extern void show_swap_cache_info(void); extern int add_to_swap_cache(struct page *, unsigned long); extern void swap_duplicate(unsigned long); +extern struct page * read_swap_cache_async(unsigned long, int); +#define read_swap_cache(entry) read_swap_cache_async(entry, 1); /* linux/mm/swapfile.c */ extern unsigned int nr_swapfiles; @@ -107,12 +106,18 @@ /* * Work out if there are any other processes sharing this page, ignoring - * any page reference coming from the page or swap cache. + * any page reference coming from the swap cache, or from outstanding + * swap IO on this page. (The page cache _does_ count as another valid + * reference to the page, however.) */ static inline int is_page_shared(struct page *page) { int count = atomic_read(&page->count); - if (page->inode) + if (PageReserved(page)) + return 1; + if (page->inode == &swapper_inode) + count--; + if (PageFreeAfter(page)) count--; return (count > 1); } diff -u --recursive --new-file v2.1.88/linux/include/linux/wireless.h linux/include/linux/wireless.h --- v2.1.88/linux/include/linux/wireless.h Fri Feb 6 15:34:56 1998 +++ linux/include/linux/wireless.h Tue Feb 24 22:08:02 1998 @@ -213,7 +213,7 @@ struct iw_statistics { __u8 status; /* Status - * - device dependant for now */ + * - device dependent for now */ struct iw_quality qual; /* Quality of the link * (instant/mean/max) */ diff -u --recursive --new-file v2.1.88/linux/include/net/neighbour.h linux/include/net/neighbour.h --- v2.1.88/linux/include/net/neighbour.h Fri Feb 6 15:34:56 1998 +++ linux/include/net/neighbour.h Tue Feb 24 11:18:57 1998 @@ -249,12 +249,12 @@ return 0; } -extern __inline__ int neigh_table_lock(struct neigh_table *tbl) +extern __inline__ void neigh_table_lock(struct neigh_table *tbl) { atomic_inc(&tbl->lock); } -extern __inline__ int neigh_table_unlock(struct neigh_table *tbl) +extern __inline__ void neigh_table_unlock(struct neigh_table *tbl) { atomic_dec(&tbl->lock); } diff -u --recursive --new-file v2.1.88/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.1.88/linux/include/net/tcp.h Mon Feb 23 18:12:12 1998 +++ linux/include/net/tcp.h Tue Feb 24 22:08:02 1998 @@ -54,7 +54,7 @@ extern int sysctl_tcp_timestamps; extern int sysctl_tcp_window_scaling; -/* These are AF independant. */ +/* These are AF independent. */ static __inline__ int tcp_bhashfn(__u16 lport) { return (lport ^ (lport >> 7)) & (TCP_BHTABLE_SIZE - 1); diff -u --recursive --new-file v2.1.88/linux/ipc/shm.c linux/ipc/shm.c --- v2.1.88/linux/ipc/shm.c Tue Dec 9 09:49:59 1997 +++ linux/ipc/shm.c Tue Feb 24 10:55:03 1998 @@ -689,7 +689,7 @@ goto done; } if (!pte_none(pte)) { - read_swap_page(pte_val(pte), (char *) page); + rw_swap_page_nocache(READ, pte_val(pte), (char *)page); pte = __pte(shp->shm_pages[idx]); if (pte_present(pte)) { free_page (page); /* doesn't sleep */ @@ -820,7 +820,7 @@ if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) != 1) goto check_table; shp->shm_pages[idx] = swap_nr; - write_swap_page (swap_nr, (char *) pte_page(page)); + rw_swap_page_nocache (WRITE, swap_nr, (char *) pte_page(page)); free_page(pte_page(page)); swap_successes++; shm_swp++; diff -u --recursive --new-file v2.1.88/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.1.88/linux/kernel/ksyms.c Thu Feb 12 20:56:13 1998 +++ linux/kernel/ksyms.c Tue Feb 24 22:49:54 1998 @@ -206,6 +206,10 @@ EXPORT_SYMBOL(find_inode_number); EXPORT_SYMBOL(is_subdir); +#ifdef CONFIG_AUTOFS_FS_MODULE +EXPORT_SYMBOL(locks_remove_flock); +#endif + #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) EXPORT_SYMBOL(do_nfsservctl); #endif diff -u --recursive --new-file v2.1.88/linux/kernel/module.c linux/kernel/module.c --- v2.1.88/linux/kernel/module.c Thu Feb 12 20:56:13 1998 +++ linux/kernel/module.c Tue Feb 24 22:08:02 1998 @@ -305,17 +305,17 @@ for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) { struct module *o, *d = dep->dep; - /* Make sure the indicated dependancies are really modules. */ + /* Make sure the indicated dependencies are really modules. */ if (d == mod) { printk(KERN_ERR "init_module: self-referential " - "dependancy in mod->deps.\n"); + "dependency in mod->deps.\n"); goto err3; } for (o = module_list; o != &kernel_module; o = o->next) if (o == d) goto found_dep; - printk(KERN_ERR "init_module: found dependancy that is " + printk(KERN_ERR "init_module: found dependency that is " "(no longer?) a module.\n"); goto err3; @@ -790,7 +790,7 @@ mod->flags &= ~MOD_RUNNING; } - /* Remove the module from the dependancy lists. */ + /* Remove the module from the dependency lists. */ for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) { struct module_ref **pp; diff -u --recursive --new-file v2.1.88/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.1.88/linux/kernel/sysctl.c Sat Jan 10 15:15:21 1998 +++ linux/kernel/sysctl.c Sat Feb 21 13:27:56 1998 @@ -523,9 +523,7 @@ proc_unregister(root, de->low_ino); table->de = NULL; kfree(de); - } else - printk("unregister_proc_table: %s not empty!\n", - table->procname); + } } } diff -u --recursive --new-file v2.1.88/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.88/linux/mm/filemap.c Tue Feb 3 18:26:30 1998 +++ linux/mm/filemap.c Mon Feb 23 15:24:32 1998 @@ -162,10 +162,12 @@ if (test_and_clear_bit(PG_referenced, &page->flags)) break; - /* is it a page cache page? */ + /* is it a swap-cache or page-cache page? */ if (page->inode) { - if (page->inode == &swapper_inode) - panic ("Shrinking a swap cache page"); + if (PageSwapCache(page)) { + delete_from_swap_cache(page); + return 1; + } remove_page_from_hash_queue(page); remove_page_from_inode_queue(page); __free_page(page); diff -u --recursive --new-file v2.1.88/linux/mm/memory.c linux/mm/memory.c --- v2.1.88/linux/mm/memory.c Tue Feb 17 13:12:49 1998 +++ linux/mm/memory.c Mon Feb 23 15:24:32 1998 @@ -267,8 +267,10 @@ } if (cow) pte = pte_wrprotect(pte); +#if 0 /* No longer needed with the new swap cache code */ if (delete_from_swap_cache(&mem_map[page_nr])) pte = pte_mkdirty(pte); +#endif set_pte(dst_pte, pte_mkold(pte)); set_pte(src_pte, pte); atomic_inc(&mem_map[page_nr].count); @@ -616,8 +618,11 @@ unsigned long old_page, new_page; struct page * page_map; - new_page = __get_free_page(GFP_KERNEL); pte = *page_table; + new_page = __get_free_page(GFP_KERNEL); + /* Did someone else copy this page for us while we slept? */ + if (pte_val(*page_table) != pte_val(pte)) + goto end_wp_page; if (!pte_present(pte)) goto end_wp_page; if (pte_write(pte)) @@ -626,15 +631,12 @@ if (MAP_NR(old_page) >= max_mapnr) goto bad_wp_page; tsk->min_flt++; - page_map = mem_map + MAP_NR(old_page); - if (PageSwapCache(page_map)) - delete_from_swap_cache(page_map); /* * Do we need to copy? */ - if (atomic_read(&mem_map[MAP_NR(old_page)].count) != 1) { + if (is_page_shared(page_map)) { if (new_page) { if (PageReserved(mem_map + MAP_NR(old_page))) ++vma->vm_mm->rss; @@ -654,6 +656,8 @@ oom(tsk); return; } + if (PageSwapCache(page_map)) + delete_from_swap_cache(page_map); flush_cache_page(vma, address); set_pte(page_table, pte_mkdirty(pte_mkwrite(pte))); flush_tlb_page(vma, address); diff -u --recursive --new-file v2.1.88/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.1.88/linux/mm/page_alloc.c Thu Jan 15 21:35:49 1998 +++ linux/mm/page_alloc.c Mon Feb 23 15:24:32 1998 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include /* for cli()/sti() */ @@ -101,6 +102,30 @@ static spinlock_t page_alloc_lock; #endif +/* + * This routine is used by the kernel swap deamon to determine + * whether we have "enough" free pages. It is fairly arbitrary, + * but this had better return false if any reasonable "get_free_page()" + * allocation could currently fail.. + * + * Right now we just require that the highest memory order should + * have at least two entries. Whether this makes sense or not + * under real load is to be tested, but it also gives us some + * guarantee about memory fragmentation (essentially, it means + * that there should be at least two large areas available). + */ +int free_memory_available(void) +{ + int retval; + unsigned long flags; + struct free_area_struct * last = free_area + NR_MEM_LISTS - 1; + + spin_lock_irqsave(&page_alloc_lock, flags); + retval = (last->next != memory_head(last)) && (last->next->next != memory_head(last)); + spin_unlock_irqrestore(&page_alloc_lock, flags); + return retval; +} + static inline void free_pages_ok(unsigned long map_nr, unsigned long order) { struct free_area_struct *area = free_area + order; @@ -328,31 +353,38 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma, pte_t * page_table, unsigned long entry, int write_access) { - unsigned long page = __get_free_page(GFP_KERNEL); + unsigned long page; + struct page *page_map; + + page_map = read_swap_cache(entry); if (pte_val(*page_table) != entry) { - free_page(page); + if (page_map) + free_page_and_swap_cache(page_address(page_map)); return; } - if (!page) { + if (!page_map) { set_pte(page_table, BAD_PAGE); swap_free(entry); oom(tsk); return; } - read_swap_page(entry, (char *) page); - if (pte_val(*page_table) != entry) { - free_page(page); - return; - } + + page = page_address(page_map); vma->vm_mm->rss++; - tsk->maj_flt++; - if (!write_access && add_to_swap_cache(&mem_map[MAP_NR(page)], entry)) { - /* keep swap page allocated for the moment (swap cache) */ + tsk->min_flt++; + swap_free(entry); + + if (!write_access || is_page_shared(page_map)) { set_pte(page_table, mk_pte(page, vma->vm_page_prot)); return; } + + /* The page is unshared, and we want write access. In this + case, it is safe to tear down the swap cache and give the + page over entirely to this process. */ + + delete_from_swap_cache(page_map); set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)))); - swap_free(entry); return; } diff -u --recursive --new-file v2.1.88/linux/mm/page_io.c linux/mm/page_io.c --- v2.1.88/linux/mm/page_io.c Mon Jan 12 14:33:20 1998 +++ linux/mm/page_io.c Tue Feb 24 10:55:35 1998 @@ -6,6 +6,7 @@ * Swap reorganised 29.12.95, * Asynchronous swapping added 30.12.95. Stephen Tweedie * Removed race in async swapping. 14.4.1996. Bruno Haible + * Add swap of shared pages through the page cache. 20.2.1998. Stephen Tweedie */ #include @@ -27,26 +28,36 @@ #include #include -static struct wait_queue * lock_queue = NULL; - /* * Reads or writes a swap page. * wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O. + * All IO to swap files (as opposed to swap partitions) is done + * synchronously. * - * Important prevention of race condition: The first thing we do is set a lock - * on this swap page, which lasts until I/O completes. This way a - * write_swap_page(entry) immediately followed by a read_swap_page(entry) - * on the same entry will first complete the write_swap_page(). Fortunately, - * not more than one write_swap_page() request can be pending per entry. So - * all races the caller must catch are: multiple read_swap_page() requests - * on the same entry. + * Important prevention of race condition: the caller *must* atomically + * create a unique swap cache entry for this swap page before calling + * rw_swap_page, and must lock that page. By ensuring that there is a + * single page of memory reserved for the swap entry, the normal VM page + * lock on that page also doubles as a lock on swap entries. Having only + * one lock to deal with per swap entry (rather than locking swap and memory + * independently) also makes it easier to make certain swapping operations + * atomic, which is particularly important when we are trying to ensure + * that shared pages stay shared while being swapped. */ + void rw_swap_page(int rw, unsigned long entry, char * buf, int wait) { unsigned long type, offset; struct swap_info_struct * p; struct page *page = mem_map + MAP_NR(buf); +#ifdef DEBUG_SWAP + printk ("DebugVM: %s_swap_page entry %08lx, page %p (count %d), %s\n", + (rw == READ) ? "read" : "write", + entry, buf, atomic_read(&page->count), + wait ? "wait" : "nowait"); +#endif + if (page->inode && page->inode != &swapper_inode) panic ("Tried to swap a non-swapper page"); type = SWP_TYPE(entry); @@ -61,31 +72,28 @@ return; } if (p->swap_map && !p->swap_map[offset]) { - printk("Hmm.. Trying to use unallocated swap (%08lx)\n", entry); + printk("Hmm.. Trying to %s unallocated swap (%08lx)\n", + (rw == READ) ? "read" : "write", + entry); return; } if (!(p->flags & SWP_USED)) { printk("Trying to swap to unused swap-device\n"); return; } - /* - * For now, this is not legal! - */ - if (PageSwapCache(page)) - panic ("Trying to swap a swap-cache page!"); - /* Make sure we are the only process doing I/O with this swap page. */ - while (test_and_set_bit(offset,p->swap_lockmap)) { - run_task_queue(&tq_disk); - sleep_on(&lock_queue); + if (!PageLocked(page)) { + printk("VM: swap page is unlocked\n"); + return; } - - if (rw == READ) + + if (rw == READ) { + clear_bit(PG_uptodate, &page->flags); kstat.pswpin++; - else + } else kstat.pswpout++; + atomic_inc(&page->count); - wait_on_page(page); /* * Make sure that we have a swap cache association for this * page. We need this to find which swap page to unlock once @@ -94,17 +102,19 @@ * as if it were: we are not allowed to manipulate the inode * hashing for locked pages. */ - if (PageSwapCache(page)) { - if (page->offset != entry) - panic ("swap entry mismatch"); - } else - page->offset = entry; + if (!PageSwapCache(page)) { + printk("VM: swap page is not in swap cache\n"); + return; + } + if (page->offset != entry) { + printk ("swap entry mismatch"); + return; + } if (p->swap_device) { if (!wait) { set_bit(PG_free_after, &page->flags); set_bit(PG_decr_after, &page->flags); - set_bit(PG_swap_unlock_after, &page->flags); atomic_inc(&nr_async_pages); } ll_rw_page(rw,p->swap_device,offset,buf); @@ -155,38 +165,51 @@ } } ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf); + /* Unlike ll_rw_page, ll_rw_swap_file won't unlock the + page for us. */ + clear_bit(PG_locked, &page->flags); + wake_up(&page->wait); } else printk("rw_swap_page: no swap file or device\n"); atomic_dec(&page->count); - if (offset && !test_and_clear_bit(offset,p->swap_lockmap)) - printk("rw_swap_page: lock already cleared\n"); - wake_up(&lock_queue); +#ifdef DEBUG_SWAP + printk ("DebugVM: %s_swap_page finished on page %p (count %d)\n", + (rw == READ) ? "read" : "write", + buf, atomic_read(&page->count)); +#endif } - -/* This is run when asynchronous page I/O has completed. */ -void swap_after_unlock_page (unsigned long entry) +/* + * Setting up a new swap file needs a simple wrapper just to read the + * swap signature. SysV shared memory also needs a simple wrapper. + */ +void rw_swap_page_nocache(int rw, unsigned long entry, char *buffer) { - unsigned long type, offset; - struct swap_info_struct * p; - - type = SWP_TYPE(entry); - if (type >= nr_swapfiles) { - printk("swap_after_unlock_page: bad swap-device\n"); + struct page *page; + + page = mem_map + MAP_NR((unsigned long) buffer); + wait_on_page(page); + set_bit(PG_locked, &page->flags); + if (test_and_set_bit(PG_swap_cache, &page->flags)) { + printk ("VM: read_swap_page: page already in swap cache!\n"); return; } - p = &swap_info[type]; - offset = SWP_OFFSET(entry); - if (offset >= p->max) { - printk("swap_after_unlock_page: weirdness\n"); + if (page->inode) { + printk ("VM: read_swap_page: page already in page cache!\n"); return; } - if (!test_and_clear_bit(offset,p->swap_lockmap)) - printk("swap_after_unlock_page: lock already cleared\n"); - wake_up(&lock_queue); + page->inode = &swapper_inode; + page->offset = entry; + atomic_inc(&page->count); /* Protect from shrink_mmap() */ + rw_swap_page(rw, entry, buffer, 1); + atomic_dec(&page->count); + page->inode = 0; + clear_bit(PG_swap_cache, &page->flags); } + + /* * Swap partitions are now read via brw_page. ll_rw_page is an * asynchronous function now --- we must call wait_on_page afterwards @@ -211,7 +234,7 @@ panic("ll_rw_page: bad block dev cmd, must be R/W"); } page = mem_map + MAP_NR(buffer); - if (test_and_set_bit(PG_locked, &page->flags)) - panic ("ll_rw_page: page already locked"); + if (!PageLocked(page)) + panic ("ll_rw_page: page not already locked"); brw_page(rw, page, dev, &block, PAGE_SIZE, 0); } diff -u --recursive --new-file v2.1.88/linux/mm/swap_state.c linux/mm/swap_state.c --- v2.1.88/linux/mm/swap_state.c Mon Jan 12 14:33:20 1998 +++ linux/mm/swap_state.c Mon Feb 23 15:24:32 1998 @@ -55,29 +55,33 @@ int add_to_swap_cache(struct page *page, unsigned long entry) { - struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)]; - #ifdef SWAP_CACHE_INFO swap_cache_add_total++; #endif - if (PageLocked(page)) - panic("Adding page cache to locked page"); - if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) { - if (PageTestandSetSwapCache(page)) - panic("swap_cache: replacing non-empty entry"); - if (page->inode) - panic("swap_cache: replacing page-cached entry"); - atomic_inc(&page->count); - page->inode = &swapper_inode; - page->offset = entry; - add_page_to_hash_queue(page, &swapper_inode, entry); - add_page_to_inode_queue(&swapper_inode, page); -#ifdef SWAP_CACHE_INFO - swap_cache_add_success++; +#ifdef DEBUG_SWAP + printk("DebugVM: add_to_swap_cache(%08lx count %d, entry %08lx)\n", + page_address(page), atomic_read(&page->count), entry); #endif - return 1; + if (PageTestandSetSwapCache(page)) { + printk("swap_cache: replacing non-empty entry %08lx " + "on page %08lx", + page->offset, page_address(page)); + return 0; } - return 0; + if (page->inode) { + printk("swap_cache: replacing page-cached entry " + "on page %08lx", page_address(page)); + return 0; + } + atomic_inc(&page->count); + page->inode = &swapper_inode; + page->offset = entry; + add_page_to_hash_queue(page, &swapper_inode, entry); + add_page_to_inode_queue(&swapper_inode, page); +#ifdef SWAP_CACHE_INFO + swap_cache_add_success++; +#endif + return 1; } /* @@ -110,6 +114,10 @@ entry, p->swap_map[offset]); p->swap_map[offset] = 127; } +#ifdef DEBUG_SWAP + printk("DebugVM: swap_duplicate(entry %08lx, count now %d)\n", + entry, p->swap_map[offset]); +#endif out: return; @@ -120,25 +128,37 @@ printk("swap_duplicate: offset exceeds max\n"); goto out; bad_unused: - printk("swap_duplicate: unused page\n"); + printk("swap_duplicate at %8p: unused page\n", + __builtin_return_address(0)); goto out; } void remove_from_swap_cache(struct page *page) { - if (!page->inode) - panic ("Removing swap cache page with zero inode hash"); - if (page->inode != &swapper_inode) - panic ("Removing swap cache page with wrong inode hash"); - if (PageLocked(page)) - panic ("Removing swap cache from locked page"); + if (!page->inode) { + printk ("VM: Removing swap cache page with zero inode hash " + "on page %08lx", page_address(page)); + return; + } + if (page->inode != &swapper_inode) { + printk ("VM: Removing swap cache page with wrong inode hash " + "on page %08lx", page_address(page)); + } /* * This will be a legal case once we have a more mature swap cache. */ - if (atomic_read(&page->count) == 1) - panic ("Removing page cache on unshared page"); + if (atomic_read(&page->count) == 1) { + printk ("VM: Removing page cache on unshared page %08lx", + page_address(page)); + return; + } + +#ifdef DEBUG_SWAP + printk("DebugVM: remove_from_swap_cache(%08lx count %d)\n", + page_address(page), atomic_read(&page->count)); +#endif remove_page_from_hash_queue (page); remove_page_from_inode_queue (page); PageClearSwapCache (page); @@ -172,6 +192,11 @@ #ifdef SWAP_CACHE_INFO swap_cache_del_success++; #endif +#ifdef DEBUG_SWAP + printk("DebugVM: delete_from_swap_cache(%08lx count %d, " + "entry %08lx)\n", + page_address(page), atomic_read(&page->count), entry); +#endif remove_from_swap_cache (page); swap_free (entry); return 1; @@ -190,8 +215,86 @@ /* * If we are the only user, then free up the swap cache. */ - if (PageSwapCache(page) && !is_page_shared(page)) + if (PageSwapCache(page) && !is_page_shared(page)) { delete_from_swap_cache(page); + } free_page(addr); } + + +/* + * Lookup a swap entry in the swap cache. We need to be careful about + * locked pages. A found page will be returned with its refcount + * incremented. + */ + +static struct page * lookup_swap_cache(unsigned long entry) +{ + struct page *found; + + while (1) { + found = find_page(&swapper_inode, entry); + if (!found) + return 0; + if (found->inode != &swapper_inode + || !PageSwapCache(found)) { + __free_page(found); + printk ("VM: Found a non-swapper swap page!\n"); + return 0; + } + if (!PageLocked(found)) + return found; + __free_page(found); + __wait_on_page(found); + } +} + +/* + * Locate a page of swap in physical memory, reserving swap cache space + * and reading the disk if it is not already cached. If wait==0, we are + * only doing readahead, so don't worry if the page is already locked. + */ + +struct page * read_swap_cache_async(unsigned long entry, int wait) +{ + struct page *found_page, *new_page = 0; + unsigned long new_page_addr = 0; + +#ifdef DEBUG_SWAP + printk("DebugVM: read_swap_cache_async entry %08lx%s\n", + entry, wait ? ", wait" : ""); +#endif +repeat: + found_page = lookup_swap_cache(entry); + if (found_page) { + if (new_page) + __free_page(new_page); + return found_page; + } + + /* The entry is not present. Lock down a new page, add it to + * the swap cache and read its contents. */ + if (!new_page) { + new_page_addr = __get_free_page(GFP_KERNEL); + if (!new_page_addr) + return 0; /* Out of memory */ + new_page = mem_map + MAP_NR(new_page_addr); + goto repeat; /* We might have stalled */ + } + + if (!add_to_swap_cache(new_page, entry)) { + free_page(new_page_addr); + return 0; + } + swap_duplicate(entry); /* Account for the swap cache */ + set_bit(PG_locked, &new_page->flags); + rw_swap_page(READ, entry, (char *) new_page_addr, wait); +#ifdef DEBUG_SWAP + printk("DebugVM: read_swap_cache_async created " + "entry %08lx at %p\n", + entry, (char *) page_address(new_page)); +#endif + return new_page; +} + diff -u --recursive --new-file v2.1.88/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.1.88/linux/mm/swapfile.c Mon Jan 12 14:33:20 1998 +++ linux/mm/swapfile.c Mon Feb 23 15:24:32 1998 @@ -21,6 +21,7 @@ #include #include /* for blk_size */ #include +#include #include #include @@ -51,8 +52,6 @@ offset = si->cluster_next++; if (si->swap_map[offset]) continue; - if (test_bit(offset, si->swap_lockmap)) - continue; si->cluster_nr--; goto got_page; } @@ -61,8 +60,6 @@ for (offset = si->lowest_bit; offset <= si->highest_bit ; offset++) { if (si->swap_map[offset]) continue; - if (test_bit(offset, si->swap_lockmap)) - continue; si->lowest_bit = offset; got_page: si->swap_map[offset] = 1; @@ -153,6 +150,10 @@ if (!--p->swap_map[offset]) nr_swap_pages++; } +#ifdef DEBUG_SWAP + printk("DebugVM: swap_free(entry %08lx, count now %d)\n", + entry, p->swap_map[offset]); +#endif out: return; @@ -173,42 +174,38 @@ /* * The swap entry has been read in advance, and we return 1 to indicate * that the page has been used or is no longer needed. + * + * Always set the resulting pte to be nowrite (the same as COW pages + * after one process has exited). We don't know just how many ptes will + * share this swap entry, so be cautious and let do_wp_page work out + * what to do if a write is requested later. */ -static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address, +static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address, pte_t *dir, unsigned long entry, unsigned long page) { pte_t pte = *dir; if (pte_none(pte)) - return 0; + return; if (pte_present(pte)) { - struct page *pg; - unsigned long page_nr = MAP_NR(pte_page(pte)); - unsigned long pg_swap_entry; - - if (page_nr >= max_mapnr) - return 0; - pg = mem_map + page_nr; - if (!(pg_swap_entry = in_swap_cache(pg))) - return 0; - if (SWP_TYPE(pg_swap_entry) != SWP_TYPE(entry)) - return 0; - delete_from_swap_cache(pg); + /* If this entry is swap-cached, then page must already + hold the right address for any copies in physical + memory */ + if (pte_page(pte) != page) + return; + /* We will be removing the swap cache in a moment, so... */ set_pte(dir, pte_mkdirty(pte)); - if (pg_swap_entry != entry) - return 0; - free_page(page); - return 1; + return; } if (pte_val(pte) != entry) - return 0; - set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)))); - ++vma->vm_mm->rss; + return; + set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); swap_free(entry); - return 1; + atomic_inc(&mem_map[MAP_NR(page)].count); + ++vma->vm_mm->rss; } -static inline int unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, +static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long size, unsigned long offset, unsigned long entry, unsigned long page) { @@ -216,11 +213,11 @@ unsigned long end; if (pmd_none(*dir)) - return 0; + return; if (pmd_bad(*dir)) { printk("unuse_pmd: bad pmd (%08lx)\n", pmd_val(*dir)); pmd_clear(dir); - return 0; + return; } pte = pte_offset(dir, address); offset += address & PMD_MASK; @@ -229,16 +226,13 @@ if (end > PMD_SIZE) end = PMD_SIZE; do { - if (unuse_pte(vma, offset+address-vma->vm_start, pte, entry, - page)) - return 1; + unuse_pte(vma, offset+address-vma->vm_start, pte, entry, page); address += PAGE_SIZE; pte++; } while (address < end); - return 0; } -static inline int unuse_pgd(struct vm_area_struct * vma, pgd_t *dir, +static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long size, unsigned long entry, unsigned long page) { @@ -246,11 +240,11 @@ unsigned long offset, end; if (pgd_none(*dir)) - return 0; + return; if (pgd_bad(*dir)) { printk("unuse_pgd: bad pgd (%08lx)\n", pgd_val(*dir)); pgd_clear(dir); - return 0; + return; } pmd = pmd_offset(dir, address); offset = address & PGDIR_MASK; @@ -259,30 +253,26 @@ if (end > PGDIR_SIZE) end = PGDIR_SIZE; do { - if (unuse_pmd(vma, pmd, address, end - address, offset, entry, - page)) - return 1; + unuse_pmd(vma, pmd, address, end - address, offset, entry, + page); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); - return 0; } -static int unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir, +static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir, unsigned long entry, unsigned long page) { unsigned long start = vma->vm_start, end = vma->vm_end; while (start < end) { - if (unuse_pgd(vma, pgdir, start, end - start, entry, page)) - return 1; + unuse_pgd(vma, pgdir, start, end - start, entry, page); start = (start + PGDIR_SIZE) & PGDIR_MASK; pgdir++; } - return 0; } -static int unuse_process(struct mm_struct * mm, unsigned long entry, +static void unuse_process(struct mm_struct * mm, unsigned long entry, unsigned long page) { struct vm_area_struct* vma; @@ -291,13 +281,12 @@ * Go through process' page directory. */ if (!mm || mm == &init_mm) - return 0; + return; for (vma = mm->mmap; vma; vma = vma->vm_next) { pgd_t * pgd = pgd_offset(mm, vma->vm_start); - if (unuse_vma(vma, pgd, entry, page)) - return 1; + unuse_vma(vma, pgd, entry, page); } - return 0; + return; } /* @@ -310,19 +299,14 @@ struct swap_info_struct * si = &swap_info[type]; struct task_struct *p; unsigned long page = 0; + struct page *page_map; unsigned long entry; int i; while (1) { - if (!page) { - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - } - /* - * Find a swap page in use and read it in. - */ + * Find a swap page in use and read it in. + */ for (i = 1 , entry = 0; i < si->max ; i++) { if (si->swap_map[i] > 0 && si->swap_map[i] != 0x80) { entry = SWP_ENTRY(type, i); @@ -331,36 +315,31 @@ } if (!entry) break; - read_swap_page(entry, (char *) page); + /* Get a page for the entry, using the existing swap + cache page if there is one. Otherwise, get a clean + page and read the swap into it. */ + page_map = read_swap_cache(entry); + if (!page_map) + return -ENOMEM; + page = page_address(page_map); read_lock(&tasklist_lock); - for_each_task(p) { - if (unuse_process(p->mm, entry, page)) { - page = 0; - goto unlock; - } - } - unlock: + for_each_task(p) + unuse_process(p->mm, entry, page); read_unlock(&tasklist_lock); - if (page) { - /* - * If we couldn't find an entry, there are several - * possible reasons: someone else freed it first, - * we freed the last reference to an overflowed entry, - * or the system has lost track of the use counts. - */ - if (si->swap_map[i] != 0) { - if (si->swap_map[i] != 127) - printk("try_to_unuse: entry %08lx " - "not in use\n", entry); - si->swap_map[i] = 0; - nr_swap_pages++; - } + /* Now get rid of the extra reference to the temporary + page we've been using. */ + if (PageSwapCache(page_map)) + delete_from_swap_cache(page_map); + free_page(page); + if (si->swap_map[i] != 0) { + if (si->swap_map[i] != 127) + printk("try_to_unuse: entry %08lx " + "not in use\n", entry); + si->swap_map[i] = 0; + nr_swap_pages++; } } - - if (page) - free_page(page); return 0; } @@ -371,7 +350,7 @@ struct file filp; int i, type, prev; int err = -EPERM; - + lock_kernel(); if (!suser()) goto out; @@ -445,8 +424,6 @@ p->swap_device = 0; vfree(p->swap_map); p->swap_map = NULL; - free_page((long) p->swap_lockmap); - p->swap_lockmap = NULL; p->flags = 0; err = 0; out: @@ -506,6 +483,7 @@ int error = -EPERM; struct file filp; static int least_priority = 0; + unsigned char *avail_map = 0; lock_kernel(); if (!suser()) @@ -523,7 +501,6 @@ p->swap_file = NULL; p->swap_device = 0; p->swap_map = NULL; - p->swap_lockmap = NULL; p->lowest_bit = 0; p->highest_bit = 0; p->cluster_nr = 0; @@ -566,24 +543,24 @@ } } else if (!S_ISREG(swap_dentry->d_inode->i_mode)) goto bad_swap; - p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER); - if (!p->swap_lockmap) { + avail_map = (unsigned char *) get_free_page(GFP_USER); + if (!avail_map) { printk("Unable to start swapping: out of memory :-)\n"); error = -ENOMEM; goto bad_swap; } - read_swap_page(SWP_ENTRY(type,0), (char *) p->swap_lockmap); - if (memcmp("SWAP-SPACE",p->swap_lockmap+PAGE_SIZE-10,10)) { + rw_swap_page_nocache(READ, SWP_ENTRY(type,0), (char *) avail_map); + if (memcmp("SWAP-SPACE",avail_map+PAGE_SIZE-10,10)) { printk("Unable to find swap-space signature\n"); error = -EINVAL; goto bad_swap; } - memset(p->swap_lockmap+PAGE_SIZE-10,0,10); + memset(avail_map+PAGE_SIZE-10,0,10); j = 0; p->lowest_bit = 0; p->highest_bit = 0; for (i = 1 ; i < 8*PAGE_SIZE ; i++) { - if (test_bit(i,p->swap_lockmap)) { + if (test_bit(i,avail_map)) { if (!p->lowest_bit) p->lowest_bit = i; p->highest_bit = i; @@ -602,13 +579,12 @@ goto bad_swap; } for (i = 1 ; i < p->max ; i++) { - if (test_bit(i,p->swap_lockmap)) + if (test_bit(i,avail_map)) p->swap_map[i] = 0; else p->swap_map[i] = 0x80; } p->swap_map[0] = 0x80; - memset(p->swap_lockmap,0,PAGE_SIZE); p->flags = SWP_WRITEOK; p->pages = j; nr_swap_pages += j; @@ -635,15 +611,15 @@ if(filp.f_op && filp.f_op->release) filp.f_op->release(filp.f_dentry->d_inode,&filp); bad_swap_2: - free_page((long) p->swap_lockmap); vfree(p->swap_map); dput(p->swap_file); p->swap_device = 0; p->swap_file = NULL; p->swap_map = NULL; - p->swap_lockmap = NULL; p->flags = 0; out: + if (avail_map) + free_page((long) avail_map); unlock_kernel(); return error; } diff -u --recursive --new-file v2.1.88/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.1.88/linux/mm/vmscan.c Thu Jan 15 21:07:58 1998 +++ linux/mm/vmscan.c Wed Feb 25 12:44:55 1998 @@ -7,7 +7,7 @@ * kswapd added: 7.1.96 sct * Removed kswapd_ctl limits, and swap out as many pages as needed * to bring the system back to free_pages_high: 2.4.97, Rik van Riel. - * Version: $Id: vmscan.c,v 1.23 1997/04/12 04:31:05 davem Exp $ + * Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $ */ #include @@ -80,73 +80,149 @@ || PageLocked(page_map) || ((gfp_mask & __GFP_DMA) && !PageDMA(page_map))) return 0; - /* Deal with page aging. Pages age from being unused; they - * rejuvenate on being accessed. Only swap old pages (age==0 - * is oldest). + + /* + * Deal with page aging. There are several special cases to + * consider: + * + * Page has been accessed, but is swap cached. If the page is + * getting sufficiently "interesting" --- its age is getting + * high --- then if we are sufficiently short of free swap + * pages, then delete the swap cache. We can only do this if + * the swap page's reference count is one: ie. there are no + * other references to it beyond the swap cache (as there must + * still be pte's pointing to it if count > 1). + * + * If the page has NOT been touched, and its age reaches zero, + * then we are swapping it out: * - * This test will no longer work once swap cached pages can be - * shared! - */ - if ((pte_dirty(pte) && delete_from_swap_cache(page_map)) - || pte_young(pte)) { + * If there is already a swap cache page for this page, then + * another process has already allocated swap space, so just + * dereference the physical page and copy in the swap entry + * from the swap cache. + * + * Note, we rely on all pages read in from swap either having + * the swap cache flag set, OR being marked writable in the pte, + * but NEVER BOTH. (It IS legal to be neither cached nor dirty, + * however.) + * + * -- Stephen Tweedie 1998 */ + + if (PageSwapCache(page_map)) { + if (pte_write(pte)) { + printk ("VM: Found a writable swap-cached page!\n"); + return 0; + } + } + + if (pte_young(pte)) { set_pte(page_table, pte_mkold(pte)); touch_page(page_map); + /* + * We should test here to see if we want to recover any + * swap cache page here. We do this if the page seeing + * enough activity, AND we are sufficiently low on swap + * + * We need to track both the number of available swap + * pages and the total number present before we can do + * this... + */ return 0; } + age_page(page_map); if (page_map->age) return 0; + if (pte_dirty(pte)) { - if (PageSwapCache(page_map)) - panic ("Can't still be swap cached!!!"); if (vma->vm_ops && vma->vm_ops->swapout) { pid_t pid = tsk->pid; vma->vm_mm->rss--; if (vma->vm_ops->swapout(vma, address - vma->vm_start + vma->vm_offset, page_table)) kill_proc(pid, SIGBUS, 1); } else { - if (!(entry = get_swap_page())) - return 0; + /* + * This is a dirty, swappable page. First of all, + * get a suitable swap entry for it, and make sure + * we have the swap cache set up to associate the + * page with that swap entry. + */ + if (PageSwapCache(page_map)) { + entry = page_map->offset; + } else { + entry = get_swap_page(); + if (!entry) + return 0; /* No swap space left */ + } + vma->vm_mm->rss--; + tsk->nswap++; flush_cache_page(vma, address); set_pte(page_table, __pte(entry)); flush_tlb_page(vma, address); - tsk->nswap++; + swap_duplicate(entry); + + /* Now to write back the page. We have two + * cases: if the page is already part of the + * swap cache, then it is already on disk. Just + * free the page and return (we release the swap + * cache on the last accessor too). + * + * If we have made a new swap entry, then we + * start the write out to disk. If the page is + * shared, however, we still need to keep the + * copy in memory, so we add it to the swap + * cache. */ + if (PageSwapCache(page_map)) { + free_page_and_swap_cache(page); + return (atomic_read(&page_map->count) == 0); + } + add_to_swap_cache(page_map, entry); + /* We checked we were unlocked way up above, and we + have been careful not to stall until here */ + set_bit(PG_locked, &page_map->flags); + /* OK, do a physical write to swap. */ rw_swap_page(WRITE, entry, (char *) page, (gfp_mask & __GFP_WAIT)); } - /* - * For now, this is safe, because the test above makes - * sure that this page is currently not swap-cached. - */ - if (PageSwapCache(page_map)) - panic ("Page became cached after IO"); - free_page(page); + /* Now we can free the current physical page. We also + * free up the swap cache if this is the last use of the + * page. Note that there is a race here: the page may + * still be shared COW by another process, but that + * process may exit while we are writing out the page + * asynchronously. That's no problem, shrink_mmap() can + * correctly clean up the occassional unshared page + * which gets left behind in the swap cache. */ + free_page_and_swap_cache(page); return 1; /* we slept: the process may not exist any more */ } - /* - * Eventually, find_in_swap_cache will be able to return true - * even for pages shared with other processes. - */ - if ((entry = find_in_swap_cache(page_map))) { - if (atomic_read(&page_map->count) != 1) { - set_pte(page_table, pte_mkdirty(pte)); - printk("Aiee.. duplicated cached swap-cache entry\n"); - return 0; - } + + /* The page was _not_ dirty, but still has a zero age. It must + * already be uptodate on disk. If it is in the swap cache, + * then we can just unlink the page now. Remove the swap cache + * too if this is the last user. */ + if ((entry = in_swap_cache(page_map))) { vma->vm_mm->rss--; flush_cache_page(vma, address); set_pte(page_table, __pte(entry)); flush_tlb_page(vma, address); - free_page(page); - return 1; + swap_duplicate(entry); + free_page_and_swap_cache(page); + return (atomic_read(&page_map->count) == 0); } + /* + * A clean page to be discarded? Must be mmap()ed from + * somewhere. Unlink the pte, and tell the filemap code to + * discard any cached backing page if this is the last user. + */ + if (PageSwapCache(page_map)) { + printk ("VM: How can this page _still_ be cached?"); + return 0; + } vma->vm_mm->rss--; flush_cache_page(vma, address); pte_clear(page_table); flush_tlb_page(vma, address); entry = page_unuse(page); - if (PageSwapCache(page_map)) - panic ("How can this page _still_ be cached?"); free_page(page); return entry; } @@ -424,7 +500,7 @@ void kswapd_setup(void) { int i; - char *revision="$Revision: 1.23 $", *s, *e; + char *revision="$Revision: 1.5 $", *s, *e; if ((s = strchr(revision, ':')) && (e = strchr(s, '$'))) @@ -441,6 +517,7 @@ */ int kswapd(void *unused) { + struct wait_queue wait = { current, NULL }; current->session = 1; current->pgrp = 1; sprintf(current->comm, "kswapd"); @@ -460,14 +537,15 @@ priorities. */ init_swap_timer(); - + add_wait_queue(&kswapd_wait, &wait); while (1) { - int fail; + int async; kswapd_awake = 0; flush_signals(current); run_task_queue(&tq_disk); - interruptible_sleep_on(&kswapd_wait); + schedule(); + current->state = TASK_INTERRUPTIBLE; kswapd_awake = 1; swapstats.wakeups++; /* Do the background pageout: @@ -477,27 +555,30 @@ * If we've had too many consecutive failures, * go back to sleep to let other tasks run. */ - for (fail = 0; fail++ < MAX_SWAP_FAIL;) { - int pages, gfp_mask; + async = 1; + for (;;) { + int gfp_mask; - pages = nr_free_pages; - if (nr_free_pages >= min_free_pages) - pages += atomic_read(&nr_async_pages); - if (pages >= free_pages_high) + if (free_memory_available()) break; gfp_mask = __GFP_IO; - if (pages < free_pages_low) + if (!async) gfp_mask |= __GFP_WAIT; - if (try_to_free_page(gfp_mask)) - fail = 0; + async = try_to_free_page(gfp_mask); + if (!(gfp_mask & __GFP_WAIT) || async) + continue; + + /* + * Not good. We failed to free a page even though + * we were synchronous. Complain and give up.. + */ + printk("kswapd: failed to free page\n"); + break; } - /* - * Report failure if we couldn't reach the minimum goal. - */ - if (nr_free_pages < min_free_pages) - printk("kswapd: failed, got %d of %d\n", - nr_free_pages, min_free_pages); } + /* As if we could ever get here - maybe we want to make this killable */ + remove_wait_queue(&kswapd_wait, &wait); + return 0; } /* diff -u --recursive --new-file v2.1.88/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.1.88/linux/net/core/skbuff.c Thu Feb 12 20:56:14 1998 +++ linux/net/core/skbuff.c Tue Feb 24 22:08:02 1998 @@ -128,7 +128,7 @@ } /* - * FIXME: We could do with an architecture dependant + * FIXME: We could do with an architecture dependent * 'alignment mask'. */ diff -u --recursive --new-file v2.1.88/linux/net/ipv4/syncookies.c linux/net/ipv4/syncookies.c --- v2.1.88/linux/net/ipv4/syncookies.c Sun Nov 30 14:00:39 1997 +++ linux/net/ipv4/syncookies.c Tue Feb 24 22:08:02 1998 @@ -92,7 +92,7 @@ return isn; } -/* This value should be dependant on TCP_TIMEOUT_INIT and +/* 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. diff -u --recursive --new-file v2.1.88/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.88/linux/net/ipv4/tcp_ipv4.c Mon Feb 23 18:12:13 1998 +++ linux/net/ipv4/tcp_ipv4.c Tue Feb 24 22:08:02 1998 @@ -174,7 +174,7 @@ return 0; } -/* Find a "good" local port, this is family independant. +/* Find a "good" local port, this is family independent. * There are several strategies working in unison here to * get the best possible performance. The current socket * load is kept track of, if it is zero there is a strong diff -u --recursive --new-file v2.1.88/linux/scripts/lxdialog/checklist.c linux/scripts/lxdialog/checklist.c --- v2.1.88/linux/scripts/lxdialog/checklist.c Sat Mar 2 23:22:25 1996 +++ linux/scripts/lxdialog/checklist.c Mon Feb 23 12:31:02 1998 @@ -188,9 +188,16 @@ check_x = (list_width - check_x) / 2; item_x = check_x + 4; + if (choice >= list_height) { + scroll = choice - list_height + 1; + choice -= scroll; + } + /* Print the list */ - for (i = 0; i < max_choice; i++) - print_item (list, items[i * 3 + 1], status[i], i, i == choice); + for (i = 0; i < max_choice; i++) { + print_item (list, items[(scroll+i) * 3 + 1], + status[i+scroll], i, i == choice); + } wnoutrefresh (list);