diff -u --recursive --new-file v1.3.74/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v1.3.74/linux/Documentation/Configure.help Fri Mar 15 16:03:10 1996 +++ linux/Documentation/Configure.help Sat Mar 16 13:52:13 1996 @@ -240,6 +240,16 @@ of the chipset, and permits faster I/O speeds to be set as well. See the README.ide and ali14xx.c files for more info. +PROMISE DC4030 support (ALPHA) +CONFIG_BLK_DEV_PROMISE + This driver is enabled at runtime using the "ide0=dc4030" kernel + boot parameter. It enables support for the secondary IDE interface + of the chipset, and takes advantage of the caching features of the + card. This driver is known to incur timeouts/retries during heavy + I/O to drives attached to the secondary interface. CDROM and + TAPE devices are not supported yet. + See the README.ide and ali14xx.c files for more info. + XT harddisk support CONFIG_BLK_DEV_XD Very old 8 bit hard disk controllers used in the IBM XT diff -u --recursive --new-file v1.3.74/linux/Documentation/svga.txt linux/Documentation/svga.txt --- v1.3.74/linux/Documentation/svga.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/svga.txt Sat Mar 16 14:50:05 1996 @@ -0,0 +1,218 @@ + Video Mode Selection Support 2.2 + (c) 1995, 1996 Martin Mares, +-------------------------------------------------------------------------------- + +1. Intro +~~~~~~~~ + This small document describes the "Video Mode Selection" feature which +allows to use various special video modes supported by the video BIOS. Due +to usage of the BIOS, the selection is limited to the boot time (before the +kernel decompression starts and works only on 80X86 machines. + + IF YOU USE THIS FEATURE, I'LL BE MUCH PLEASED IF YOU SEND ME A MAIL +DESCRIBING YOUR EXPERIENCE WITH IT. BUG REPORTS ARE ALSO WELCOME. + + The video mode to be used is selected by a kernel paramater which can be +specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..." +option of LILO or by the "vidmode" utility (present in standard Linux utility +packages). You can use the following settings of this parameter: + + NORMAL_VGA - Standard 80x25 mode available on all display adapters. + + EXTENDED_VGA - Standard 8-pixel font mode: 80x43 on EGA, 80x50 on VGA. + + ASK_VGA - Display a video mode menu upon startup (see below). + + 0..35 - Menu item number (when you have used the menu to view the list of + modes available on your adapter, you can specify the menu item you want + to use). 0..9 correspond to "0".."9", 10..35 to "a".."z". Warning: the + mode list displayed may vary as the kernel version changes, because the + modes are listed in a "first detected -- first displayed" manner. It's + better to use absolute mode numbers instead. + + 0x.... - Hexadecimal video mode ID (also displayed on the menu, see below + for exact meaning of the ID). Warning: rdev and LILO don't support + hexadecimal numbers -- you have to convert it to decimal manually. + +2. Menu +~~~~~~~ + The ASK_VGA mode causes the kernel to offer a video mode menu upon +bootup. It displays a "Press to see video modes available, +to continue or wait 30 secs" message. If you press , you enter the +menu, if you press or wait 30 seconds, the kernel will boot up with +the standard 80x25 mode set. + + The menu looks like: + +Video adapter: +Mode: COLSxROWS: +0 0F00 80x25 +1 0F01 80x50 +2 0F02 80x43 +3 0F03 80x26 +.... +Enter mode number: + + should contain a name of your video adapter +or the chip in it or at least whether it's an EGA or VGA or VESA VGA (VGA with +a VESA-compliant BIOS in it). If it doesn't match your configuration, tell me +and I'll try to fix it somehow (you know, hardware detection is a real pain +on PC's). + + "0 0F00 80x25" tells that the first menu item (the menu items are numbered +from "0" to "9" and from "a" to "z") is a 80x25 mode with ID=0x0f00 (see the +next section for a description of the mode ID's). + + encourages you to write the item number or mode ID +you wish to set and press . If the computer complains something about +"Unknown mode ID", it tries to explain you that it isn't possible to set such +a mode. It's also possible to press only which forces the current +mode to be used. + + The mode list may be a bit inaccurate on your machine (it isn't possible +to autodetect all existing video cards and their mutations). Some of the +modes may be unsettable, some of them might work incorrectly with Linux +(the common case is mirroring of first few lines at the bottom of the screen +because of BIOS bugs) or there can exist modes which are not displayed. If +you think the list doesn't match your configuration, let me know and I'll try +to add your configuration to the next version of the mode selector. + + The modes displayed on the menu are partially sorted: The list starts with +the standard modes (80x25 and 80x50) followed by "special" modes (80x28 and +80x43), local modes (if the local modes feature is enabled), VESA modes and +finally SVGA modes for the auto-detected adapter. + + If you enter "scan" instead of item number / mode ID, the program will try +to scan your video modes in a slightly aggresive, but much more accurate way. +This should reveal all video modes supported by your BIOS. During this process, +the screen will flash wildly and strange things will appear. If you are afraid +this could damage your monitor, don't use this functions. After scanning, the +mode ordering is a bit different: the auto-detected SVGA modes are not listed +at all and the modes revealed by the scan are shown before the VESA modes. + +3. Mode ID's +~~~~~~~~~~~~ + Because of the complexity of all the video stuff, the video mode ID's +used here are also a bit complex. A video mode ID is a 16-bit number usually +expressed in a hexadecimal notation (starting with "0x"). The ID numbers +can be divided to three regions: + + 0x0000 to 0x00ff - menu item references. 0x0000 is the first item. + + 0x0100 to 0x017f - standard BIOS modes. The ID is a BIOS video mode number + (as presented to INT 10, function 00) increased by 0x0100. You can + use any mode numbers even if not shown on the menu. + + 0x0200 to 0x04ff - VESA BIOS modes. The ID is a VESA mode ID increased by + 0x0200. All VESA modes should be autodetected and shown on the menu. + + 0x0f00 to 0x0fff - special modes (they are set by various tricks -- usually + by modifying one of the standard modes). Currently available: + 0x0f00 standard 80x25, don't reset mode if already set (=FFFF) + 0x0f01 standard with 8-point font: 80x43 on EGA, 80x50 on VGA + 0x0f02 VGA 80x43 (VGA switched to 350 scanlines with a 8-point font) + 0x0f03 VGA 80x28 (standard VGA scans, but 14-point font) + 0x0f04 leave current video mode + + 0x1000 to 0x7fff - modes specified by resolution. The code has a "0xRRCC" + form where RR is a number of rows and CC is a number of columns. + E.g., 0x1950 corresponds to a 80x25 mode, 0x2b84 to 132x43 etc. + This is the only fully portable way to refer to a non-standard mode. + + 0xff00 to 0xffff - aliases for backward compatibility: + 0xffff equivalent to 0x0f00 (standard 80x25) + 0xfffe equivalent to 0x0f01 (EGA 80x43 or VGA 80x50) + + If you add 0x8000 to the mode ID, the program will try to recalculate +vertical display timing according to mode parameters, which can be used to +eliminate some annoying bugs of certain VGA BIOS'es -- mainly extra lines at +the end of the display. + +4. Options +~~~~~~~~~~ + Some options can be set in the source text (in arch/i386/boot/video.S). +All of them are simple #define's -- change them to #undef's when you want to +switch them off. Currently supported: + + CONFIG_VIDEO_SVGA - enables autodetection of SVGA cards. If your card is +detected incorrectly, you can switch this off. + + CONFIG_VIDEO_VESA - enables autodetection of VESA modes. If it doesn't work +on your machine (or displays a "Error: Scanning of VESA modes failed" message), +you can switch it off and report as a bug. + + CONFIG_VIDEO_COMPACT - enables compacting of the video mode list. Duplicate +entries (those with the same screen size) are deleted except for the first one +(see the previous section for more information on mode ordering). However, +it's possible that the first variant doesn't work, while some of the others do +-- in this case turn this switch off to see the rest. + + CONFIG_VIDEO_RETAIN - enables retaining of screen contents when switching +video modes. Useful and probably harmless. + + CONFIG_VIDEO_LOCAL - enables inclusion of "local modes" in the list. The +local modes are added automatically to the beginning of the list not depending +by hardware configuration. The local modes are listed in the source text after +the "local_mode_table:" line. The comment before this line describes the format +of the table (which also includes a video card name to be displayed on the +top of the menu). + +5. Adding more cards +~~~~~~~~~~~~~~~~~~~~ + If you have a card not detected by the driver and you are a good programmer, +feel free to add it to the source and send me a diff. It's very simple: You +have to add a new entry to the svga_table consisting of a pointer to your mode +table and a pointer to your detection routine. The order of entries in the +svga_table defines the order of probing. Please use only reliable detection +routines which are known to identify _only_ the card in question. + + The detection routine is called with BP pointing to your mode table and +ES containing 0xc000. If you want, you may alter BP allowing to select an +appropriate mode table according to model ID detected. If the detection fails, +return BP=0. + + The mode table consists of lines containing a (BIOS mode number, rows, +columns) triple and is finished by single zero byte followed by NUL-terminated +adapter name. + +6. Still doesn't work? +~~~~~~~~~~~~~~~~~~~~~~ + When the mode detection doesn't work (e.g., the mode list is incorrect or +the machine hangs instead of displaying the menu), try to switch off some of +the configuration options listed in section 4. If it fails, you can still use +your kernel with the video mode set directly via the kernel parameter. + + In either case, please send me a bug report containing what _exactly_ +happens and how do the configuration switches affect the behaviour of the bug. + + If you start Linux from the M$-DOS, you might also use some DOS tools for +video mode setting. In this case, you must specify the 0x0f04 mode ("leave +current settings") to Linux, because if you use anything other, the 80x25 +mode will be used automatically. + + If you set some SVGA mode and there's one or more extra lines on the +bottom of the display containing already scrolled-out lines, your VGA BIOS +contains the most common video BIOS bug called "incorrect vertical display +end setting". Adding 0x8000 to the mode ID might fix the problem. Unfortunately, +this must be done manually -- no autodetection mechanisms are available. + +7. History +~~~~~~~~~~ +1.0 (??-Nov-95) First version supporting all adapters supported by the old + setup.S + Cirrus Logic 54XX. Present in some 1.3.4? kernels + and then removed due to instability on some machines. +2.0 (28-Jan-96) Rewritten from scratch. Cirrus Logic 64XX support added, almost + everything is configurable, the VESA support should be much more + stable, explicit mode numbering allowed, "scan" implemented etc. +2.1 (30-Jan-96) VESA modes moved to 0x200-0x3ff. Mode selection by resolution + supported. Few bugs fixed. VESA modes are listed prior to + modes supplied by SVGA autodetection as they are more reliable. + CLGD autodetect works better. Doesn't depend on 80x25 being + active when started. Scanning fixed. 80x43 (any VGA) added. + Code cleaned up. +2.2 (01-Feb-96) EGA 80x43 fixed. VESA extended to 0x200-0x4ff (non-standard 02XX + VESA modes work now). Display end bug workaround supported. + Special modes renumbered to allow adding of the "recalculate" + flag, 0xffff and 0xfffe became aliases instead of real ID's. + Screen contents retained during mode changes. +2.3 (15-Mar-96) Changed to work with 1.3.74 kernel. diff -u --recursive --new-file v1.3.74/linux/MAINTAINERS linux/MAINTAINERS --- v1.3.74/linux/MAINTAINERS Wed Mar 13 10:09:08 1996 +++ linux/MAINTAINERS Sat Mar 16 13:52:13 1996 @@ -107,6 +107,12 @@ L: linux-ipx@vger.rutgers.edu [will change] S: Maintained +IDE DRIVER [GENERAL] +P: Mark Lord +M: mlord@pobox.com +L: linux-kernel@vger.rutgers.edu +S: Maintained + ISDN SUBSYSTEM P: Fritz Elfert M: fritz@wuemaus.franken.de diff -u --recursive --new-file v1.3.74/linux/Makefile linux/Makefile --- v1.3.74/linux/Makefile Fri Mar 15 16:03:10 1996 +++ linux/Makefile Sat Mar 16 13:52:10 1996 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 74 +SUBLEVEL = 75 ARCH = i386 @@ -72,10 +72,11 @@ # NFS_ROOT_NAME specifies the default name of the directory to mount # as root via NFS, if the kernel does not get the "root=" option from # the boot loader. The "%s" will be replaced by the IP-number of the -# local system. +# local system. Use empty string for default root path provided by BOOTP. # -NFS_ROOT = -DNFS_ROOT="\"/tftpboot/%s\"" +#NFS_ROOT = -DNFS_ROOT="\"/tftpboot/%s\"" +NFS_ROOT = -DNFS_ROOT="\"\"" # # INSTALL_PATH specifies where to place the updated kernel and system map diff -u --recursive --new-file v1.3.74/linux/README linux/README --- v1.3.74/linux/README Wed Feb 7 15:11:19 1996 +++ linux/README Fri Mar 15 11:01:45 1996 @@ -10,14 +10,17 @@ bugs. It is *strongly* recommended that you back up the previous kernel before installing any new 1.3.xx release. -If you need to use a proven and stable Linux kernel, please use either -1.0.9 or 1.2.xx. All features which will be in the 1.3.xx releases will -be contained in 1.4.xx when the code base has stabilized again. - -If you decide to use 1.3, it is recommended that you join the kernel mailing -list. To do this, e-mail majordomo@vger.rutgers.edu, and put in the body -of the message "subscribe linux-kernel" or "subscribe linux-kernel-digest" -for a daily digest of the mailing list (it is a high-traffic list.) +If you need to use a proven and stable Linux kernel, please +use 1.0.9 or 1.2.13. All features found in the 1.3.xx releases +will be contained in 2.0 when the code base has stabilized again. + +If you decide to use 1.3, it might be a good idea to follow the kernel +channel, available as newsgroup (under linux.dev.kernel) and as mailing +list. To subscribe to the latter, e-mail majordomo@vger.rutgers.edu, +and put in the body of the message "subscribe linux-kernel" or +"subscribe linux-kernel-digest" for a daily digest of the mailing list +(it is a high-traffic list). Note that getting subscribed or unsubscribed +sometimes takes days or even weeks. WHAT IS LINUX? @@ -42,8 +45,8 @@ Project) books. This README is not meant to be documentation on the system: there are much better sources available. - - There are various readme's in the kernel doc/ subdirectory: these are - mainly used for kernel developers and some very kernel-specific + - There are various readme's in the kernel Documentation/ subdirectory: + these are mainly used for kernel developers and some very kernel-specific installation notes for some drivers for example. INSTALLING the kernel: diff -u --recursive --new-file v1.3.74/linux/arch/alpha/Makefile linux/arch/alpha/Makefile --- v1.3.74/linux/arch/alpha/Makefile Tue Dec 26 04:45:34 1995 +++ linux/arch/alpha/Makefile Sat Mar 16 13:52:12 1996 @@ -42,6 +42,12 @@ msb my-special-boot: @$(MAKEBOOT) msb +bootimage: + @$(MAKEBOOT) bootimage + +srmboot: + @$(MAKEBOOT) srmboot + archclean: @$(MAKEBOOT) clean diff -u --recursive --new-file v1.3.74/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile --- v1.3.74/linux/arch/alpha/boot/Makefile Thu Nov 9 11:23:46 1995 +++ linux/arch/alpha/boot/Makefile Sat Mar 16 13:52:12 1996 @@ -34,6 +34,17 @@ ( cat tools/lxboot tools/bootlx vmlinux.nh ) > /dev/rz0a disklabel -rw rz0 'linux' tools/lxboot tools/bootlx +bootimage: tools/mkbb tools/lxboot tools/bootlx vmlinux.nh + ( cat tools/lxboot tools/bootlx vmlinux.nh ) > bootimage + tools/mkbb bootimage tools/lxboot + +srmboot: bootdevice bootimage + dd if=bootimage of=$(BOOTDEV) bs=512 seek=1 skip=1 + tools/mkbb $(BOOTDEV) tools/lxboot + +bootdevice: + @test "$(BOOTDEV)" != "" || (echo You must specify BOOTDEV ; exit -1) + vmlinux.gz: vmlinux gzip -fv vmlinux @@ -56,6 +67,9 @@ tools/build: tools/build.c $(HOSTCC) tools/build.c -o tools/build +tools/mkbb: tools/mkbb.c + $(HOSTCC) tools/mkbb.c -o tools/mkbb + bootloader: $(OBJECTS) $(LD) $(LINKFLAGS) \ $(OBJECTS) \ @@ -64,6 +78,7 @@ (rm -f bootloader && exit 1) clean: - rm -f $(TARGETS) bootloader tools/build + rm -f $(TARGETS) bootloader bootimage vmlinux.nh tools/build \ + tools/mkbb tools/bootlx tools/lxboot dep: diff -u --recursive --new-file v1.3.74/linux/arch/alpha/boot/head.S linux/arch/alpha/boot/head.S --- v1.3.74/linux/arch/alpha/boot/head.S Mon Jan 16 07:17:34 1995 +++ linux/arch/alpha/boot/head.S Sat Mar 16 13:52:12 1996 @@ -129,3 +129,11 @@ ret $31,($26) .end dispatch + .align 3 + .globl tbi + .ent tbi +tbi: + .long PAL_tbi + ret ($26) + .end tbi + diff -u --recursive --new-file v1.3.74/linux/arch/alpha/boot/main.c linux/arch/alpha/boot/main.c --- v1.3.74/linux/arch/alpha/boot/main.c Sun Dec 17 11:43:08 1995 +++ linux/arch/alpha/boot/main.c Sat Mar 16 13:52:12 1996 @@ -13,6 +13,7 @@ #include #include #include +#include #include diff -u --recursive --new-file v1.3.74/linux/arch/alpha/boot/tools/mkbb.c linux/arch/alpha/boot/tools/mkbb.c --- v1.3.74/linux/arch/alpha/boot/tools/mkbb.c Thu Jan 1 02:00:00 1970 +++ linux/arch/alpha/boot/tools/mkbb.c Sat Mar 16 13:52:12 1996 @@ -0,0 +1,151 @@ +/* This utility makes a bootblock suitable for the SRM console/miniloader */ + +/* Usage: + * mkbb + * + * Where is the name of the device to install the bootblock on, + * and is the name of a bootblock to merge in. This bootblock + * contains the offset and size of the bootloader. It must be exactly + * 512 bytes long. + */ + +#include +#include +#include + +/* Minimal definition of disklabel, so we don't have to include + * asm/disklabel.h (confuses make) + */ +#ifndef MAXPARTITIONS +#define MAXPARTITIONS 8 /* max. # of partitions */ +#endif + +#ifndef u8 +#define u8 unsigned char +#endif + +#ifndef u16 +#define u16 unsigned short +#endif + +#ifndef u32 +#define u32 unsigned int +#endif + +struct disklabel { + u32 d_magic; /* must be DISKLABELMAGIC */ + u16 d_type, d_subtype; + u8 d_typename[16]; + u8 d_packname[16]; + u32 d_secsize; + u32 d_nsectors; + u32 d_ntracks; + u32 d_ncylinders; + u32 d_secpercyl; + u32 d_secprtunit; + u16 d_sparespertrack; + u16 d_sparespercyl; + u32 d_acylinders; + u16 d_rpm, d_interleave, d_trackskew, d_cylskew; + u32 d_headswitch, d_trkseek, d_flags; + u32 d_drivedata[5]; + u32 d_spare[5]; + u32 d_magic2; /* must be DISKLABELMAGIC */ + u16 d_checksum; + u16 d_npartitions; + u32 d_bbsize, d_sbsize; + struct d_partition { + u32 p_size; + u32 p_offset; + u32 p_fsize; + u8 p_fstype; + u8 p_frag; + u16 p_cpg; + } d_partitions[MAXPARTITIONS]; +}; + + +typedef union __bootblock { + struct { + char __pad1[64]; + struct disklabel __label; + } __u1; + struct { + unsigned long __pad2[63]; + unsigned long __checksum; + } __u2; + char bootblock_bytes[512]; + unsigned long bootblock_quadwords[64]; +} bootblock; + +#define bootblock_label __u1.__label +#define bootblock_checksum __u2.__checksum + +main(int argc, char ** argv) +{ + bootblock bootblock_from_disk; + bootblock bootloader_image; + int dev, fd; + int i; + int nread; + + /* Make sure of the arg count */ + if(argc != 3) { + fprintf(stderr, "Usage: %s device lxboot\n", argv[0]); + exit(0); + } + + /* First, open the device and make sure it's accessible */ + dev = open(argv[1], O_RDWR); + if(dev < 0) { + perror(argv[1]); + exit(0); + } + + /* Now open the lxboot and make sure it's reasonable */ + fd = open(argv[2], O_RDONLY); + if(fd < 0) { + perror(argv[2]); + close(dev); + exit(0); + } + + /* Read in the lxboot */ + nread = read(fd, &bootloader_image, sizeof(bootblock)); + if(nread != sizeof(bootblock)) { + perror("lxboot read"); + fprintf(stderr, "expected %d, got %d\n", sizeof(bootblock), nread); + exit(0); + } + + /* Read in the bootblock from disk. */ + nread = read(dev, &bootblock_from_disk, sizeof(bootblock)); + if(nread != sizeof(bootblock)) { + perror("bootblock read"); + fprintf(stderr, "expected %d, got %d\n", sizeof(bootblock), nread); + exit(0); + } + + /* Swap the bootblock's disklabel into the bootloader */ + bootloader_image.bootblock_label = bootblock_from_disk.bootblock_label; + + /* Calculate the bootblock checksum */ + bootloader_image.bootblock_checksum = 0; + for(i = 0; i < 63; i++) { + bootloader_image.bootblock_checksum += + bootloader_image.bootblock_quadwords[i]; + } + + /* Write the whole thing out! */ + lseek(dev, 0L, SEEK_SET); + if(write(dev, &bootloader_image, sizeof(bootblock)) != sizeof(bootblock)) { + perror("bootblock write"); + exit(0); + } + + close(fd); + close(dev); + exit(0); +} + + diff -u --recursive --new-file v1.3.74/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v1.3.74/linux/arch/alpha/config.in Sat Mar 2 10:43:20 1996 +++ linux/arch/alpha/config.in Sat Mar 16 13:52:12 1996 @@ -56,8 +56,14 @@ define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_ALCOR y fi -# This needs to be defined for all EV4 and EV45 CPUs: + +if [ "$CONFIG_ALPHA_JENSEN" = "y" ] +then + bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM +fi + define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y + bool 'Echo console messages on /dev/ttyS1' CONFIG_SERIAL_ECHO if [ "$CONFIG_PCI" = "y" ]; then bool 'TGA Console Support' CONFIG_TGA_CONSOLE diff -u --recursive --new-file v1.3.74/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v1.3.74/linux/arch/alpha/kernel/irq.c Wed Mar 13 10:09:09 1996 +++ linux/arch/alpha/kernel/irq.c Sat Mar 16 13:52:12 1996 @@ -281,7 +281,7 @@ #endif } -static inline void handle_irq(int irq, void *dev_id, struct pt_regs * regs) +static inline void handle_irq(int irq, struct pt_regs * regs) { struct irqaction * action = irq_action[irq]; @@ -340,6 +340,8 @@ unmask_irq(ack); } +#ifdef CONFIG_PCI + /* * Handle ISA interrupt via the PICs. */ @@ -469,6 +471,8 @@ } restore_flags(flags); } + +#endif /* CONFIG_PCI */ /* * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and diff -u --recursive --new-file v1.3.74/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v1.3.74/linux/arch/alpha/kernel/setup.c Sat Mar 2 10:43:21 1996 +++ linux/arch/alpha/kernel/setup.c Sat Mar 16 13:52:12 1996 @@ -128,8 +128,22 @@ ROOT_DEV = to_kdev_t(0x0802); /* sda2 */ command_line[COMMAND_LINE_SIZE - 1] = '\0'; - strcpy(command_line, COMMAND_LINE); - strcpy(saved_command_line, COMMAND_LINE); + + /* Hack for Jensen... since we're restricted to 8 or 16 + * chars for boot flags depending on the boot mode, + * we need some shorthand. This should do for + * installation. Later we'll add other abbreviaitions + * as well... + */ + if(strcmp(COMMAND_LINE, "INSTALL") == 0) { + strcpy(command_line, "root=/dev/fd0 load_ramdisk=1"); + strcpy(saved_command_line, command_line); + } + else { + strcpy(command_line, COMMAND_LINE); + strcpy(saved_command_line, COMMAND_LINE); + } + printk("Command line: %s\n", command_line); *cmdline_p = command_line; *memory_start_p = (unsigned long) &_end; diff -u --recursive --new-file v1.3.74/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile --- v1.3.74/linux/arch/i386/boot/Makefile Wed Mar 13 10:09:10 1996 +++ linux/arch/i386/boot/Makefile Sat Mar 16 13:52:09 1996 @@ -65,7 +65,7 @@ setup.o: setup.s $(AS86) -o $@ $< -setup.s: setup.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile +setup.s: setup.S video.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Makefile $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ bootsect: bootsect.o diff -u --recursive --new-file v1.3.74/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v1.3.74/linux/arch/i386/boot/setup.S Wed Mar 13 10:09:11 1996 +++ linux/arch/i386/boot/setup.S Sat Mar 16 13:52:10 1996 @@ -23,6 +23,9 @@ ! High load stuff, initrd support and position independency ! by Hans Lermen & Werner Almesberger, February 1996 ! , +! +! Video handling moved to video.S by Martin Mares, March 1996 +! ! NOTE! These had better be the same as in bootsect.s! #define __ASSEMBLY__ @@ -31,10 +34,6 @@ #include #include -#ifndef SVGA_MODE -#define SVGA_MODE ASK_VGA -#endif - ! Signature words to ensure LILO loaded us right #define SIG1 0xAA55 #define SIG2 0x5A5A @@ -122,13 +121,18 @@ prtstr: lodsb and al,al jz fin - call prnt1 + call prtchr jmp prtstr fin: ret +! Space printing + +prtsp2: call prtspc ! Print double space +prtspc: mov al,#0x20 ! Print single space (fall-thru!) + ! Part of above routine, this one just prints ascii al -prnt1: push ax +prtchr: push ax push cx xor bh,bh mov cx,#0x01 @@ -139,7 +143,7 @@ ret beep: mov al,#0x07 - jmp prnt1 + jmp prtchr no_sig_mess: .ascii "No setup signature found ..." db 0x00 @@ -216,49 +220,16 @@ int 0x15 mov [2],ax -! set the keyboard repeat rate to the max +! Set the keyboard repeat rate to the max mov ax,#0x0305 xor bx,bx ! clear bx int 0x16 -! check for EGA/VGA and some config parameters +! Check for video adapter and its parameters and allow the +! user to browse video modes. - mov ah,#0x12 - mov bl,#0x10 - int 0x10 - mov [8],ax - mov [10],bx - mov [12],cx - mov ax,#0x5019 - cmp bl,#0x10 - je novga - mov ax,#0x1a00 ! Added check for EGA/VGA discrimination - int 0x10 - mov bx,ax - mov ax,#0x5019 - movb [15],#0 ! by default, no VGA - cmp bl,#0x1a ! 1a means VGA, anything else EGA or lower - jne novga - movb [15],#1 ! we've detected a VGA - call chsvga -novga: mov [14],al - mov ah,#0x03 ! read cursor pos - xor bh,bh ! clear bh - int 0x10 ! save it in known place, con_init fetches - mov [0],dx ! it from 0x90000. - -! Get video-card data: - - mov ah,#0x0f - int 0x10 - mov [4],bx ! bh = display page - mov [6],ax ! al = video mode, ah = window width - xor ax,ax - mov es,ax ! Access low memory - seg es - mov ax,[0x485] ! POINTS - Height of character matrix - mov [16],ax + call video ! Get hd0 data @@ -307,7 +278,7 @@ stosb is_disk1: -! check for PS/2 pointing device +! Check for PS/2 pointing device mov ax,cs ! aka #SETUPSEG sub ax,#DELTA_INITSEG ! aka #INITSEG @@ -361,7 +332,7 @@ done_apm_bios: #endif -! now we want to move to protected mode ... +! Now we want to move to protected mode ... seg cs cmp realmode_swtch,#0 @@ -516,7 +487,7 @@ mov al,#0xFB ! mask all irq's but irq2 which out #0x21,al ! is cascaded -! well, that certainly wasn't fun :-(. Hopefully it works, and we don't +! Well, that certainly wasn't fun :-(. Hopefully it works, and we don't ! need no steenking BIOS anyway (except for the initial loading :-). ! The BIOS-routine wants lots of unnecessary data, and it's less ! "interesting" anyway. This is how REAL programmers do it. @@ -530,12 +501,11 @@ ! Note that the short jump isn't strictly needed, although there are ! reasons why it might be a good idea. It won't hurt in any case. ! - xor ax,ax - inc ax ! protected mode (PE) bit + mov ax,#1 ! protected mode (PE) bit lmsw ax ! This is it! jmp flush_instr flush_instr: - mov bx,#0 ! Flag to indicate a boot + xor bx,bx ! Flag to indicate a boot ! NOTE: For high loaded big kernels we need a ! jmpi 0x100000,KERNEL_CS @@ -664,45 +634,6 @@ test al,#2 ! is input buffer full? jnz empty_8042 ! yes - loop ret -! -! Read a key and return the (US-)ascii code in al, scan code in ah -! -getkey: - xor ah,ah - int 0x16 - ret - -! -! Read a key with a timeout of 30 seconds. The cmos clock is used to get -! the time. -! -getkt: - call gettime - add al,#30 ! wait 30 seconds - cmp al,#60 - jl lminute - sub al,#60 -lminute: - mov cl,al -again: mov ah,#0x01 - int 0x16 - jnz getkey ! key pressed, so get it - call gettime - cmp al,cl - jne again - mov al,#0x20 ! timeout, return default char `space' - ret - -! -! Flush the keyboard buffer -! -flush: mov ah,#0x01 - int 0x16 - jz empty - xor ah,ah - int 0x16 - jmp flush -empty: ret ! ! Read the cmos clock. Return the seconds in al @@ -721,510 +652,16 @@ ret ! -! Delay is needed after doing i/o +! Delay is needed after doing I/O ! delay: .word 0x00eb ! jmp $+2 ret -! Routine trying to recognize type of SVGA-board present (if any) -! and if it recognize one gives the choices of resolution it offers. -! If one is found the resolution chosen is given by al,ah (rows,cols). - -chsvga: cld - push ds - push cs - mov ax,[0x01fa] - pop ds - mov modesave,ax - mov ax,#0xc000 - mov es,ax - mov ax,modesave - cmp ax,#NORMAL_VGA - je defvga - cmp ax,#EXTENDED_VGA - je vga50 - cmp ax,#ASK_VGA - jne svga - lea si,msg1 - call prtstr - call flush -nokey: call getkt - cmp al,#0x0d ! enter ? - je svga ! yes - svga selection - cmp al,#0x20 ! space ? - je defvga ! no - repeat - call beep - jmp nokey -defvga: mov ax,#0x5019 - pop ds - ret -/* extended vga mode: 80x50 */ -vga50: - mov ax,#0x1112 - xor bl,bl - int 0x10 ! use 8x8 font set (50 lines on VGA) - mov ax,#0x1200 - mov bl,#0x20 - int 0x10 ! use alternate print screen - mov ax,#0x1201 - mov bl,#0x34 - int 0x10 ! turn off cursor emulation - mov ah,#0x01 - mov cx,#0x0607 - int 0x10 ! turn on cursor (scan lines 6 to 7) - pop ds - mov ax,#0x5032 ! return 80x50 - ret -/* extended vga mode: 80x28 */ -vga28: - pop ax ! clean the stack - mov ax,#0x1111 - xor bl,bl - int 0x10 ! use 9x14 fontset (28 lines on VGA) - mov ah, #0x01 - mov cx,#0x0b0c - int 0x10 ! turn on cursor (scan lines 11 to 12) - pop ds - mov ax,#0x501c ! return 80x28 - ret -/* svga modes */ -! -! test for presence of an S3 VGA chip. The algorithm was taken -! from the SuperProbe package of XFree86 1.2.1 -! report bugs to Christoph.Niemann@linux.org -! -svga: cld - mov cx,#0x0f35 ! we store some constants in cl/ch - mov dx,#0x03d4 - movb al,#0x38 - call inidx - mov bh,al ! store current value of CRT-register 0x38 - mov ax,#0x0038 - call outidx ! disable writing to special regs - movb al,cl ! check whether we can write special reg 0x35 - call inidx - movb bl,al ! save the current value of CRT reg 0x35 - andb al,#0xf0 ! clear bits 0-3 - movb ah,al - movb al,cl ! and write it to CRT reg 0x35 - call outidx - call inidx ! now read it back - andb al,ch ! clear the upper 4 bits - jz s3_2 ! the first test failed. But we have a - movb ah,bl ! second chance - mov al,cl - call outidx - jmp s3_1 ! do the other tests -s3_2: mov ax,cx ! load ah with 0xf and al with 0x35 - orb ah,bl ! set the upper 4 bits of ah with the orig value - call outidx ! write ... - call inidx ! ... and reread - andb al,cl ! turn off the upper 4 bits - push ax - movb ah,bl ! restore old value in register 0x35 - movb al,cl - call outidx - pop ax - cmp al,ch ! setting lower 4 bits was successful => bad - je no_s3 ! writing is allowed => this is not an S3 -s3_1: mov ax,#0x4838 ! allow writing to special regs by putting - call outidx ! magic number into CRT-register 0x38 - movb al,cl ! check whether we can write special reg 0x35 - call inidx - movb bl,al - andb al,#0xf0 - movb ah,al - movb al,cl - call outidx - call inidx - andb al,ch - jnz no_s3 ! no, we can't write => no S3 - mov ax,cx - orb ah,bl - call outidx - call inidx - andb al,ch - push ax - movb ah,bl ! restore old value in register 0x35 - movb al,cl - call outidx - pop ax - cmp al,ch - jne no_s31 ! writing not possible => no S3 - movb al,#0x30 - call inidx ! now get the S3 id ... - lea di,idS3 - mov cx,#0x10 - repne - scasb - je no_s31 - lea si,dsc_S3 ! table of descriptions of video modes for BIOS - lea di,mo_S3 ! table of sizes of video modes for my BIOS - movb ah,bh - movb al,#0x38 - call outidx ! restore old value of CRT register 0x38 - br selmod ! go ask for video mode -no_s3: movb al,#0x35 ! restore CRT register 0x35 - movb ah,bl - call outidx -no_s31: movb ah,bh - movb al,#0x38 - call outidx ! restore old value of CRT register 0x38 - - lea si,idati ! Check ATI 'clues' - mov di,#0x31 - mov cx,#0x09 - repe - cmpsb - jne noati - lea si,dscati - lea di,moati - br selmod -noati: mov ax,#0x200f ! Check Ahead 'clues' - mov dx,#0x3ce - out dx,ax - inc dx - in al,dx - cmp al,#0x20 - je isahed - cmp al,#0x21 - jne noahed -isahed: lea si,dscahead - lea di,moahead - br selmod -noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues' - in al,dx - or al,#0x10 - out dx,al - mov dx,#0x104 - in al,dx - mov bl,al - mov dx,#0x3c3 - in al,dx - and al,#0xef - out dx,al - cmp bl,[idcandt] - jne nocant - lea si,dsccandt - lea di,mocandt - br selmod -nocant: mov dx,#0x3d4 ! Check Cirrus 'clues' - mov al,#0x0c - out dx,al - inc dx - in al,dx - mov bl,al - xor al,al - out dx,al - dec dx - mov al,#0x1f - out dx,al - inc dx - in al,dx - mov bh,al - xor ah,ah - shl al,#4 - mov cx,ax - mov al,bh - shr al,#4 - add cx,ax - shl cx,#8 - add cx,#6 - mov ax,cx - mov dx,#0x3c4 - out dx,ax - inc dx - in al,dx - and al,al - jnz nocirr - mov al,bh - out dx,al - in al,dx - cmp al,#0x01 - jne nocirr - call rst3d4 - lea si,dsccirrus - lea di,mocirrus - br selmod -rst3d4: mov dx,#0x3d4 - mov al,bl - xor ah,ah - shl ax,#8 - add ax,#0x0c - out dx,ax - ret -nocirr: call rst3d4 ! Check Everex 'clues' - mov ax,#0x7000 - xor bx,bx - int 0x10 - cmp al,#0x70 - jne noevrx - shr dx,#4 - cmp dx,#0x678 - je istrid - cmp dx,#0x236 - je istrid - lea si,dsceverex - lea di,moeverex - br selmod -istrid: lea cx,ev2tri - jmp cx -noevrx: lea si,idgenoa ! Check Genoa 'clues' - xor ax,ax - seg es - mov al,[0x37] - mov di,ax - mov cx,#0x04 - dec si - dec di -l1: inc si - inc di - mov al,(si) - test al,al - jz l2 - seg es - cmp al,(di) -l2: loope l1 - cmp cx,#0x00 - jne nogen - lea si,dscgenoa - lea di,mogenoa - br selmod -nogen: cld - lea si,idoakvga - mov di,#0x08 - mov cx,#0x08 - repe - cmpsb - jne nooak - lea si,dscoakvga - lea di,mooakvga - br selmod -nooak: cld - lea si,idparadise ! Check Paradise 'clues' - mov di,#0x7d - mov cx,#0x04 - repe - cmpsb - jne nopara - lea si,dscparadise - lea di,moparadise - br selmod -nopara: mov dx,#0x3c4 ! Check Trident 'clues' - mov al,#0x0e - out dx,al - inc dx - in al,dx - xchg ah,al - xor al,al - out dx,al - in al,dx - xchg al,ah - mov bl,al ! Strange thing ... in the book this wasn't - and bl,#0x02 ! necessary but it worked on my card which - jz setb2 ! is a trident. Without it the screen goes - and al,#0xfd ! blurred ... - jmp clrb2 ! -setb2: or al,#0x02 ! -clrb2: out dx,al - and ah,#0x0f - cmp ah,#0x02 - jne notrid -ev2tri: lea si,dsctrident - lea di,motrident - jmp selmod -notrid: mov dx,#0x3cd ! Check Tseng 'clues' - in al,dx ! Could things be this simple ! :-) - mov bl,al - mov al,#0x55 - out dx,al - in al,dx - mov ah,al - mov al,bl - out dx,al - cmp ah,#0x55 - jne notsen - lea si,dsctseng - lea di,motseng - jmp selmod -notsen: mov dx,#0x3cc ! Check Video7 'clues' - in al,dx - mov dx,#0x3b4 - and al,#0x01 - jz even7 - mov dx,#0x3d4 -even7: mov al,#0x0c - out dx,al - inc dx - in al,dx - mov bl,al - mov al,#0x55 - out dx,al - in al,dx - dec dx - mov al,#0x1f - out dx,al - inc dx - in al,dx - mov bh,al - dec dx - mov al,#0x0c - out dx,al - inc dx - mov al,bl - out dx,al - mov al,#0x55 - xor al,#0xea - cmp al,bh - jne novid7 - lea si,dscvideo7 - lea di,movideo7 - jmp selmod -novid7: lea si,dsunknown - lea di,mounknown -selmod: xor cx,cx - mov cl,(di) - mov ax,modesave - cmp ax,#ASK_VGA - je askmod - cmp ax,#NORMAL_VGA - je askmod - cmp al,cl - jl gotmode - push si - lea si,msg4 - call prtstr - pop si -askmod: push si - lea si,msg2 - call prtstr - pop si - push si - push cx -tbl: pop bx - push bx - mov al,bl - sub al,cl - call modepr - lodsw - xchg al,ah - call dprnt - xchg ah,al - push ax - mov al,#0x78 - call prnt1 - pop ax - call dprnt - push si - lea si,crlf ! print CR+LF - call prtstr - pop si - loop tbl - pop cx - lea si,msg3 - call prtstr - pop si - add cl,#0x30 - jmp nonum -nonumb: call beep -nonum: call getkey - cmp al,#0x30 ! ascii `0' - jb nonumb - cmp al,#0x3a ! ascii `9' - jbe number - cmp al,#0x61 ! ascii `a' - jb nonumb - cmp al,#0x7a ! ascii `z' - ja nonumb - sub al,#0x27 - cmp al,cl - jae nonumb - sub al,#0x30 - jmp gotmode -number: cmp al,cl - jae nonumb - sub al,#0x30 -gotmode: xor ah,ah - or al,al - beq vga50 - push ax - dec ax - beq vga28 - add di,ax - mov al,(di) - int 0x10 - pop ax - shl ax,#1 - add si,ax - lodsw - pop ds - ret - -! Routine to write al into a VGA-register that is -! accessed via an index register -! -! dx contains the address of the index register -! al contains the index -! ah contains the value to write to the data register (dx + 1) -! -! no registers are changed - -outidx: out dx,al - push ax - mov al,ah - inc dx - out dx,al - dec dx - pop ax - ret -inidx: out dx,al - inc dx - in al,dx - dec dx - ret - -! Routine to print a decimal value on screen, the value to be -! printed is put in al (i.e 0-255). - -dprnt: push ax - push cx - xor ah,ah ! Clear ah - mov cl,#0x0a - idiv cl - cmp al,#0x09 - jbe lt100 - call dprnt - jmp skip10 -lt100: add al,#0x30 - call prnt1 -skip10: mov al,ah - add al,#0x30 - call prnt1 - pop cx - pop ax - ret - ! -! Routine to print the mode number key on screen. Mode numbers -! 0-9 print the ascii values `0' to '9', 10-35 are represented by -! the letters `a' to `z'. This routine prints some spaces around the -! mode no. +! Descriptor tables ! -modepr: push ax - cmp al,#0x0a - jb digit ! Here is no check for number > 35 - add al,#0x27 -digit: add al,#0x30 - mov modenr, al - push si - lea si, modestring - call prtstr - pop si - pop ax - ret - gdt: .word 0,0,0,0 ! dummy @@ -1248,68 +685,25 @@ .word 0x800 ! gdt limit=2048, 256 GDT entries .word 512+gdt,0x9 ! gdt base = 0X9xxxx -msg1: .ascii "Press to see SVGA-modes available, to continue or wait 30 secs." - db 0x0d, 0x0a, 0x0a, 0x00 -msg2: .ascii "Mode: COLSxROWS:" - db 0x0d, 0x0a, 0x0a, 0x00 -msg3: db 0x0d, 0x0a - .ascii "Choose mode by pressing the corresponding number or letter." -crlf: db 0x0d, 0x0a, 0x00 -msg4: .ascii "You passed an undefined mode number to setup. Please choose a new mode." - db 0x0d, 0x0a, 0x0a, 0x07, 0x00 -modestring: .ascii " " -modenr: db 0x00 ! mode number - .ascii ": " - db 0x00 - -idati: .ascii "761295520" -idcandt: .byte 0xa5 -idgenoa: .byte 0x77, 0x00, 0x99, 0x66 -idparadise: .ascii "VGA=" -idoakvga: .ascii "OAK VGA " -idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 - .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 - -! Manufacturer: Numofmodes+2: Mode: -! Number of modes is the number of chip-specific svga modes plus the extended -! modes available on any vga (currently 2) - -moati: .byte 0x06, 0x23, 0x33, 0x22, 0x21 -moahead: .byte 0x07, 0x22, 0x23, 0x24, 0x2f, 0x34 -mocandt: .byte 0x04, 0x60, 0x61 -mocirrus: .byte 0x06, 0x1f, 0x20, 0x22, 0x31 -moeverex: .byte 0x0c, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40 -mogenoa: .byte 0x0c, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78 -moparadise: .byte 0x04, 0x55, 0x54 -motrident: .byte 0x09, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a -motseng: .byte 0x07, 0x26, 0x2a, 0x23, 0x24, 0x22 -movideo7: .byte 0x08, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45 -mooakvga: .byte 0x08, 0x00, 0x07, 0x4e, 0x4f, 0x50, 0x51 -mo_S3: .byte 0x04, 0x54, 0x55 -mounknown: .byte 0x02 - -! msb = Cols lsb = Rows: -! The first two modes are standard vga modes available on any vga. -! mode 0 is 80x50 and mode 1 is 80x28 - -dscati: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x641e, 0x6419 -dscahead: .word 0x5032, 0x501c, 0x842c, 0x8419, 0x841c, 0xa032, 0x5042 -dsccandt: .word 0x5032, 0x501c, 0x8419, 0x8432 -dsccirrus: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x841e, 0x6425 -dsceverex: .word 0x5032, 0x501c, 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e -dscgenoa: .word 0x5032, 0x501c, 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b -dscparadise: .word 0x5032, 0x501c, 0x8419, 0x842c -dsctrident: .word 0x5032, 0x501c, 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c -dsctseng: .word 0x5032, 0x501c, 0x503c, 0x6428, 0x8419, 0x841c, 0x842c -dscvideo7: .word 0x5032, 0x501c, 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c -dscoakvga: .word 0x5032, 0x501c, 0x2819, 0x5019, 0x503c, 0x843c, 0x8419, 0x842b -dsc_S3: .word 0x5032, 0x501c, 0x842b, 0x8419 -dsunknown: .word 0x5032, 0x501c -modesave: .word SVGA_MODE +! +! Include video setup & detection code +! + +#include "video.S" + +! +! Setup signature -- must be last +! -! This must be last setup_sig1: .word SIG1 setup_sig2: .word SIG2 + +! +! After this point, there is some free space which is used by the video mode +! handling code to store the temporary mode table (not used by the kernel). +! + +modelist: .text endtext: diff -u --recursive --new-file v1.3.74/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S --- v1.3.74/linux/arch/i386/boot/video.S Thu Jan 1 02:00:00 1970 +++ linux/arch/i386/boot/video.S Sat Mar 16 14:47:59 1996 @@ -0,0 +1,1632 @@ +! +! Display adapter & video mode setup, version 2.3 (15-Mar-96) +! +! Copyright (C) 1995, 1996 Martin Mares +! Based on the original setup.S code (C) Linus Torvalds +! + +! Enable autodetection of SVGA adapters and modes +#define CONFIG_VIDEO_SVGA + +! Enable autodetection of VESA modes +#define CONFIG_VIDEO_VESA + +! Enable compacting of mode table +#define CONFIG_VIDEO_COMPACT + +! Retain screen contents when switching modes +#define CONFIG_VIDEO_RETAIN + +! Enable local mode list +#undef CONFIG_VIDEO_LOCAL + +! This code uses an extended set of video mode numbers. These include: +! Aliases for standard modes +! NORMAL_VGA (-1) +! EXTENDED_VGA (-2) +! ASK_VGA (-3) +! Video modes numbered by menu position -- NOT RECOMMENDED because of lack +! of compatibility when extending the table. These are between 0x00 and 0xff. +#define VIDEO_FIRST_MENU 0x0000 +! Standard BIOS video modes (BIOS number + 0x0100) +#define VIDEO_FIRST_BIOS 0x0100 +! VESA BIOS video modes (VESA number + 0x0200) +#define VIDEO_FIRST_VESA 0x0200 +! Special video modes +#define VIDEO_FIRST_SPECIAL 0x0f00 +#define VIDEO_80x25 0x0f00 +#define VIDEO_8POINT 0x0f01 +#define VIDEO_80x43 0x0f02 +#define VIDEO_80x28 0x0f03 +#define VIDEO_CURRENT_MODE 0x0f04 +#define VIDEO_LAST_SPECIAL 0x0f05 +! Video modes given by resolution +#define VIDEO_FIRST_RESOLUTION 0x1000 + +! The "recalculate timings" flag +#define VIDEO_RECALC 0x8000 + +! Positions of various video parameters passed to the kernel +#define PARAM_CURSOR_POS 0 +#define PARAM_VIDEO_PAGE 4 +#define PARAM_VIDEO_MODE 6 +#define PARAM_VIDEO_COLS 7 +#define PARAM_VIDEO_EGA_BX 10 +#define PARAM_VIDEO_LINES 14 +#define PARAM_HAVE_VGA 15 +#define PARAM_FONT_POINTS 16 + +! Define DO_STORE according to CONFIG_VIDEO_RETAIN +#ifdef CONFIG_VIDEO_RETAIN +#define DO_STORE call store_screen +#else +#define DO_STORE +#endif + +! +! This is the main entry point called by setup.S +! + +video: push ds ! We use different segments + push ds ! FS contains original DS + pop fs + push cs ! DS is equal to CS + pop ds + push cs ! ES is equal to CS + pop es + xor ax,ax + mov gs,ax ! GS is zero + cld + call basic_detect ! Basic adapter type testing (EGA/VGA/MDA/CGA) + seg fs ! User-selected video mode + mov ax,[0x01fa] + cmp ax,#ASK_VGA ! Bring up the menu + jz vid2 + call mode_set ! Set the mode + jc vid1 + lea si,badmdt ! Invalid mode ID + call prtstr +vid2: call mode_menu +vid1: +#ifdef CONFIG_VIDEO_RETAIN + call restore_screen ! Restore screen contents +#endif + call mode_params ! Store mode parameters + pop ds ! Restore original DS + ret + +! +! Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel. +! + +basic_detect: + seg fs ! Default is no VGA + movb [PARAM_HAVE_VGA],#0 + + mov ah,#0x12 ! Check EGA/VGA + mov bl,#0x10 + int 0x10 + seg fs + mov [PARAM_VIDEO_EGA_BX],bx ! Used for identification of EGA in the kernel + cmp bl,#0x10 ! No, this is a CGA/MDA/HGA card. + je basret + incb [adapter] + + mov ax,#0x1a00 ! Check for EGA/VGA discrimination + int 0x10 + cmp al,#0x1a ! 1a means VGA, anything else EGA + jne basret + seg fs + incb [PARAM_HAVE_VGA] ! We've detected a VGA + incb [adapter] + +basret: ret + +! +! Store the video mode parameters for later usage by the kernel. +! This is done by asking the BIOS except for the rows/columns +! parameters in the default 80x25 mode -- these are set directly, +! because some very obscure BIOSes supply insane values. +! + +mode_params: + mov ah,#0x03 ! Read cursor position + xor bh,bh + int 0x10 + seg fs + mov [PARAM_CURSOR_POS],dx + + mov ah,#0x0f ! Read page/mode/width + int 0x10 + seg fs + mov [PARAM_VIDEO_PAGE],bx + seg fs + mov [PARAM_VIDEO_MODE],ax ! Video mode and screen width + cmp al,#7 ! MDA/HGA => segment differs + jnz mopar0 + mov [video_segment],#0xb000 +mopar0: seg gs ! Font size + mov ax,[0x485] + seg fs + mov [PARAM_FONT_POINTS],ax ! (valid only on EGA/VGA) + + cmpb [def_mode],#0 ! Default mode -- force sane values + jz mopar1 + seg fs + movb [PARAM_VIDEO_COLS],#80 +mopar2: seg fs + movb [PARAM_VIDEO_LINES],#25 + ret + +mopar1: cmpb [adapter],#0 ! If we are on CGA/MDA/HGA, the screen must + jz mopar2 ! have 25 lines. + seg gs ! On EGA/VGA, use the EGA+ BIOS variable + mov al,[0x484] ! containing maximal line number. + inc al + seg fs + movb [PARAM_VIDEO_LINES],al + ret + +! +! The video mode menu +! + +mode_menu: + lea si,keymsg ! "Return/Space/Timeout" message + call prtstr + call flush +nokey: call getkt + cmp al,#0x0d ! ENTER ? + je listm ! yes - manual mode selection + cmp al,#0x20 ! SPACE ? + je defmd1 ! no - repeat + call beep + jmp nokey +defmd1: ret ! No mode selected => use the 80x25 default + +listm: call mode_table ! We need a mode table to be listed +listm0: lea si,name_bann ! Print adapter name + call prtstr + mov si,[card_name] + or si,si + jnz an2 + mov al,[adapter] + lea si,old_name + or al,al + jz an1 + lea si,ega_name + dec al + jz an1 + lea si,vga_name + jmp an1 +an2: call prtstr + lea si,svga_name +an1: call prtstr + lea si,listhdr ! Table header + call prtstr + mov dl,#0x30 ! DL holds mode number + lea si,modelist +lm1: cmp (si),#ASK_VGA ! End? + jz lm2 + mov al,dl ! Menu selection number + call prtchr + call prtsp2 + lodsw + call prthw ! Mode ID + call prtsp2 + mov al,(si+1) + call prtdec ! Rows + mov al,#0x78 ! 'x' + call prtchr + lodsw + call prtdec ! Columns + mov al,#0x0d ! New line + call prtchr + mov al,#0x0a + call prtchr + inc dl ! Next character + cmp dl,#0x3a + jnz lm1 + mov dl,#0x61 + jmp lm1 + +lm2: lea si,prompt ! Mode prompt + call prtstr + lea di,edit_buf ! Editor buffer +lm3: call getkey + cmp al,#0x0d ! Enter? + jz lment + cmp al,#0x08 ! Backspace? + jz lmbs + cmp al,#0x20 ! Printable? + jc lm3 + cmp di,#edit_buf+4 ! Enough space? + jz lm3 + stosb + call prtchr + jmp lm3 + +lmbs: cmp di,#edit_buf ! Backspace + jz lm3 + dec di + mov al,#0x08 + call prtchr + call prtspc + mov al,#0x08 + call prtchr + jmp lm3 + +lment: movb (di),#0 + lea si,crlft + call prtstr + lea si,edit_buf + cmpb (si),#0 ! Empty string => use default mode + jz lmdef + cmpb (si+1),#0 ! One character => menu selection + jz mnusel + cmp (si),#0x6373 ! "scan" => mode scanning + jnz lmhx + cmp (si+2),#0x6e61 + jz lmscan +lmhx: xor bx,bx ! Else => mode ID in hex +lmhex: lodsb + or al,al + jz lmuse1 + sub al,#0x30 + jc lmbad + cmp al,#10 + jc lmhx1 + sub al,#7 + and al,#0xdf + cmp al,#10 + jc lmbad + cmp al,#16 + jnc lmbad +lmhx1: shl bx,#4 + or bl,al + jmp lmhex +lmuse1: mov ax,bx + jmp lmuse + +mnusel: lodsb ! Menu selection + xor ah,ah + sub al,#0x30 + jc lmbad + cmp al,#10 + jc lmuse + cmp al,#0x61-0x30 + jc lmbad + sub al,#0x61-0x30-10 + cmp al,#36 + jnc lmbad +lmuse: call mode_set + jc lmdef +lmbad: lea si,unknt + call prtstr + br lm2 + +lmscan: cmpb [adapter],#0 ! Scanning supported only on EGA/VGA + jz lmbad + mov [mt_end],#0 ! Scanning of modes: done as new autodetection + movb [scanning],#1 + call mode_table + br listm0 + +lmdef: ret + +! +! Aliases for backward compatibility. +! + +setalias: + mov ax,#VIDEO_80x25 + inc bx + jz mode_set + mov al,#VIDEO_8POINT-VIDEO_FIRST_SPECIAL + inc bx + jnz setbad + + ! Fall-thru ! + +! +! Setting of user mode (AX=mode ID) => CF=success +! + +mode_set: + mov bx,ax + cmp ah,#0xff + jz setalias + test ah,#VIDEO_RECALC>>8 + jnz setrec + cmp ah,#VIDEO_FIRST_RESOLUTION>>8 + jnc setres + cmp ah,#VIDEO_FIRST_SPECIAL>>8 + jz setspc + cmp ah,#VIDEO_FIRST_VESA>>8 + jnc setvesa + or ah,ah + jz setmenu + dec ah + jz setbios +setbad: clc + movb [do_restore],#0 ! The screen needn't be restored + ret + +setvesa: + DO_STORE + sub bh,#VIDEO_FIRST_VESA>>8 + mov ax,#0x4f02 ! VESA BIOS mode set call + int 0x10 + cmp ax,#0x004f ! AL=4f if implemented, AH=0 if OK + jnz setbad + stc + ret + +setbios: + DO_STORE + int 0x10 ! Standard BIOS mode set call + push bx + mov ah,#0x0f ! Check if really set + int 0x10 + pop bx + cmp al,bl + jnz setbad + stc + ret + +setspc: xor bh,bh ! Set special mode + cmp bl,#VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL + jnc setbad + add bx,bx + .word 0xa7ff, spec_inits ! JMP [BX+spec_inits] + +setmenu: + push bx ! Set mode chosen from menu + call mode_table ! Build the mode table + pop ax + shl ax,#2 + add si,ax + cmp si,di + jnc setbad + mov ax,(si) ! Fetch mode ID +_m_s: jmp mode_set + +setres: + push bx ! Set mode chosen by its resolution + call mode_table + pop bx + xchg bh,bl +setr1: lodsw + cmp ax,#ASK_VGA ! End of the list? + jz setbad + lodsw + cmp ax,bx + jnz setr1 + mov ax,(si-4) ! Fetch mode ID + jmp _m_s + +! +! Recalculate vertical display end registers -- this fixes various +! inconsistencies of extended modes on many adapters. Called when +! the VIDEO_RECALC flag is set in the mode ID. +! + +setrec: sub ah,#VIDEO_RECALC>>8 ! Set the base mode + call mode_set + jnc rct3 + seg gs ! Font size in pixels + mov ax,[0x485] + seg gs ! Number of rows + mov bl,[0x484] + inc bl + mul bl ! Number of visible + dec ax ! scan lines - 1 + mov dx,#0x3d4 + mov bx,ax + mov al,#0x12 ! Lower 8 bits + mov ah,bl + out dx,ax + mov al,#0x07 ! Bits 8 and 9 in the overflow register + call inidx + xchg ah,al + and ah,#0xbd + shr bh,#1 + jnc rct1 + or ah,#0x02 +rct1: shr bh,#1 + jnc rct2 + or ah,#0x40 +rct2: mov al,#0x07 + out dx,ax + stc +rct3: ret + +! +! Table of routines for setting of the special modes. +! + +spec_inits: + .word set_80x25 + .word set_8pixel + .word set_80x43 + .word set_80x28 + .word set_current + +! +! Set the 80x25 mode. If already set, do nothing. +! + +set_80x25: + incb [def_mode] ! Signal "we use default mode" +use_80x25: + mov ah,#0x0f ! Get current mode ID + int 0x10 + cmp ax,#0x5007 ! Mode 7 (80x25 mono) is the only one available + jz st80 ! on CGA/MDA/HGA and is also available on EGAM + cmp ax,#0x5003 ! Unknown mode => force 80x25 color + jnz force3 +st80: cmpb [adapter],#0 ! CGA/MDA/HGA => mode 3/7 is always 80x25 + jz set80 + seg gs ! This is EGA+ -- beware of 80x50 etc. + mov al,[0x0484] + or al,al ! Some buggy BIOS'es set 0 rows + jz set80 + cmp al,#24 ! It's hopefully correct + jz set80 +force3: DO_STORE + mov ax,#0x0003 ! Forced set + int 0x10 +set80: stc + ret + +! +! Set the 80x50/80x43 8-pixel mode. Simple BIOS calls. +! + +set_8pixel: + DO_STORE + call use_80x25 ! The base is 80x25 +set_8pt: + mov ax,#0x1112 ! Use 8x8 font + xor bl,bl + int 0x10 + mov ax,#0x1200 ! Use alternate print screen + mov bl,#0x20 + int 0x10 + mov ax,#0x1201 ! Turn off cursor emulation + mov bl,#0x34 + int 0x10 + mov ah,#0x01 ! Define cursor (scan lines 6 to 7) + mov cx,#0x0607 + int 0x10 +set_current: + stc + ret + +! +! Set the 80x28 mode. This mode works on all VGA's, because it's a standard +! 80x25 mode with 14-point fonts instead of 16-point. +! + +set_80x28: + DO_STORE + call use_80x25 ! The base is 80x25 + mov ax,#0x1111 ! Use 9x14 font + xor bl,bl + int 0x10 + mov ah,#0x01 ! Define cursor (scan lines 11 to 12) + mov cx,#0x0b0c + int 0x10 + stc + ret + +! +! Set the 80x43 mode. This mode is works on all VGA's. +! It's a 350-scanline mode with 8-pixel font. +! + +set_80x43: + DO_STORE + mov ax,#0x1201 ! Set 350 scans + mov bl,#0x30 + int 0x10 + mov ax,#0x0003 ! Reset video mode + int 0x10 + jmp set_8pt ! Use 8-pixel font + +#ifdef CONFIG_VIDEO_RETAIN + +! +! Store screen contents to temporary buffer. +! + +store_screen: + cmpb [do_restore],#0 ! Already stored? + jnz stsr + push ax + push bx + incb [do_restore] ! Screen will be restored later + mov al,[def_mode] ! "Default mode" flag overriden + push ax + movb [def_mode],#0 + call mode_params ! Obtain and store basic parameters + pop ax + mov [def_mode],al + seg fs ! of the current mode. + mov ax,[PARAM_CURSOR_POS] + lea di,modelist+8192 + stosw + seg fs + mov ah,[PARAM_VIDEO_LINES] + seg fs + mov al,[PARAM_VIDEO_COLS] + stosw + mul ah + mov cx,ax ! CX=number of characters to store + + push ds ! Store the screen + mov ds,[video_segment] + xor si,si + rep + movsw + pop ds + pop bx + pop ax +stsr: ret + +! +! Restore screen contents from temporary buffer. +! + +restore_screen: + cmpb [do_restore],#0 ! Has the screen been stored? + jz res1 + call mode_params ! Get parameters of current mode + seg fs + mov cl,[PARAM_VIDEO_LINES] + seg fs + mov ch,[PARAM_VIDEO_COLS] + lea si,modelist+8192 ! Screen buffer + lodsw ! Set cursor position + mov dx,ax + cmp dh,cl + jc res2 + mov dh,cl + dec dh +res2: cmp dl,ch + jc res3 + mov dl,ch + dec dl +res3: mov ah,#0x02 + mov bh,#0x00 + int 0x10 + lodsw ! Display size + mov dl,ah ! DL=number of lines + mov ah,#0 ! BX=physical length of orig. line + mov bx,ax + cmp dl,cl ! Too many? + jc res4 + push ax + mov al,dl + sub al,cl + mul bl + add si,ax + add si,ax + pop ax + mov dl,cl +res4: cmp al,ch ! Too wide? + jc res5 + mov al,ch ! AX=width of src. line +res5: mov cl,#0 + xchg cl,ch + mov bp,cx ! BP=width of dest. line + push es + mov es,[video_segment] + xor di,di ! Move the data + add bx,bx ! Convert BX and BP to _bytes_ + add bp,bp +res6: push si + push di + mov cx,ax + rep + movsw + pop di + pop si + add di,bp + add si,bx + dec dl + jnz res6 + pop es ! Done +res1: ret + +#endif /* CONFIG_VIDEO_RETAIN */ + +! +! Build the table of video modes (stored after the setup.S code at the +! `modelist' label. Each video mode record looks like: +! .word MODE-ID (our special mode ID (see above)) +! .byte rows (number of rows) +! .byte columns (number of columns) +! Returns address of the end of the table in DI, the end is marked +! with a ASK_VGA ID. +! + +mode_table: + mov di,[mt_end] ! Already filled? + or di,di + jnz mtab1x + lea di,modelist ! Store standard modes: + + mov eax,#VIDEO_80x25 + 0x50190000 ! The 80x25 mode (ALL) + stosd + mov al,[adapter] ! CGA/MDA/HGA -- no more modes + or al,al + jz mtabe + dec al + jnz mtabv + mov eax,#VIDEO_8POINT + 0x502b0000 ! The 80x43 EGA mode + stosd + jmp mtabe +mtab1x: jmp mtab1 + +mtabv: mov eax,#VIDEO_8POINT + 0x50320000 ! The 80x50 mode (VGA only) + stosd + mov eax,#VIDEO_80x43 + 0x502b0000 ! The 80x43 mode (VGA only) + stosd + mov eax,#VIDEO_80x28 + 0x501c0000 ! The 80x28 mode (VGA only) + stosd + + cmpb [scanning],#0 ! Mode scan requested? + jz mscan1 + call mode_scan +mscan1: + +#ifdef CONFIG_VIDEO_LOCAL + call local_modes +#endif +#ifdef CONFIG_VIDEO_VESA + call vesa_modes ! Detect VESA VGA modes +#endif +#ifdef CONFIG_VIDEO_SVGA + cmpb [scanning],#0 ! Bypass when scanning + jnz mscan2 + call svga_modes ! Detect SVGA cards & modes +mscan2: +#endif + +mtabe: + +#ifdef CONFIG_VIDEO_COMPACT + lea si,modelist ! Compact video mode list if requested. + mov dx,di + mov di,si +cmt1: cmp si,dx ! Scan all modes + jz cmt2 + lea bx,modelist ! Find in previous entries + mov cx,(si+2) +cmt3: cmp si,bx + jz cmt4 + cmp cx,(bx+2) ! Found => don't copy this entry + jz cmt5 + add bx,#4 + jmp cmt3 + +cmt4: movsd ! Copy entry + jmp cmt1 + +cmt5: add si,#4 ! Skip entry + jmp cmt1 + +cmt2: +#endif /* CONFIG_VIDEO_COMPACT */ + + mov (di),#ASK_VGA ! End marker + mov [mt_end],di +mtab1: lea si,modelist ! Returning: SI=mode list, DI=list end +ret0: ret + +! +! Detect VESA modes. +! + +#ifdef CONFIG_VIDEO_VESA + +vesa_modes: + cmpb [adapter],#2 ! VGA only + jnz ret0 + mov bp,di ! BP=original mode table end + add di,#0x400 ! Buffer space + mov ax,#0x4f00 ! VESA Get card info call + int #0x10 + mov di,bp + cmp ax,#0x004f ! Successful? + jnz ret0 + cmp (di+0x400),#0x4556 + jnz ret0 + cmp (di+0x402),#0x4153 + jnz ret0 + mov [card_name],#vesa_name ! Set name to "VESA VGA" + push gs + lgs si,(di+0x40e) ! GS:SI=mode list + mov cx,#128 ! Iteration limit +vesa1: seg gs ! Get next mode in the list + lodsw + cmp ax,#0xffff ! End of the table? + jz vesar + cmp ax,#0x0080 ! Check validity of mode ID + jc vesa2 + or ah,ah ! Valid ID's are 0x0000-0x007f + jz vesae ! and 0x0100-0x02ff. + cmp ax,#0x0300 + jnc vesae +vesa2: push cx + mov cx,ax ! Get mode information structure + mov ax,#0x4f01 + int 0x10 + mov bx,cx ! BX=mode number + add bh,#VIDEO_FIRST_VESA>>8 + pop cx + cmp ax,#0x004f + jnz vesae + mov al,(di) ! Check capabilities. We require + and al,#0x19 ! a color text mode. + cmp al,#0x09 + jnz vesan + cmp (di+8),#0xb800 ! Standard video memory address required + jnz vesan + testb (di),#2 ! Mode characteristics supplied? + mov (di),bx ! Store mode number + jz vesa3 + xor dx,dx + mov bx,(di+0x12) ! Width + or bh,bh + jnz vesan + mov (di+3),bl + mov ax,(di+0x14) ! Height + or ah,ah + jnz vesan + mov (di+2),al + mul bl + cmp ax,#8193 ! Small enough for Linux console driver? + jnc vesan + jmp vesaok + +vesa3: sub bx,#0x8108 ! This mode has no detailed info specified, + jc vesan ! so it must be a standard VESA mode. + cmp bx,#5 + jnc vesan + mov ax,(bx+vesa_text_mode_table) + mov (di+2),ax +vesaok: add di,#4 ! The mode is valid. Store it. +vesan: loop vesa1 ! Next mode. Limit exceeded => error +vesae: lea si,vesaer + call prtstr + mov di,bp ! Discard already found modes. +vesar: pop gs + ret + +! +! Dimensions of standard VESA text modes +! + +vesa_text_mode_table: + db 60, 80 ! 0108 + db 25, 132 ! 0109 + db 43, 132 ! 010A + db 50, 132 ! 010B + db 60, 132 ! 010C + +#endif /* CONFIG_VIDEO_VESA */ + +! +! Scan for video modes. A bit dirty, but should work. +! + +mode_scan: + mov cx,#0x0100 ! Start with mode 0 +scm1: mov ah,#0 ! Test the mode + mov al,cl + int 0x10 + mov ah,#0x0f + int 0x10 + cmp al,cl + jnz scm2 ! Mode not set + mov dx,#0x3c0 ! Test if it's a text mode + mov al,#0x10 ! Mode bits + call inidx + and al,#0x03 + jnz scm2 + mov dx,#0x3d4 ! Cursor location + mov al,#0x0f + call inidx + or al,al + jnz scm2 + mov ax,cx ! OK, store the mode + stosw + seg gs ! Number of rows + mov al,[0x484] + inc al + stosb + seg gs ! Number of columns + mov ax,[0x44a] + stosb +scm2: inc cl + jns scm1 + mov ax,#0x0003 ! Return back to mode 3 + int 0x10 + ret + +tstidx: out dx,ax ! OUT DX,AX and inidx +inidx: out dx,al ! Read from indexed VGA register + inc dx ! AL=index, DX=index reg port -> AL=data + in al,dx + dec dx + ret + +! +! Try to detect type of SVGA card and supply (usually approximate) video +! mode table for it. +! + +#ifdef CONFIG_VIDEO_SVGA + +svga_modes: + lea si,svga_table ! Test all known SVGA adapters +dosvga: lodsw + mov bp,ax ! Default mode table + or ax,ax + jz didsv1 + lodsw ! Pointer to test routine + push si + push di + push es + mov bx,#0xc000 + mov es,bx + call ax ! Call test routine + pop es + pop di + pop si + or bp,bp + jz dosvga + mov si,bp ! Found, copy the modes + mov ah,#0x01 +cpsvga: lodsb + or al,al + jz didsv + stosw + movsw + jmp cpsvga + +didsv: mov [card_name],si ! Store pointer to card name +didsv1: ret + +! +! Table of all known SVGA cards. For each card, we store a pointer to +! a table of video modes supported by the card and a pointer to a routine +! used for testing of presence of the card. The video mode table is always +! followed by the name of the card or the chipset. +! + +svga_table: + .word s3_md, s3_test + .word ati_md, ati_test + .word chips_md, chips_test + .word cirrus5_md, cirrus5_test + .word cirrus6_md, cirrus6_test + .word cirrus1_md, cirrus1_test + .word ahead_md, ahead_test + .word everex_md, everex_test + .word genoa_md, genoa_test + .word oak_md, oak_test + .word paradise_md, paradise_test + .word trident_md, trident_test + .word tseng_md, tseng_test + .word video7_md, video7_test + .word 0 + +! +! Test routines and mode tables: +! + +! S3 - The test algorithm was taken from the SuperProbe package +! for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org + +s3_test: + mov cx,#0x0f35 ! we store some constants in cl/ch + mov dx,#0x03d4 + movb al,#0x38 + call inidx + mov bh,al ! store current value of CRT-register 0x38 + mov ax,#0x0038 + call outidx ! disable writing to special regs + movb al,cl ! check whether we can write special reg 0x35 + call inidx + movb bl,al ! save the current value of CRT reg 0x35 + andb al,#0xf0 ! clear bits 0-3 + movb ah,al + movb al,cl ! and write it to CRT reg 0x35 + call outidx + call inidx ! now read it back + andb al,ch ! clear the upper 4 bits + jz s3_2 ! the first test failed. But we have a + movb ah,bl ! second chance + mov al,cl + call outidx + jmp s3_1 ! do the other tests +s3_2: mov ax,cx ! load ah with 0xf and al with 0x35 + orb ah,bl ! set the upper 4 bits of ah with the orig value + call outidx ! write ... + call inidx ! ... and reread + andb al,cl ! turn off the upper 4 bits + push ax + movb ah,bl ! restore old value in register 0x35 + movb al,cl + call outidx + pop ax + cmp al,ch ! setting lower 4 bits was successful => bad + je no_s3 ! writing is allowed => this is not an S3 +s3_1: mov ax,#0x4838 ! allow writing to special regs by putting + call outidx ! magic number into CRT-register 0x38 + movb al,cl ! check whether we can write special reg 0x35 + call inidx + movb bl,al + andb al,#0xf0 + movb ah,al + movb al,cl + call outidx + call inidx + andb al,ch + jnz no_s3 ! no, we can't write => no S3 + mov ax,cx + orb ah,bl + call outidx + call inidx + andb al,ch + push ax + movb ah,bl ! restore old value in register 0x35 + movb al,cl + call outidx + pop ax + cmp al,ch + jne no_s31 ! writing not possible => no S3 + movb al,#0x30 + call inidx ! now get the S3 id ... + lea di,idS3 + mov cx,#0x10 + repne + scasb + je no_s31 + movb ah,bh + movb al,#0x38 + jmp s3rest +no_s3: movb al,#0x35 ! restore CRT register 0x35 + movb ah,bl + call outidx +no_s31: xor bp,bp ! Detection failed +s3rest: movb ah,bh + movb al,#0x38 ! restore old value of CRT register 0x38 +outidx: out dx,al ! Write to indexed VGA register + push ax ! AL=index, AH=data, DX=index reg port + mov al,ah + inc dx + out dx,al + dec dx + pop ax + ret + +idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95 + .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0 + +s3_md: .byte 0x54, 0x2b, 0x84 + .byte 0x55, 0x19, 0x84 + .byte 0 + .ascii "S3" + .byte 0 + +! ATI cards. + +ati_test: + lea si,idati + mov di,#0x31 + mov cx,#0x09 + repe + cmpsb + je atiok + xor bp,bp +atiok: ret + +idati: .ascii "761295520" + +ati_md: .byte 0x23, 0x19, 0x84 + .byte 0x33, 0x2c, 0x84 + .byte 0x22, 0x1e, 0x64 + .byte 0x21, 0x19, 0x64 + .byte 0x58, 0x21, 0x50 + .byte 0x5b, 0x1e, 0x50 + .byte 0 + .ascii "ATI" + .byte 0 + +! AHEAD + +ahead_test: + mov ax,#0x200f + mov dx,#0x3ce + out dx,ax + inc dx + in al,dx + cmp al,#0x20 + je isahed + cmp al,#0x21 + je isahed + xor bp,bp +isahed: ret + +ahead_md: + .byte 0x22, 0x2c, 0x84 + .byte 0x23, 0x19, 0x84 + .byte 0x24, 0x1c, 0x84 + .byte 0x2f, 0x32, 0xa0 + .byte 0x32, 0x22, 0x50 + .byte 0x34, 0x42, 0x50 + .byte 0 + .ascii "Ahead" + .byte 0 + +! Chips & Tech. + +chips_test: + mov dx,#0x3c3 + in al,dx + or al,#0x10 + out dx,al + mov dx,#0x104 + in al,dx + mov bl,al + mov dx,#0x3c3 + in al,dx + and al,#0xef + out dx,al + cmp bl,#0xa5 + je cantok + xor bp,bp +cantok: ret + +chips_md: + .byte 0x60, 0x19, 0x84 + .byte 0x61, 0x32, 0x84 + .byte 0 + .ascii "Chips & Technologies" + .byte 0 + +! Cirrus Logic 5X0 + +cirrus1_test: + mov dx,#0x3d4 + mov al,#0x0c + out dx,al + inc dx + in al,dx + mov bl,al + xor al,al + out dx,al + dec dx + mov al,#0x1f + out dx,al + inc dx + in al,dx + mov bh,al + xor ah,ah + shl al,#4 + mov cx,ax + mov al,bh + shr al,#4 + add cx,ax + shl cx,#8 + add cx,#6 + mov ax,cx + mov dx,#0x3c4 + out dx,ax + inc dx + in al,dx + and al,al + jnz nocirr + mov al,bh + out dx,al + in al,dx + cmp al,#0x01 + je iscirr +nocirr: xor bp,bp +iscirr: mov dx,#0x3d4 + mov al,bl + xor ah,ah + shl ax,#8 + add ax,#0x0c + out dx,ax + ret + +cirrus1_md: + .byte 0x1f, 0x19, 0x84 + .byte 0x20, 0x2c, 0x84 + .byte 0x22, 0x1e, 0x84 + .byte 0x31, 0x25, 0x64 + .byte 0 + .ascii "Cirrus Logic 5X0" + .byte 0 + +! Cirrus Logic 54XX + +cirrus5_test: + mov dx,#0x3c4 + mov al,#6 + call inidx + mov bl,al ! BL=backup + mov ax,#6 + call tstidx + cmp al,#0x0f + jne c5fail + mov ax,#0x1206 + call tstidx + cmp al,#0x12 + jne c5fail + mov al,#0x1e + call inidx + mov bh,al + mov ah,bh + and ah,#0xc0 + mov al,#0x1e + call tstidx + and al,#0x3f + jne c5xx + mov al,#0x1e + mov ah,bh + or ah,#0x3f + call tstidx + xor al,#0x3f + and al,#0x3f +c5xx: pushf + mov al,#0x1e + mov ah,bh + out dx,ax + popf + je c5done +c5fail: xor bp,bp +c5done: mov al,#6 + mov ah,bl + out dx,ax + ret + +cirrus5_md: + .byte 0x14, 0x19, 0x84 + .byte 0x54, 0x2b, 0x84 + .byte 0 + .ascii "Cirrus Logic 54XX" + .byte 0 + +! Cirrus Logic 64XX -- no known extra modes, but must be identified, because +! it's misidentified by the Ahead test. + +cirrus6_test: + mov dx,#0x3ce + mov al,#0x0a + call inidx + mov bl,al ! BL=backup + mov ax,#0xce0a + call tstidx + or al,al + jne c2fail + mov ax,#0xec0a + call tstidx + cmp al,#0x01 + jne c2fail + mov al,#0xaa + call inidx ! 4X, 5X, 7X and 8X are valid 64XX chip ID's + shr al,#4 + sub al,#4 + jz c6done + dec al + jz c6done + sub al,#2 + jz c6done + dec al + jz c6done +c2fail: xor bp,bp +c6done: mov al,#0x0a + mov ah,bl + out dx,ax + ret + +cirrus6_md: + .byte 0 + .ascii "Cirrus Logic 64XX" + .byte 0 + +! Everex / Trident + +everex_test: + mov ax,#0x7000 + xor bx,bx + int 0x10 + cmp al,#0x70 + jne noevrx + shr dx,#4 + cmp dx,#0x678 + je evtrid + cmp dx,#0x236 + jne evrxok +evtrid: lea bp,trident_md +evrxok: ret + +noevrx: xor bp,bp + ret + +everex_md: + .byte 0x03, 0x22, 0x50 + .byte 0x04, 0x3c, 0x50 + .byte 0x07, 0x2b, 0x64 + .byte 0x08, 0x4b, 0x64 + .byte 0x0a, 0x19, 0x84 + .byte 0x0b, 0x2c, 0x84 + .byte 0x16, 0x1e, 0x50 + .byte 0x18, 0x1b, 0x64 + .byte 0x21, 0x40, 0xa0 + .byte 0x40, 0x1e, 0x84 + .byte 0 + .ascii "Everex/Trident" + .byte 0 + +! Genoa. + +genoa_test: + lea si,idgenoa ! Check Genoa 'clues' + xor ax,ax + seg es + mov al,[0x37] + mov di,ax + mov cx,#0x04 + dec si + dec di +l1: inc si + inc di + mov al,(si) + test al,al + jz l2 + seg es + cmp al,(di) +l2: loope l1 + or cx,cx + je isgen + xor bp,bp +isgen: ret + +idgenoa: .byte 0x77, 0x00, 0x99, 0x66 + +genoa_md: + .byte 0x58, 0x20, 0x50 + .byte 0x5a, 0x2a, 0x64 + .byte 0x60, 0x19, 0x84 + .byte 0x61, 0x1d, 0x84 + .byte 0x62, 0x20, 0x84 + .byte 0x63, 0x2c, 0x84 + .byte 0x64, 0x3c, 0x84 + .byte 0x6b, 0x4f, 0x64 + .byte 0x72, 0x3c, 0x50 + .byte 0x74, 0x42, 0x50 + .byte 0x78, 0x4b, 0x64 + .byte 0 + .ascii "Genoa" + .byte 0 + +! OAK + +oak_test: + lea si,idoakvga + mov di,#0x08 + mov cx,#0x08 + repe + cmpsb + je isoak + xor bp,bp +isoak: ret + +idoakvga: .ascii "OAK VGA " + +oak_md: .byte 0x4e, 0x3c, 0x50 + .byte 0x4f, 0x3c, 0x84 + .byte 0x50, 0x19, 0x84 + .byte 0x51, 0x2b, 0x84 + .byte 0 + .ascii "OAK" + .byte 0 + +! WD Paradise. + +paradise_test: + lea si,idparadise + mov di,#0x7d + mov cx,#0x04 + repe + cmpsb + je ispara + xor bp,bp +ispara: ret + +idparadise: .ascii "VGA=" + +paradise_md: + .byte 0x41, 0x22, 0x50 + .byte 0x47, 0x1c, 0x84 + .byte 0x55, 0x19, 0x84 + .byte 0x54, 0x2c, 0x84 + .byte 0 + .ascii "Paradise" + .byte 0 + +! Trident. + +trident_test: + mov dx,#0x3c4 + mov al,#0x0e + out dx,al + inc dx + in al,dx + xchg ah,al + xor al,al + out dx,al + in al,dx + xchg al,ah + mov bl,al ! Strange thing ... in the book this wasn't + and bl,#0x02 ! necessary but it worked on my card which + jz setb2 ! is a trident. Without it the screen goes + and al,#0xfd ! blurred ... + jmp clrb2 ! +setb2: or al,#0x02 ! +clrb2: out dx,al + and ah,#0x0f + cmp ah,#0x02 + je istrid + xor bp,bp +istrid: ret + +trident_md: + .byte 0x50, 0x1e, 0x50 + .byte 0x51, 0x2b, 0x50 + .byte 0x52, 0x3c, 0x50 + .byte 0x57, 0x19, 0x84 + .byte 0x58, 0x1e, 0x84 + .byte 0x59, 0x2b, 0x84 + .byte 0x5a, 0x3c, 0x84 + .byte 0 + .ascii "Trident" + .byte 0 + +! Tseng. + +tseng_test: + mov dx,#0x3cd + in al,dx ! Could things be this simple ! :-) + mov bl,al + mov al,#0x55 + out dx,al + in al,dx + mov ah,al + mov al,bl + out dx,al + cmp ah,#0x55 + je istsen + xor bp,bp +istsen: ret + +tseng_md: + .byte 0x26, 0x3c, 0x50 + .byte 0x2a, 0x28, 0x64 + .byte 0x23, 0x19, 0x84 + .byte 0x24, 0x1c, 0x84 + .byte 0x22, 0x2c, 0x84 + .byte 0 + .ascii "Tseng" + .byte 0 + +! Video7. + +video7_test: + mov dx,#0x3cc + in al,dx + mov dx,#0x3b4 + and al,#0x01 + jz even7 + mov dx,#0x3d4 +even7: mov al,#0x0c + out dx,al + inc dx + in al,dx + mov bl,al + mov al,#0x55 + out dx,al + in al,dx + dec dx + mov al,#0x1f + out dx,al + inc dx + in al,dx + mov bh,al + dec dx + mov al,#0x0c + out dx,al + inc dx + mov al,bl + out dx,al + mov al,#0x55 + xor al,#0xea + cmp al,bh + je isvid7 + xor bp,bp +isvid7: ret + +video7_md: + .byte 0x40, 0x2b, 0x50 + .byte 0x43, 0x3c, 0x50 + .byte 0x44, 0x3c, 0x64 + .byte 0x41, 0x19, 0x84 + .byte 0x42, 0x2c, 0x84 + .byte 0x45, 0x1c, 0x84 + .byte 0 + .ascii "Video 7" + .byte 0 + +#endif /* CONFIG_VIDEO_SVGA */ + +! +! User-defined local mode table (VGA only) +! + +#ifdef CONFIG_VIDEO_LOCAL + +local_modes: + lea si,local_mode_table +locm1: lodsw + or ax,ax + jz locm2 + stosw + movsw + jmp locm1 +locm2: ret + +! This is the table of local video modes which can be supplied manually +! by the user. Each entry consists of mode ID (word) and dimensions +! (byte for column count and another byte for row count). These modes +! are placed before all SVGA and VESA modes and override them if table +! compacting is enabled. The table must end with a zero word followed +! by NUL-terminated video adapter name. + +local_mode_table: + .word 0x0100 ! Example: 40x25 + .byte 25,40 + .word 0 + .ascii "Local" + .byte 0 + +#endif /* CONFIG_VIDEO_LOCAL */ + +! +! Read a key and return the ASCII code in al, scan code in ah +! + +getkey: xor ah,ah + int 0x16 + ret + +! +! Read a key with a timeout of 30 seconds. The hardware clock is used to get +! the time. +! + +getkt: call gettime + add al,#30 ! Wait 30 seconds + cmp al,#60 + jl lminute + sub al,#60 +lminute: + mov cl,al +again: mov ah,#0x01 + int 0x16 + jnz getkey ! key pressed, so get it + call gettime + cmp al,cl + jne again + mov al,#0x20 ! timeout, return default char `space' + ret + +! +! Flush the keyboard buffer +! + +flush: mov ah,#0x01 + int 0x16 + jz empty + xor ah,ah + int 0x16 + jmp flush +empty: ret + +! +! Print hexadecimal number. +! + +prthw: push ax + mov al,ah + call prthb + pop ax +prthb: push ax + shr al,#4 + call prthn + pop ax + and al,#0x0f +prthn: cmp al,#0x0a + jc prth1 + add al,#0x07 +prth1: add al,#0x30 + br prtchr + +! +! Print decimal number (AL). +! + +prtdec: push ax + push cx + xor ah,ah ! Clear ah + mov cl,#0x0a + idiv cl + cmp al,#0x09 + jbe lt100 + call prtdec + jmp skip10 +lt100: add al,#0x30 + call prtchr +skip10: mov al,ah + add al,#0x30 + call prtchr + pop cx + pop ax + ret + +! Variables: + +adapter: .byte 0 ! Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA +def_mode: .byte 0 ! "Default mode selected" flag +mt_end: .word 0 ! End of video mode table if built +edit_buf: .space 6 ! Line editor buffer +card_name: .word 0 ! Pointer to adapter name +scanning: .byte 0 ! Performing mode scan +do_restore: .byte 0 ! Screen contents altered during mode change +video_segment: .word 0xb800 ! Video memory segment + +! Messages: + +keymsg: .ascii "Press to see video modes available, " + .ascii " to continue or wait 30 secs" + db 0x0d, 0x0a, 0 +listhdr: db 0x0d, 0x0a + .ascii "Mode: COLSxROWS:" +crlft: db 0x0d, 0x0a, 0 +prompt: db 0x0d, 0x0a + .ascii "Enter mode number: " + db 0 +unknt: .ascii "Unknown mode ID. Try again." + db 0 +badmdt: .ascii "You passed an undefined mode number to setup." + db 0x0d, 0x0a, 0 +vesaer: .ascii "Error: Scanning of VESA modes failed. Please " + .ascii "report to ." + db 0x0d, 0x0a, 0 +old_name: .ascii "CGA/MDA/HGA" + db 0 +ega_name: .ascii "EGA" + db 0 +svga_name: .ascii " " +vga_name: .ascii "VGA" + db 0 +vesa_name: .ascii "VESA" + db 0 +name_bann: .ascii "Video adapter: " + db 0 diff -u --recursive --new-file v1.3.74/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v1.3.74/linux/arch/i386/defconfig Sun Mar 10 09:49:46 1996 +++ linux/arch/i386/defconfig Sat Mar 16 13:52:13 1996 @@ -38,6 +38,7 @@ # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_PCMCIA is not set CONFIG_BLK_DEV_CMD640=y CONFIG_BLK_DEV_RZ1000=y # CONFIG_BLK_DEV_TRITON is not set diff -u --recursive --new-file v1.3.74/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v1.3.74/linux/arch/i386/kernel/irq.c Wed Mar 13 10:09:11 1996 +++ linux/arch/i386/kernel/irq.c Sat Mar 16 13:52:10 1996 @@ -182,7 +182,7 @@ /* * On SMP boards, irq13 is used for interprocessor interrupts (IPI's). */ -static struct irqaction irq13 = { smp_message_irq, SA_INTERRUPT, 0, "IPI", NULL, NULL }: +static struct irqaction irq13 = { smp_message_irq, SA_INTERRUPT, 0, "IPI", NULL, NULL }; #else diff -u --recursive --new-file v1.3.74/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v1.3.74/linux/arch/i386/kernel/process.c Wed Mar 13 10:09:11 1996 +++ linux/arch/i386/kernel/process.c Sat Mar 16 13:52:10 1996 @@ -154,7 +154,14 @@ while(0x80000000 & smp_process_available); cli(); while(set_bit(31,&smp_process_available)) - while(test_bit(31,&smp_process_available)); + while(test_bit(31,&smp_process_available)) + { + /* + * Oops.. This is kind of important in some cases... + */ + if(clear_bit(smp_processor_id(), &smp_invalidate_needed)) + local_invalidate(); + } if (0==(0x7fffffff & smp_process_available)){ clear_bit(31,&smp_process_available); sti(); diff -u --recursive --new-file v1.3.74/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v1.3.74/linux/arch/i386/kernel/smp.c Wed Mar 13 10:09:11 1996 +++ linux/arch/i386/kernel/smp.c Sat Mar 16 13:52:10 1996 @@ -36,6 +36,18 @@ #include #include +/* + * Why isnt this somewhere standard ?? + */ + +extern __inline int max(int a,int b) +{ + if(a>b) + return a; + return b; +} + + int smp_found_config=0; /* Have we found an SMP box */ unsigned long cpu_present_map = 0; /* Bitmask of existing CPU's */ @@ -46,7 +58,8 @@ volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map thats also checked in the spinlock */ struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per cpu bogomips and other parameters */ static unsigned int num_processors = 1; /* Internal processor count */ -static unsigned long io_apic_addr = 0; /* Address of the I/O apic (not yet used) */ +int smp_top_cpu = 0; /* Highest used APIC id */ +static unsigned long io_apic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */ unsigned char boot_cpu_id = 0; /* Processor that is doing the boot up */ static unsigned char *kstack_base,*kstack_end; /* Kernel stack list pointers */ static int smp_activated = 0; /* Tripped once we need to start cross invalidating */ @@ -319,25 +332,19 @@ switch(mpf->mpf_feature1) { case 1: - printk("ISA"); + case 5: + printk("ISA\n"); break; case 2: - printk("EISA with no IRQ8 chaining"); + printk("EISA with no IRQ8 chaining\n"); break; + case 6: case 3: - printk("EISA"); + printk("EISA\n"); break; case 4: - printk("MCA"); - break; - case 5: - printk("ISA\nBus#1 is PCI"); - break; - case 6: - printk("EISA\nBus #1 is PCI"); - break; case 7: - printk("MCA\nBus #1 is PCI"); + printk("MCA\n"); break; case 0: break; @@ -346,14 +353,63 @@ mpf->mpf_feature1); return; } + if(mpf->mpf_feature1>4) + printk("Bus #1 is PCI\n"); /* - * Read the physical hardware table. If there isn't one - * the processors present are 0 and 1. + * Read the physical hardware table. */ if(mpf->mpf_physptr) smp_read_mpc((void *)mpf->mpf_physptr); else - cpu_present_map=3; + { + unsigned long cfg; + + /* + * If no table present, determine + * what the CPU mapping is. + */ + +/* + * + * HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK + * + */ + /* + * Standard page mapping + * functions don't work yet. + * We know that page 0 is not + * used. Steal it for now! + */ + + cfg=pg0[0]; + pg0[0] = (apic_addr | 7); + local_invalidate(); + + boot_cpu_id = GET_APIC_ID(*((volatile unsigned long *) APIC_ID)); + nlong = boot_cpu_id<<24; /* Dummy 'self' for bootup */ + + /* + * Give it back + */ + + pg0[0]= cfg; + local_invalidate(); + +/* + * + * END OF HACK END OF HACK END OF HACK END OF HACK END OF HACK + * + */ + + /* + * If boot CPU != 0, other CPU + * is 0, else other CPU is 1. + */ + if (boot_cpu_id) + cpu_present_map=1 | (1 << boot_cpu_id); + else + cpu_present_map=3; + } printk("Processors: %d\n", num_processors); /* * Only use the first one found. @@ -610,8 +666,11 @@ * Don't even attempt to start the boot CPU! */ if (i == boot_cpu_id) + { + smp_top_cpu=max(smp_top_cpu,i); continue; - + } + if (cpu_present_map & (1 << i)) { unsigned long send_status, accept_status; @@ -766,6 +825,8 @@ cpucount++; /* number CPUs logically, starting from 1 (BSP is 0) */ cpu_number_map[i] = cpucount; + smp_top_cpu=max(smp_top_cpu,i); + } else { @@ -1098,7 +1159,7 @@ if(clear_bit(i,(unsigned long *)&smp_invalidate_needed)) local_invalidate(); set_bit(i, (unsigned long *)&cpu_callin_map[0]); - cpu_callin_map[0]|=1< #include #include +#include /* * The SMP kernel can't handle the 4MB page table optimizations yet @@ -236,7 +237,7 @@ start_mem += PAGE_SIZE; } for (tmp = 0 ; tmp < high_memory ; tmp += PAGE_SIZE) { - if (tmp >= 16*1024*1024) + if (tmp >= MAX_DMA_ADDRESS) mem_map[MAP_NR(tmp)].dma = 0; if (mem_map[MAP_NR(tmp)].reserved) { if (tmp >= 0xA0000 && tmp < 0x100000) diff -u --recursive --new-file v1.3.74/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v1.3.74/linux/drivers/block/Config.in Wed Mar 13 10:09:12 1996 +++ linux/drivers/block/Config.in Sat Mar 16 13:52:13 1996 @@ -13,6 +13,7 @@ bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE bool ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD bool ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE + bool ' Support removeable IDE interfaces (PCMCIA)' CONFIG_BLK_DEV_IDE_PCMCIA bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 if [ "$CONFIG_PCI" = "y" ]; then bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 @@ -26,6 +27,7 @@ bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 bool ' UMC 8672 support' CONFIG_BLK_DEV_UMC8672 bool ' ALI M1439/M1445 support' CONFIG_BLK_DEV_ALI14XX + bool ' PROMISE DC4030 support (ALPHA)' CONFIG_BLK_DEV_PROMISE fi fi diff -u --recursive --new-file v1.3.74/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v1.3.74/linux/drivers/block/Makefile Wed Feb 28 11:50:00 1996 +++ linux/drivers/block/Makefile Sat Mar 16 13:52:13 1996 @@ -85,6 +85,10 @@ L_OBJS += ali14xx.o endif +ifeq ($(CONFIG_BLK_DEV_PROMISE),y) +L_OBJS += promise.o +endif + ifeq ($(CONFIG_BLK_DEV_IDECD),y) L_OBJS += ide-cd.o endif diff -u --recursive --new-file v1.3.74/linux/drivers/block/README.ide linux/drivers/block/README.ide --- v1.3.74/linux/drivers/block/README.ide Sat Mar 2 10:43:21 1996 +++ linux/drivers/block/README.ide Sat Mar 16 13:52:13 1996 @@ -1,4 +1,4 @@ -README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.3.xx) +README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.3/2.0) ================================================================================ Supported by: mlord@pobox.com -- disks, interfaces, probing snyder@fnald0.fnal.gov -- cdroms, ATAPI, audio @@ -10,7 +10,7 @@ See description later on below for handling BIG IDE drives with >1024 cyls. -Major features of ide.c & ide-cd.c: +Major features of ide.c & ide-cd.c ("NEW!" marks changes since 1.2.13): NEW! - support for IDE ATAPI *tape* drives, courtesy of Gadi Oxman (re-run MAKEDEV.ide to create the tape device entries in /dev/) @@ -58,6 +58,8 @@ NEW! - ide-cd.c now supports door locking and auto-loading. - Also preliminary support for multisession and direct reads of audio data. +NEW! - experimental support for Promise DC4030VL caching interface card +NEW! - email thanks/problems to: peterd@pnd-pc.demon.co.uk NEW! - the hdparm-2.7 package can be used to set PIO modes for some chipsets. For work in progress, see the comments in ide.c, ide-cd.c, and triton.c. @@ -233,11 +235,11 @@ "idex=noautotune" : driver will NOT attempt to tune interface speed This is the default for most chipsets, except the cmd640. + "idex=serialize" : do not overlap operations on idex and ide(x^1) The following two are valid ONLY on ide0, and the defaults for the base,ctl ports must not be altered. - "ide0=serialize" : do not overlap operations on ide0 and ide1. "ide0=dtc2278" : probe/support DTC2278 interface "ide0=ht6560b" : probe/support HT6560B interface "ide0=cmd640_vlb" : *REQUIRED* for VLB cards with the CMD640 chip diff -u --recursive --new-file v1.3.74/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c --- v1.3.74/linux/drivers/block/cmd640.c Sat Mar 2 10:43:22 1996 +++ linux/drivers/block/cmd640.c Sat Mar 16 13:52:13 1996 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/cmd640.c Version 0.07 Jan 27, 1996 + * linux/drivers/block/cmd640.c Version 0.08 Mar 15, 1996 * - * Copyright (C) 1995-1996 Linus Torvalds & author (see below) + * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) */ /* @@ -41,6 +41,8 @@ * CMD at their ftp site. * * Version 0.08 Added autotune/noautotune support. -ml + * + * Version 0.09 Try to be smarter about 2nd port enabling. -ml * */ @@ -300,12 +302,33 @@ } /* + * Returns 1 if an IDE interface/drive exists at 0x170, + * Returns 0 otherwise. + */ +int secondary_port_responding (void) +{ + /* + * Test for hardware at 0x170 (secondary IDE port). + * Leave the enable-bit alone if something responds. + */ + outb_p(0x0a,0x176); /* select drive0 */ + udelay(1); + if (inb_p(0x176) == 0xff) { + outb_p(0x0b,0x176); /* select drive1 */ + udelay(1); + if (inb_p(0x176) == 0xff) + return 0; /* nothing is there */ + } + return 1; /* something is there */ +} + +/* * Probe for Cmd640x and initialize it if found */ int ide_probe_for_cmd640x(void) { - int second_port; + int second_port_toggled = 0; byte b; if (probe_for_cmd640_pci1()) { @@ -320,6 +343,7 @@ } ide_hwifs[0].serialized = 1; /* ensure this *always* gets set */ + ide_hwifs[1].serialized = 1; /* ensure this *always* gets set */ #if 0 /* Dump initial state of chip registers */ @@ -359,11 +383,6 @@ put_cmd640_reg(ARTTIM23, 0xcc); /* 0xc0? */ /* - * Do not initialize secondary controller for vlbus - */ - second_port = (bus_type != vlb); - - /* * Set the maximum allowed bus speed (it is safest until we * find how to detect bus speed) * Normally PCI bus runs at 33MHz, but often works overclocked to 40 @@ -375,10 +394,11 @@ */ b = get_cmd640_reg(CNTRL); - if (second_port) - b |= CNTRL_ENA_2ND; - else - b &= ~CNTRL_ENA_2ND; + + if (!secondary_port_responding()) { + b ^= CNTRL_ENA_2ND; /* toggle the bit */ + second_port_toggled = 1; + } /* * Disable readahead for drives at primary interface @@ -401,7 +421,7 @@ /* * Initialize 2nd IDE port, if required */ - if (second_port) { + if (secondary_port_responding()) { ide_hwifs[1].chipset = ide_cmd640; ide_hwifs[1].tuneproc = &cmd640_tune_drive; if (ide_hwifs[1].drives[0].autotune == 0) @@ -411,7 +431,6 @@ /* We reset timings, and disable read-ahead */ put_cmd640_reg(ARTTIM23, (DIS_RA2 | DIS_RA3)); put_cmd640_reg(DRWTIM23, 0); - cmd640_reset_controller(1); } @@ -434,9 +453,10 @@ */ put_cmd640_reg(CMDTIM, 0); - printk("\n ... serialized, secondary interface %s\n", - second_port ? "enabled" : "disabled"); - + /* + * Tell everyone what we did to their system + */ + printk("\n ... serialized, secondary port %s\n", second_port_toggled ? "toggled" : "untouched"); return 1; } diff -u --recursive --new-file v1.3.74/linux/drivers/block/dtc2278.c linux/drivers/block/dtc2278.c --- v1.3.74/linux/drivers/block/dtc2278.c Sat Mar 2 10:43:22 1996 +++ linux/drivers/block/dtc2278.c Sat Mar 16 13:52:13 1996 @@ -117,6 +117,7 @@ restore_flags(flags); ide_hwifs[0].serialized = 1; + ide_hwifs[1].serialized = 1; ide_hwifs[0].chipset = ide_dtc2278; ide_hwifs[1].chipset = ide_dtc2278; ide_hwifs[0].tuneproc = &tune_dtc2278; diff -u --recursive --new-file v1.3.74/linux/drivers/block/ht6560b.c linux/drivers/block/ht6560b.c --- v1.3.74/linux/drivers/block/ht6560b.c Wed Feb 14 14:37:07 1996 +++ linux/drivers/block/ht6560b.c Sat Mar 16 13:52:13 1996 @@ -152,6 +152,7 @@ */ outb (timing, IDE_SELECT_REG); (void) inb (IDE_STATUS_REG); + OUT_BYTE(drive->select.all,IDE_SELECT_REG); restore_flags (flags); } } @@ -226,6 +227,7 @@ ide_hwifs[0].tuneproc = &tune_ht6560b; ide_hwifs[1].tuneproc = &tune_ht6560b; ide_hwifs[0].serialized = 1; + ide_hwifs[1].serialized = 1; } else printk("ht6560b: not found\n"); } diff -u --recursive --new-file v1.3.74/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v1.3.74/linux/drivers/block/ide-cd.c Wed Mar 13 10:09:13 1996 +++ linux/drivers/block/ide-cd.c Sat Mar 16 13:52:13 1996 @@ -1443,44 +1443,6 @@ } } - - -/**************************************************************************** - * drive_cmd handling. - * - * Most of the functions accessed via drive_cmd are not valid for ATAPI - * devices. Only attempt to execute those which actually should be valid. - */ - -static -void cdrom_do_drive_cmd (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - byte *args = rq->buffer; - - if (args) - { -#if 0 /* This bit isn't done yet... */ - if (args[0] == WIN_SETFEATURES && - (args[2] == 0x66 || args[2] == 0xcc || args[2] == 0x02 || - args[2] == 0xdd || args[2] == 0x5d)) - { - OUT_BYTE (args[2], io_base + IDE_FEATURE_OFFSET); - - } - else -#endif - { - printk ("%s: Unsupported drive command %02x %02x %02x\n", - drive->name, args[0], args[1], args[2]); - rq->errors = 1; - } - } - - cdrom_end_request (1, drive); -} - - /**************************************************************************** * cdrom driver request routine. @@ -1499,9 +1461,6 @@ ide_do_reset (drive); return; } - - else if (rq -> cmd == IDE_DRIVE_CMD) - cdrom_do_drive_cmd (drive); else if (rq -> cmd != READ) { diff -u --recursive --new-file v1.3.74/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v1.3.74/linux/drivers/block/ide-tape.c Wed Feb 14 14:37:08 1996 +++ linux/drivers/block/ide-tape.c Sat Mar 16 13:52:14 1996 @@ -163,7 +163,7 @@ * The recommended user block size is returned by * the MTIOCGET ioctl. * Additional minor changes. - * Ver 1.3 Feb 9 96 Fixed pipelined read mode bug which prevented the + * Ver 1.3 Feb 9 96 Fixed pipelined read mode bug which prevented the * use of some block sizes during a restore procedure. * The character device interface will now present a * continuous view of the media - any mix of block sizes @@ -180,6 +180,7 @@ * and can be enabled by using hdparm -d1 on the tape's * block device interface. For more info, read the * comments in triton.c. + * Ver 1.4 Mar 13 96 Fixed serialize support. * * We are currently in an *alpha* stage. The driver is not complete and not * much tested. I would strongly suggest to: @@ -1825,6 +1826,7 @@ unsigned int major = HWIF(drive)->major; idetape_tape_t *tape=&(drive->tape); struct blk_dev_struct *bdev = &blk_dev[major]; + struct request *next_rq; unsigned long flags; idetape_status_reg_t status; @@ -1839,7 +1841,7 @@ * we can safely access the tape. */ - if (bdev->current_request == NULL) { + if (HWGROUP (drive)->rq == NULL) { sti (); idetape_poll_for_dsc_direct (data); return; @@ -1928,8 +1930,13 @@ /* * Fallback to method 1. */ - - if (bdev->current_request->next == NULL) { + + next_rq=bdev->current_request; + if (next_rq == HWGROUP (drive)->rq) + next_rq=next_rq->next; + + if (next_rq == NULL) { + /* * There will not be another request after the currently * ongoing request, so ide.c won't be able to sample @@ -3383,10 +3390,12 @@ if (tape->active_data_request == NULL) idetape_insert_pipeline_into_queue (drive); - if (tape->active_data_request == NULL) - return; - save_flags (flags);cli (); + if (tape->active_data_request == NULL) { + restore_flags (flags); + return; + } + if (tape->last_stage != NULL) idetape_wait_for_request (&(tape->last_stage->rq)); diff -u --recursive --new-file v1.3.74/linux/drivers/block/ide-tape.h linux/drivers/block/ide-tape.h --- v1.3.74/linux/drivers/block/ide-tape.h Wed Feb 14 14:37:08 1996 +++ linux/drivers/block/ide-tape.h Sat Mar 16 13:52:14 1996 @@ -511,7 +511,7 @@ #define POLL_HWIF_TAPE_DRIVE \ if (hwif->tape_drive != NULL) { \ if (hwif->tape_drive->tape.request_status) { \ - OUT_BYTE(hwif->tape_drive->select.all,IDE_SELECT_REG); \ + SELECT_DRIVE(hwif,hwif->tape_drive); \ hwif->tape_drive->tape.last_status=GET_STAT(); \ hwif->tape_drive->tape.request_status=0; \ } \ diff -u --recursive --new-file v1.3.74/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v1.3.74/linux/drivers/block/ide.c Fri Mar 15 16:03:11 1996 +++ linux/drivers/block/ide.c Sat Mar 16 13:52:15 1996 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 5.30 Feb 27, 1996 + * linux/drivers/block/ide.c Version 5.33 Mar 15, 1996 * * Copyright (C) 1994-1996 Linus Torvalds & authors (see below) */ @@ -208,11 +208,21 @@ * Version 5.29 fixed non-IDE check for too many physical heads * don't use LBA if capacity is smaller than CHS * Version 5.30 remove real_devices kludge, formerly used by genhd.c + * Version 5.32 change "KB" to "kB" + * fix serialize (was broken in kernel 1.3.72) + * add support for "hdparm -I" + * use common code for disk/tape/cdrom IDE_DRIVE_CMDs + * add support for Promise DC4030VL caching card + * improved serialize support + * put partition check back into alphabetical order + * add config option for PCMCIA baggage + * try to make PCMCIA support safer to use + * improve security on ioctls(): all are suser() only + * Version 5.33 improve handling of HDIO_DRIVE_CMDs that read data * * Some additional driver compile-time options are in ide.h * * To do, in likely order of completion: - * - add Promise DC4030VL support from peterd@pnd-pc.demon.co.uk * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f */ @@ -247,7 +257,13 @@ #include "ide.h" #include "ide_modes.h" -static ide_hwgroup_t *irq_to_hwgroup [NR_IRQS]; +#ifdef CONFIG_BLK_DEV_PROMISE +#include "promise.h" +#define IS_PROMISE_DRIVE (HWIF(drive)->chipset == ide_promise) +#else +#define IS_PROMISE_DRIVE (0) /* auto-NULLs out Promise code */ +#endif /* CONFIG_BLK_DEV_PROMISE */ + static const byte ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR}; static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168}; @@ -285,6 +301,55 @@ #endif /* DISK_RECOVERY_TIME */ + +/* + * Do not even *think* about calling this! + */ +static void init_hwif_data (unsigned int index) +{ + byte *p; + unsigned int unit; + ide_hwif_t *hwif = &ide_hwifs[index]; + + /* bulk initialize hwif & drive info with zeros */ + p = ((byte *) hwif) + sizeof(ide_hwif_t); + do { + *--p = 0; + } while (p > (byte *) hwif); + + /* fill in any non-zero initial values */ + hwif->index = index; + hwif->noprobe = (index > 1); + hwif->io_base = default_io_base[index]; + hwif->ctl_port = hwif->io_base ? hwif->io_base+0x206 : 0x000; +#ifdef CONFIG_BLK_DEV_HD + if (hwif->io_base == HD_DATA) + hwif->noprobe = 1; /* may be overriden by ide_setup() */ +#endif /* CONFIG_BLK_DEV_HD */ + hwif->major = ide_hwif_to_major[index]; + hwif->name[0] = 'i'; + hwif->name[1] = 'd'; + hwif->name[2] = 'e'; + hwif->name[3] = '0' + index; +#ifdef CONFIG_BLK_DEV_IDETAPE + hwif->tape_drive = NULL; +#endif /* CONFIG_BLK_DEV_IDETAPE */ + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + + drive->select.all = (unit<<4)|0xa0; + drive->hwif = hwif; + drive->ctl = 0x08; + drive->ready_stat = READY_STAT; + drive->bad_wstat = BAD_W_STAT; + drive->special.b.recalibrate = 1; + drive->special.b.set_geometry = 1; + drive->name[0] = 'h'; + drive->name[1] = 'd'; + drive->name[2] = 'a' + (index * MAX_DRIVES) + unit; + } +} + /* * init_ide_data() sets reasonable default values into all fields * of all instances of the hwifs and drives, but only on the first call. @@ -302,58 +367,15 @@ #define MAGIC_COOKIE 0x12345678 static void init_ide_data (void) { - byte *p; - unsigned int h, unit; + unsigned int index; static unsigned long magic_cookie = MAGIC_COOKIE; if (magic_cookie != MAGIC_COOKIE) return; /* already initialized */ magic_cookie = 0; - for (h = 0; h < NR_IRQS; ++h) - irq_to_hwgroup[h] = NULL; - - /* bulk initialize hwif & drive info with zeros */ - p = ((byte *) ide_hwifs) + sizeof(ide_hwifs); - do { - *--p = 0; - } while (p > (byte *) ide_hwifs); - - /* fill in any non-zero initial values */ - for (h = 0; h < MAX_HWIFS; ++h) { - ide_hwif_t *hwif = &ide_hwifs[h]; - - hwif->index = h; - hwif->noprobe = (h > 1); - hwif->io_base = default_io_base[h]; - hwif->ctl_port = hwif->io_base ? hwif->io_base+0x206 : 0x000; -#ifdef CONFIG_BLK_DEV_HD - if (hwif->io_base == HD_DATA) - hwif->noprobe = 1; /* may be overriden by ide_setup() */ -#endif /* CONFIG_BLK_DEV_HD */ - hwif->major = ide_hwif_to_major[h]; - hwif->name[0] = 'i'; - hwif->name[1] = 'd'; - hwif->name[2] = 'e'; - hwif->name[3] = '0' + h; -#ifdef CONFIG_BLK_DEV_IDETAPE - hwif->tape_drive = NULL; -#endif /* CONFIG_BLK_DEV_IDETAPE */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - - drive->select.all = (unit<<4)|0xa0; - drive->hwif = hwif; - drive->ctl = 0x08; - drive->ready_stat = READY_STAT; - drive->bad_wstat = BAD_W_STAT; - drive->special.b.recalibrate = 1; - drive->special.b.set_geometry = 1; - drive->name[0] = 'h'; - drive->name[1] = 'd'; - drive->name[2] = 'a' + (h * MAX_DRIVES) + unit; - } - } + for (index = 0; index < MAX_HWIFS; ++index) + init_hwif_data(index); } #if SUPPORT_VLB_SYNC @@ -479,12 +501,14 @@ return 0; if (drive->media != ide_disk) return 0x7fffffff; /* cdrom or tape */ - drive->select.b.lba = 0; - /* Determine capacity, and use LBA if the drive properly supports it */ - if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) { - if (id->lba_capacity >= capacity) { - capacity = id->lba_capacity; - drive->select.b.lba = 1; + if (!IS_PROMISE_DRIVE) { + drive->select.b.lba = 0; + /* Determine capacity, and use LBA if the drive properly supports it */ + if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) { + if (id->lba_capacity >= capacity) { + capacity = id->lba_capacity; + drive->select.b.lba = 1; + } } } return (capacity - drive->sect0); @@ -524,7 +548,7 @@ */ static void init_gendisk (ide_hwif_t *hwif) { - struct gendisk *gd; + struct gendisk *gd, **gdp; unsigned int unit, units, minors; int *bs; @@ -555,9 +579,10 @@ gd->nr_real = units; /* current num real drives */ gd->init = ide_geninit; /* initialization function */ gd->real_devices= hwif; /* ptr to internal data */ + gd->next = NULL; /* linked list of major devs */ - gd->next = gendisk_head; /* link new major into list */ - hwif->gd = gendisk_head = gd; + for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) ; + hwif->gd = *gdp = gd; /* link onto tail of list */ } static void do_reset1 (ide_drive_t *, int); /* needed below */ @@ -695,9 +720,12 @@ if (OK_TO_RESET_CONTROLLER) rdrive->mult_count = 0; if (!rdrive->keep_settings) { - rdrive->using_dma = 0; rdrive->mult_req = 0; rdrive->unmask = 0; + if (rdrive->using_dma) { + rdrive->using_dma = 0; + printk("%s: disabled DMA\n", rdrive->name); + } } if (rdrive->mult_req != rdrive->mult_count) rdrive->special.b.set_multmode = 1; @@ -860,8 +888,7 @@ if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL) return; /* retry only "normal" I/O: */ - if (rq->cmd == IDE_DRIVE_CMD || (rq->cmd != READ && rq->cmd != WRITE && drive->media == ide_disk)) - { + if (rq->cmd == IDE_DRIVE_CMD) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return; @@ -980,13 +1007,12 @@ } /* - * multwrite() transfers a block of one or more sectors of data to a drive - * as part of a disk multwrite operation. + * ide_multwrite() transfers a block of up to mcount sectors of data + * to a drive as part of a disk multiple-sector write operation. */ -static void multwrite (ide_drive_t *drive) +void ide_multwrite (ide_drive_t *drive, unsigned int mcount) { struct request *rq = &HWGROUP(drive)->wrq; - unsigned int mcount = drive->mult_count; do { unsigned int nsect = rq->current_nr_sectors; @@ -1029,7 +1055,7 @@ if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { if (stat & DRQ_STAT) { if (rq->nr_sectors) { - multwrite(drive); + ide_multwrite(drive, drive->mult_count); ide_set_handler (drive, &multwrite_intr, WAIT_CMD); return; } @@ -1105,9 +1131,15 @@ */ static void drive_cmd_intr (ide_drive_t *drive) { + struct request *rq = HWGROUP(drive)->rq; + byte *args = (byte *) rq->buffer; byte stat = GET_STAT(); sti(); + if ((stat & DRQ_STAT) && args && args[3]) { + ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS); + stat = GET_STAT(); + } if (OK_STAT(stat,READY_STAT,BAD_STAT)) ide_end_drive_cmd (drive, stat, GET_ERR()); else @@ -1132,13 +1164,13 @@ OUT_BYTE(drive->cyl,IDE_LCYL_REG); OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG); OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG); - ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr); + if (!IS_PROMISE_DRIVE) + ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr); } } else if (s->b.recalibrate) { s->b.recalibrate = 0; - if (drive->media == ide_disk) { + if (drive->media == ide_disk && !IS_PROMISE_DRIVE) ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr); - } } else if (s->b.set_pio) { ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc; s->b.set_pio = 0; @@ -1150,7 +1182,8 @@ if (drive->media == ide_disk) { if (drive->id && drive->mult_req > drive->id->max_multsect) drive->mult_req = drive->id->max_multsect; - ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr); + if (!IS_PROMISE_DRIVE) + ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr); } else drive->mult_req = 0; } else if (s->all) { @@ -1201,13 +1234,14 @@ } /* - * do_rw_disk() issues WIN_{MULT}READ and WIN_{MULT}WRITE commands to a disk, - * using LBA if supported, or CHS otherwise, to address sectors. It also takes - * care of issuing special DRIVE_CMDs. + * do_rw_disk() issues READ and WRITE commands to a disk, + * using LBA if supported, or CHS otherwise, to address sectors. + * It also takes care of issuing special DRIVE_CMDs. */ static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) { - unsigned short io_base = HWIF(drive)->io_base; + ide_hwif_t *hwif = HWIF(drive); + unsigned short io_base = hwif->io_base; OUT_BYTE(drive->ctl,IDE_CONTROL_REG); OUT_BYTE(rq->nr_sectors,io_base+IDE_NSECTOR_OFFSET); @@ -1237,6 +1271,14 @@ head, sect, rq->nr_sectors, (unsigned long) rq->buffer); #endif } +#ifdef CONFIG_BLK_DEV_PROMISE + if (IS_PROMISE_DRIVE) { + if (hwif->is_promise2 || rq->cmd == READ) { + do_promise_io (drive, rq); + return; + } + } +#endif /* CONFIG_BLK_DEV_PROMISE */ if (rq->cmd == READ) { #ifdef CONFIG_BLK_DEV_TRITON if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive))) @@ -1262,37 +1304,43 @@ if (drive->mult_count) { HWGROUP(drive)->wrq = *rq; /* scratchpad */ ide_set_handler (drive, &multwrite_intr, WAIT_CMD); - multwrite(drive); + ide_multwrite(drive, drive->mult_count); } else { ide_set_handler (drive, &write_intr, WAIT_CMD); ide_output_data(drive, rq->buffer, SECTOR_WORDS); } return; } - if (rq->cmd == IDE_DRIVE_CMD) { - byte *args = rq->buffer; - if (args) { + printk("%s: bad command: %d\n", drive->name, rq->cmd); + ide_end_request(0, HWGROUP(drive)); +} + +/* + * execute_drive_cmd() issues a special drive command, + * usually initiated by ioctl() from the external hdparm program. + */ +static void execute_drive_cmd (ide_drive_t *drive, struct request *rq) +{ + byte *args = rq->buffer; + if (args) { #ifdef DEBUG - printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x\n", - drive->name, args[0], args[1], args[2]); + printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n", + drive->name, args[0], args[1], args[2], args[3]); #endif - OUT_BYTE(args[2],io_base+IDE_FEATURE_OFFSET); - ide_cmd(drive, args[0], args[1], &drive_cmd_intr); - return; - } else { - /* - * NULL is actually a valid way of waiting for - * all current requests to be flushed from the queue. - */ + OUT_BYTE(args[2],IDE_FEATURE_REG); + ide_cmd(drive, args[0], args[1], &drive_cmd_intr); + return; + } else { + /* + * NULL is actually a valid way of waiting for + * all current requests to be flushed from the queue. + */ #ifdef DEBUG - printk("%s: DRIVE_CMD (null)\n", drive->name); + printk("%s: DRIVE_CMD (null)\n", drive->name); #endif - ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); - return; - } + ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); + return; } - printk("%s: bad command: %d\n", drive->name, rq->cmd); - ide_end_request(0, HWGROUP(drive)); } /* @@ -1335,10 +1383,6 @@ block = 1; /* redirect MBR access to EZ-Drive partn table */ #endif /* FAKE_FDISK_FOR_EZDRIVE */ ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive; -#ifdef CONFIG_BLK_DEV_HT6560B - if (hwif->selectproc) - hwif->selectproc (drive); -#endif /* CONFIG_BLK_DEV_HT6560B */ #if (DISK_RECOVERY_TIME > 0) while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME); #endif @@ -1347,13 +1391,17 @@ POLL_HWIF_TAPE_DRIVE; /* macro from ide-tape.h */ #endif /* CONFIG_BLK_DEV_IDETAPE */ - OUT_BYTE(drive->select.all,IDE_SELECT_REG); + SELECT_DRIVE(hwif,drive); if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { printk("%s: drive not ready for command\n", drive->name); return; } if (!drive->special.all) { + if (rq->cmd == IDE_DRIVE_CMD) { + execute_drive_cmd(drive, rq); + return; + } #ifdef CONFIG_BLK_DEV_IDEATAPI switch (drive->media) { case ide_disk: @@ -1366,12 +1414,6 @@ #endif /* CONFIG_BLK_DEV_IDECD */ #ifdef CONFIG_BLK_DEV_IDETAPE case ide_tape: - if (rq->cmd == IDE_DRIVE_CMD) { - byte *args = (byte *) rq->buffer; - OUT_BYTE(args[2],IDE_FEATURE_REG); - ide_cmd(drive, args[0], args[1], &drive_cmd_intr); - return; - } idetape_do_request (drive, rq, block); return; #endif /* CONFIG_BLK_DEV_IDETAPE */ @@ -1418,15 +1460,21 @@ ide_hwif_t *hwif = hwgroup->hwif; struct request *rq; if ((rq = hwgroup->rq) == NULL) { + /* + * hwgroup->next_hwif is different from hwgroup->hwif + * only when a request is inserted using "ide_next". + * This saves wear and tear on IDE tapes. + */ + hwif = hwgroup->next_hwif; do { rq = blk_dev[hwif->major].current_request; if (rq != NULL && rq->rq_status != RQ_INACTIVE) goto got_rq; - } while ((hwif = hwif->next) != hwgroup->hwif); + } while ((hwif = hwif->next) != hwgroup->next_hwif); return; /* no work left for this hwgroup */ } got_rq: - do_request(hwgroup->hwif = hwif, hwgroup->rq = rq); + do_request(hwgroup->hwif = hwgroup->next_hwif = hwif, hwgroup->rq = rq); cli(); } while (hwgroup->handler == NULL); } @@ -1548,10 +1596,7 @@ ide_drive_t *drive = &hwif->drives[unit]; if (!drive->present) continue; -#ifdef CONFIG_BLK_DEV_HT6560B - if (hwif->selectproc) - hwif->selectproc (drive); -#endif /* CONFIG_BLK_DEV_HT6560B */ + SELECT_DRIVE(hwif,drive); if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) (void) ide_dump_status(drive, "unexpected_intr", stat); if ((stat & DRQ_STAT)) @@ -1559,18 +1604,15 @@ } } } while ((hwif = hwif->next) != hwgroup->hwif); -#ifdef CONFIG_BLK_DEV_HT6560B - if (hwif->selectproc) - hwif->selectproc (hwgroup->drive); -#endif /* CONFIG_BLK_DEV_HT6560B */ + SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */ } /* * entry point for all interrupts, caller does cli() for us */ -static void ide_intr (int irq, void *dev_id, struct pt_regs *regs) +void ide_intr (int irq, void *dev_id, struct pt_regs *regs) { - ide_hwgroup_t *hwgroup = irq_to_hwgroup[irq]; + ide_hwgroup_t *hwgroup = dev_id; ide_handler_t *handler; if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) { @@ -1674,6 +1716,8 @@ struct blk_dev_struct *bdev = &blk_dev[major]; struct semaphore sem = MUTEX_LOCKED; + if (IS_PROMISE_DRIVE && rq->buffer != NULL) + return -ENOSYS; /* special drive cmds not supported */ rq->errors = 0; rq->rq_status = RQ_ACTIVE; rq->rq_dev = MKDEV(major,(drive->select.b.unit)<next_hwif = HWIF(drive); cur_rq = bdev->current_request; if (cur_rq == NULL || action == ide_preempt) { @@ -1842,19 +1888,22 @@ static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct hd_geometry *loc = (struct hd_geometry *) arg; int err; ide_drive_t *drive; unsigned long flags; struct request rq; - ide_init_drive_cmd (&rq); + if (!suser()) + return -EACCES; if (!inode || !(inode->i_rdev)) return -EINVAL; if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENODEV; + ide_init_drive_cmd (&rq); switch (cmd) { case HDIO_GETGEO: + { + struct hd_geometry *loc = (struct hd_geometry *) arg; if (!loc || drive->media != ide_disk) return -EINVAL; err = verify_area(VERIFY_WRITE, loc, sizeof(*loc)); if (err) return err; @@ -1864,15 +1913,13 @@ put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect, (unsigned long *) &loc->start); return 0; - + } case BLKFLSBUF: - if(!suser()) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRASET: - if(!suser()) return -EACCES; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; @@ -1926,8 +1973,6 @@ if (arg > 1) return -EINVAL; case HDIO_SET_32BIT: - if (!suser()) - return -EACCES; if ((MINOR(inode->i_rdev) & PARTN_MASK)) return -EINVAL; save_flags(flags); @@ -1967,8 +2012,6 @@ return 0; case HDIO_SET_MULTCOUNT: - if (!suser()) - return -EACCES; if (MINOR(inode->i_rdev) & PARTN_MASK) return -EINVAL; if (drive->id && arg > drive->id->max_multsect) @@ -1987,26 +2030,33 @@ case HDIO_DRIVE_CMD: { - unsigned long args; - - if (NULL == (long *) arg) + byte args[4], *argbuf = args; + int argsize = 4; + if (NULL == (void *) arg) { err = ide_do_drive_cmd(drive, &rq, ide_wait); - else { - if (!(err = verify_area(VERIFY_READ,(long *)arg,sizeof(long)))) - { - args = get_user((long *)arg); - if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long)))) { - rq.buffer = (char *) &args; - err = ide_do_drive_cmd(drive, &rq, ide_wait); - put_user(args,(long *)arg); - } + } else if (!(err = verify_area(VERIFY_READ,(void *)arg, 4))) { + memcpy_fromfs(args, (void *)arg, 4); + if (args[3]) { + argsize = 4 + (SECTOR_WORDS * 4 * args[3]); + argbuf = kmalloc(argsize, GFP_KERNEL); + if (argbuf == NULL) + return -ENOMEM; + argbuf[0] = args[0]; + argbuf[1] = args[1]; + argbuf[2] = args[2]; + argbuf[3] = args[3]; } + if (!(err = verify_area(VERIFY_WRITE,(void *)arg, argsize))) { + rq.buffer = argbuf; + err = ide_do_drive_cmd(drive, &rq, ide_wait); + memcpy_tofs((void *)arg, argbuf, argsize); + } + if (argsize > 4) + kfree(argbuf); } return err; } case HDIO_SET_PIO_MODE: - if (!suser()) - return -EACCES; if (MINOR(inode->i_rdev) & PARTN_MASK) return -EINVAL; if (!HWIF(drive)->tuneproc) @@ -2117,6 +2167,13 @@ if (cmd == WIN_PIDENTIFY) { byte type = (id->config >> 8) & 0x1f; printk("%s: %s, ATAPI ", drive->name, id->model); +#ifdef CONFIG_BLK_DEV_PROMISE + if (HWIF(drive)->is_promise2) { + printk(" -- not supported on 2nd Promise port\n"); + drive->present = 0; + return; + } +#endif /* CONFIG_BLK_DEV_PROMISE */ switch (type) { case 0: /* Early cdrom models used zero */ case 5: @@ -2226,7 +2283,7 @@ (void) current_capacity (drive); /* initialize LBA selection */ - printk ("%s: %.40s, %ldMB w/%dKB Cache, %sCHS=%d/%d/%d", + printk ("%s: %.40s, %ldMB w/%dkB Cache, %sCHS=%d/%d/%d", drive->name, id->model, current_capacity(drive)/2048L, id->buf_size/2, drive->select.b.lba ? "LBA, " : "", drive->bios_cyl, drive->bios_head, drive->bios_sect); @@ -2286,7 +2343,13 @@ } else hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */ - OUT_BYTE(cmd,IDE_COMMAND_REG); /* ask drive for ID */ +#if CONFIG_BLK_DEV_PROMISE + if (IS_PROMISE_DRIVE) { + if(promise_cmd(drive,PROMISE_IDENTIFY)) + return 1; + } else +#endif /* CONFIG_BLK_DEV_PROMISE */ + OUT_BYTE(cmd,IDE_COMMAND_REG); /* ask drive for ID */ timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; timeout += jiffies; do { @@ -2339,6 +2402,7 @@ static int do_probe (ide_drive_t *drive, byte cmd) { int rc; + ide_hwif_t *hwif; #ifdef CONFIG_BLK_DEV_IDEATAPI if (drive->present) { /* avoid waiting for inappropriate probes */ if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY)) @@ -2350,10 +2414,8 @@ drive->name, drive->present, drive->media, (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI"); #endif -#ifdef CONFIG_BLK_DEV_HT6560B - if (HWIF(drive)->selectproc) - HWIF(drive)->selectproc (drive); -#endif /* CONFIG_BLK_DEV_HT6560B */ + hwif = HWIF(drive); + SELECT_DRIVE(hwif,drive); OUT_BYTE(drive->select.all,IDE_SELECT_REG); /* select target drive */ delay_10ms(); /* wait for BUSY_STAT */ if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) { @@ -2422,7 +2484,12 @@ { unsigned int unit; +#if CONFIG_BLK_DEV_PROMISE + if (!hwif->is_promise2 && + (check_region(hwif->io_base,8) || check_region(hwif->ctl_port,1))) { +#else if (check_region(hwif->io_base,8) || check_region(hwif->ctl_port,1)) { +#endif /* CONFIG_BLK_DEV_PROMISE */ int msgout = 0; for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; @@ -2447,6 +2514,8 @@ ide_drive_t *drive = &hwif->drives[unit]; (void) probe_for_drive (drive); if (drive->present && drive->media == ide_disk) { + if (IS_PROMISE_DRIVE) + drive->select.b.lba = 1; /* required by promise driver */ if ((!drive->head || drive->head > 16) && !drive->select.b.lba) { printk("%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head); @@ -2559,11 +2628,11 @@ * "idex=noautotune" : driver will NOT attempt to tune interface speed * This is the default for most chipsets, * except the cmd640. + * "idex=serialize" : do not overlap operations on idex and ide(x^1) * * The following two are valid ONLY on ide0, * and the defaults for the base,ctl ports must not be altered. * - * "ide0=serialize" : do not overlap operations on ide0 and ide1. * "ide0=dtc2278" : probe/support DTC2278 interface * "ide0=ht6560b" : probe/support HT6560B interface * "ide0=cmd640_vlb" : *REQUIRED* for VLB cards with the CMD640 chip @@ -2609,7 +2678,7 @@ hwif->noprobe = 0; goto done; case -4: /* "serialize" */ - printk(" -- USE \"ide%c=serialize\" INSTEAD", '0'+hw); + printk(" -- USE \"ide%d=serialize\" INSTEAD", hw); goto do_serialize; case -5: /* "autotune" */ drive->autotune = 1; @@ -2638,7 +2707,7 @@ * Be VERY CAREFUL changing this: note hardcoded indexes below */ const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", - "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", NULL}; + "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL}; hw = s[3] - '0'; hwif = &ide_hwifs[hw]; i = match_parm(&s[4], ide_words, vals, 3); @@ -2659,6 +2728,13 @@ goto bad_hwif; switch (i) { +#ifdef CONFIG_BLK_DEV_PROMISE + case -11: /* "dc4030" */ + { + setup_dc4030(hwif); + goto done; + } +#endif /* CONFIG_BLK_DEV_PROMISE */ #ifdef CONFIG_BLK_DEV_ALI14XX case -10: /* "ali14xx" */ { @@ -2717,8 +2793,8 @@ goto done; case -2: /* "serialize" */ do_serialize: - if (hw > 1) goto bad_hwif; - ide_hwifs[0].serialized = 1; + ide_hwifs[hw].serialized = 1; /* serialize */ + ide_hwifs[hw^1].serialized = 1; /* with mate */ goto done; case -1: /* "noprobe" */ @@ -2853,6 +2929,10 @@ byte cmos_disks, *BIOS = (byte *) &drive_info; int unit; +#ifdef CONFIG_BLK_DEV_PROMISE + if (hwif->is_promise2) + return; +#endif /* CONFIG_BLK_DEV_PROMISE */ outb_p(0x12,0x70); /* specify CMOS address 0x12 */ cmos_disks = inb_p(0x71); /* read the data from 0x12 */ /* Extract drive geometry from CMOS+BIOS if not already setup */ @@ -2882,35 +2962,43 @@ static int init_irq (ide_hwif_t *hwif) { unsigned long flags; - int irq = hwif->irq; - ide_hwgroup_t *hwgroup = irq_to_hwgroup[irq]; + ide_hwgroup_t *hwgroup = hwif->hwgroup; + ide_hwif_t *mate_hwif; + unsigned int index, mate_irq = hwif->irq; save_flags(flags); cli(); /* - * Grab the irq if we don't already have it from a previous hwif + * Handle serialization, regardless of init sequence */ - if (hwgroup == NULL) { - if (request_irq(irq, ide_intr, SA_INTERRUPT|SA_SAMPLE_RANDOM, hwif->name, NULL)) { - restore_flags(flags); - printk(" -- FAILED!"); - return 1; - } + mate_hwif = &ide_hwifs[hwif->index ^ 1]; + if (hwif->serialized && mate_hwif->present) { + hwgroup = mate_hwif->hwgroup; + mate_irq = mate_hwif->irq; } + /* - * Check for serialization with ide0. - * This code depends on us having already taken care of ide0. + * If another hwif is sharing our irq, then join its hwgroup. */ - if (hwif->index == 1 && ide_hwifs[0].serialized && ide_hwifs[0].present) - hwgroup = ide_hwifs[0].hwgroup; + if (hwgroup == NULL) { + for (index = 0; index < MAX_HWIFS; index++) { + if (index != hwif->index) { + ide_hwif_t *g = &ide_hwifs[index]; + if (g->irq == hwif->irq || g->irq == mate_irq) { + hwgroup = ide_hwifs[index].hwgroup; + break; + } + } + } + } + /* - * If this is the first interface in a group, - * then we need to create the hwgroup structure + * If we are still without a hwgroup, then form a new one */ if (hwgroup == NULL) { hwgroup = kmalloc (sizeof(ide_hwgroup_t), GFP_KERNEL); - hwgroup->hwif = hwif->next = hwif; + hwgroup->hwif = hwgroup->next_hwif = hwif->next = hwif; hwgroup->rq = NULL; hwgroup->handler = NULL; hwgroup->drive = &hwif->drives[0]; @@ -2918,17 +3006,30 @@ init_timer(&hwgroup->timer); hwgroup->timer.function = &timer_expiry; hwgroup->timer.data = (unsigned long) hwgroup; - } else { - hwif->next = hwgroup->hwif->next; - hwgroup->hwif->next = hwif; } + + /* + * Allocate the irq, if not already obtained for another hwif + */ + if (!hwif->got_irq) { + if (request_irq(hwif->irq, ide_intr, SA_INTERRUPT|SA_SAMPLE_RANDOM, hwif->name, hwgroup)) { + restore_flags(flags); + return 1; + } + hwif->got_irq = 1; + } + + /* + * Everything is okay, so link us into the hwgroup + */ hwif->hwgroup = hwgroup; - irq_to_hwgroup[irq] = hwgroup; + hwif->next = hwgroup->hwif->next; + hwgroup->hwif->next = hwif; restore_flags(flags); /* safe now that hwif->hwgroup is set up */ printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name, - hwif->io_base, hwif->io_base+7, hwif->ctl_port, irq); + hwif->io_base, hwif->io_base+7, hwif->ctl_port, hwif->irq); if (hwgroup->hwif != hwif) printk(" (serialized with %s)", hwgroup->hwif->name); printk("\n"); @@ -3012,6 +3113,9 @@ ide_probe_for_cmd640x(); } #endif +#ifdef CONFIG_BLK_DEV_PROMISE + init_dc4030(); +#endif } static int hwif_init (int h) @@ -3076,7 +3180,7 @@ */ int ide_init (void) { - int h; + int index; init_ide_data (); /* @@ -3087,8 +3191,8 @@ /* * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports */ - for (h = 0; h < MAX_HWIFS; ++h) - hwif_init(h); + for (index = 0; index < MAX_HWIFS; ++index) + hwif_init (index); #ifdef CONFIG_BLK_DEV_IDETAPE idetape_register_chrdev(); /* Register character device interface to the ide tape */ @@ -3097,61 +3201,107 @@ return 0; } +#ifdef CONFIG_BLK_DEV_IDE_PCMCIA int ide_register(int io_base, int ctl_port, int irq) { - int h, i; + int index, i, rc = -1; ide_hwif_t *hwif; - for (h = 0; h < MAX_HWIFS; ++h) { - hwif = &ide_hwifs[h]; - if (hwif->present == 0) break; - } - hwif->io_base = io_base; - hwif->ctl_port = ctl_port; - hwif->irq = irq; - hwif->noprobe = 0; - if (hwif_init(h) != 0) { - hwif->gd->real_devices = hwif->drives[0].name; - for (i = 0; i < hwif->gd->nr_real; i++) - revalidate_disk(MKDEV(hwif->major, i<present) { + if (hwif->io_base == io_base || hwif->ctl_port == ctl_port) + break; + } else { + hwif->io_base = io_base; + hwif->ctl_port = ctl_port; + hwif->irq = irq; + hwif->noprobe = 0; + if (!hwif_init(index)) + break; + hwif->gd->real_devices = hwif->drives[0].name; + for (i = 0; i < hwif->gd->nr_real; i++) + revalidate_disk(MKDEV(hwif->major, i<= MAX_HWIFS)) + if (index >= MAX_HWIFS) + return; + save_flags(flags); + cli(); + hwif = &ide_hwifs[index]; + if (!hwif->present || hwif->drives[0].busy || hwif->drives[1].busy) { + restore_flags(flags); return; - hwif = &ide_hwifs[h]; - if (hwif->present) { - hwif->present = 0; - /* This assumes that there is only one group member */ - free_irq(hwif->irq, NULL); - kfree(hwif->hwgroup); - irq_to_hwgroup[hwif->irq] = NULL; - unregister_blkdev(hwif->major, hwif->name); - kfree(blksize_size[hwif->major]); - blk_dev[hwif->major].request_fn = NULL; - blksize_size[hwif->major] = NULL; - gd = gendisk_head; prev_gd = NULL; - while (gd && (gd != hwif->gd)) { - prev_gd = gd; - gd = gd->next; - } - if (gd != hwif->gd) - printk("gd not in disk chain!\n"); - else { - if (prev_gd != NULL) - prev_gd->next = gd->next; - else - gendisk_head = gd->next; - kfree(gd->sizes); - kfree(gd->part); - kfree(gd); - } } + hwif->present = 0; + hwgroup = hwif->hwgroup; + + /* + * free the irq if we were the only hwif using it + */ + g = hwgroup->hwif; + do { + if (g->irq == hwif->irq) + ++irq_count; + g = g->next; + } while (g != hwgroup->hwif); + if (irq_count == 1) + free_irq(hwif->irq, hwgroup); + + /* + * Remove us from the hwgroup, and free + * the hwgroup if we were the only member + */ + while (hwgroup->hwif->next != hwif) + hwgroup->hwif = hwgroup->hwif->next; + hwgroup->hwif->next = hwif->next; + if (hwgroup->hwif == hwif) + hwgroup->hwif = hwif->next; + if (hwgroup->next_hwif == hwif) + hwgroup->next_hwif = hwif->next; + if (hwgroup->hwif == hwif) + kfree(hwgroup); + + /* + * Remove us from the kernel's knowledge + */ + unregister_blkdev(hwif->major, hwif->name); + kfree(blksize_size[hwif->major]); + blk_dev[hwif->major].request_fn = NULL; + blksize_size[hwif->major] = NULL; + gd = gendisk_head; prev_gd = NULL; + while (gd && (gd != hwif->gd)) { + prev_gd = gd; + gd = gd->next; + } + if (gd != hwif->gd) + printk("gd not in disk chain!\n"); + else { + if (prev_gd != NULL) + prev_gd->next = gd->next; + else + gendisk_head = gd->next; + kfree(gd->sizes); + kfree(gd->part); + kfree(gd); + } + init_hwif_data (index); /* restore hwif data to pristine status */ + restore_flags(flags); } +#endif /* CONFIG_BLK_DEV_IDE_PCMCIA */ diff -u --recursive --new-file v1.3.74/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v1.3.74/linux/drivers/block/ide.h Wed Mar 13 10:09:15 1996 +++ linux/drivers/block/ide.h Sat Mar 16 15:01:24 1996 @@ -74,7 +74,7 @@ * Definitions for accessing IDE controller registers */ -#define HWIF(drive) ((ide_hwif_t *)drive->hwif) +#define HWIF(drive) ((ide_hwif_t *)((drive)->hwif)) #define HWGROUP(drive) ((ide_hwgroup_t *)(HWIF(drive)->hwgroup)) #define IDE_DATA_OFFSET (0) @@ -102,10 +102,10 @@ #define IDE_ALTSTATUS_REG IDE_CONTROL_REG #ifdef REALLY_FAST_IO -#define OUT_BYTE(b,p) outb((b),p) +#define OUT_BYTE(b,p) outb((b),(p)) #define IN_BYTE(p) (byte)inb(p) #else -#define OUT_BYTE(b,p) outb_p((b),p) +#define OUT_BYTE(b,p) outb_p((b),(p)) #define IN_BYTE(p) (byte)inb_p(p) #endif /* REALLY_FAST_IO */ @@ -140,6 +140,18 @@ #define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */ #define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ +#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PROMISE) +#define SELECT_DRIVE(hwif,drive) \ +{ \ + if (hwif->selectproc) \ + hwif->selectproc(drive); \ + else \ + OUT_BYTE((drive)->select.all, hwif->io_base+IDE_SELECT_OFFSET); \ +} +#else +#define SELECT_DRIVE(hwif,drive) OUT_BYTE((drive)->select.all, hwif->io_base+IDE_SELECT_OFFSET); +#endif /* CONFIG_BLK_DEV_HT6560B || CONFIG_BLK_DEV_PROMISE */ + #ifdef CONFIG_BLK_DEV_IDETAPE #include "ide-tape.h" #endif /* CONFIG_BLK_DEV_IDETAPE */ @@ -340,7 +352,6 @@ #ifdef CONFIG_BLK_DEV_IDETAPE idetape_tape_t tape; /* for ide-tape.c */ #endif /* CONFIG_BLK_DEV_IDETAPE */ - } ide_drive_t; /* @@ -377,8 +388,7 @@ typedef void (ide_tuneproc_t)(ide_drive_t *, byte); /* - * This is used to provide HT6560B interface support. - * It will probably also be used by the DC4030VL driver. + * This is used to provide HT6560B & PROMISE interface support. */ typedef void (ide_selectproc_t) (ide_drive_t *); @@ -388,7 +398,8 @@ */ typedef enum { ide_unknown, ide_generic, ide_triton, ide_cmd640, ide_dtc2278, ide_ali14xx, - ide_qd6580, ide_umc8672, ide_ht6560b } + ide_qd6580, ide_umc8672, ide_ht6560b, + ide_promise } hwif_chipset_t; typedef struct hwif_s { @@ -399,9 +410,9 @@ ide_drive_t drives[MAX_DRIVES]; /* drive info */ struct gendisk *gd; /* gendisk structure */ ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */ -#ifdef CONFIG_BLK_DEV_HT6560B +#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PROMISE) ide_selectproc_t *selectproc; /* tweaks hardware to select drive */ -#endif /* CONFIG_BLK_DEV_HT6560B */ +#endif ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */ unsigned long *dmatable; /* dma physical region descriptor table */ unsigned short dma_base; /* base addr for dma ports (triton) */ @@ -410,10 +421,14 @@ char name[5]; /* name of interface, eg. "ide0" */ byte index; /* 0 for ide0; 1 for ide1; ... */ hwif_chipset_t chipset; /* sub-module for tuning.. */ - unsigned noprobe : 1; /* don't probe for this interface */ - unsigned present : 1; /* this interface exists */ - unsigned serialized : 1; /* valid only for ide_hwifs[0] */ - unsigned no_unmask : 1; /* disallow setting unmask bits */ + unsigned noprobe : 1; /* don't probe for this interface */ + unsigned present : 1; /* this interface exists */ + unsigned serialized : 1; /* serialized operation with mate hwif */ + unsigned no_unmask : 1; /* disallow setting unmask bits */ + unsigned got_irq : 1; /* 1 = already alloc'd our irq */ +#ifdef CONFIG_BLK_DEV_PROMISE + unsigned is_promise2: 1; /* 2nd i/f on promose DC4030 */ +#endif /* CONFIG_BLK_DEV_PROMISE */ #if (DISK_RECOVERY_TIME > 0) unsigned long last_time; /* time when previous rq was done */ #endif @@ -435,6 +450,7 @@ ide_handler_t *handler;/* irq handler, if active */ ide_drive_t *drive; /* current drive */ ide_hwif_t *hwif; /* ptr to current hwif in linked-list */ + ide_hwif_t *next_hwif; /* next selected hwif (for tape) */ struct request *rq; /* current request */ struct timer_list timer; /* failsafe timer */ struct request wrq; /* local copy of current write rq */ @@ -583,6 +599,12 @@ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD). */ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); + +/* + * ide_multwrite() transfers a block of up to mcount sectors of data + * to a drive as part of a disk multwrite operation. + */ +void ide_multwrite (ide_drive_t *drive, unsigned int mcount); #ifdef CONFIG_BLK_DEV_IDECD /* diff -u --recursive --new-file v1.3.74/linux/drivers/block/promise.c linux/drivers/block/promise.c --- v1.3.74/linux/drivers/block/promise.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/promise.c Sat Mar 16 13:52:15 1996 @@ -0,0 +1,346 @@ +/* + * linux/drivers/block/promise.c Version 0.04 Mar 15, 1996 + * + * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) + */ + +/* + * Principal Author/Maintainer: peterd@pnd-pc.demon.co.uk + * + * This file provides support for the second port and cache of Promise + * IDE interfaces, e.g. DC4030, DC5030. + * + * Thanks are due to Mark Lord for advice and patiently answering stupid + * questions, and all those mugs^H^H^H^Hbrave souls who've tested this. + * + * Version 0.01 Initial version, #include'd in ide.c rather than + * compiled separately. + * Reads use Promise commands, writes as before. Drives + * on second channel are read-only. + * Version 0.02 Writes working on second channel, reads on both + * channels. Writes fail under high load. Suspect + * transfers of >127 sectors don't work. + * Version 0.03 Brought into line with ide.c version 5.27. + * Other minor changes. + * Version 0.04 Updated for ide.c version 5.30 + * Changed initialization strategy + * Version 0.05 Kernel integration. -ml + */ + + +/* + * From: 'peterd@pnd-pc.demon.co.uk' + * + * Here's another version of the Promise driver for DC4030VL2 cards. + * There have been few substantive changes to the code, but it is now in + * line with the more recent ide.c changes, and is somewhat more configurable. + * + * Once you've compiled it in, you'll have to also enable the interface + * setup routine from the kernel command line, as in + * + * 'linux ide0=dc4030' + * + * As before, it seems that somewhere around 3Megs when writing, bad things + * start to happen [timeouts/retries -ml]. If anyone can give me more feedback, + * I'd really appreciate it. [email: peterd@pnd-pc.demon.co.uk] + * + */ + + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ide.h" +#include "promise.h" + +/* This is needed as the controller may not interrupt if the required data is +available in the cache. We have to simulate an interrupt. Ugh! */ + +extern void ide_intr(int, void *dev_id, struct pt_regs*); + +/* + * promise_selectproc() is invoked by ide.c + * in preparation for access to the specified drive. + */ +static void promise_selectproc (ide_drive_t *drive) +{ + unsigned int number; + + OUT_BYTE(drive->select.all,IDE_SELECT_REG); + udelay(1); /* paranoia */ + number = ((HWIF(drive)->is_promise2)<<1) + drive->select.b.unit; + OUT_BYTE(number,IDE_FEATURE_REG); +} + +/* + * promise_cmd handles the set of vendor specific commands that are initiated + * by command F0. They all have the same success/failure notification. + */ +int promise_cmd(ide_drive_t *drive, byte cmd) +{ + unsigned long timeout, timer; + byte status_val; + + promise_selectproc(drive); /* redundant? */ + OUT_BYTE(0xF3,IDE_SECTOR_REG); + OUT_BYTE(cmd,IDE_SELECT_REG); + OUT_BYTE(PROMISE_EXTENDED_COMMAND,IDE_COMMAND_REG); + timeout = HZ * 10; + timeout += jiffies; + do { + if(jiffies > timeout) { + return 2; /* device timed out */ + } + /* This is out of delay_10ms() */ + /* Delays at least 10ms to give interface a chance */ + timer = jiffies + (HZ + 99)/100 + 1; + while (timer > jiffies); + status_val = IN_BYTE(IDE_SECTOR_REG); + } while (status_val != 0x50 && status_val != 0x70); + + if(status_val == 0x50) + return 0; /* device returned success */ + else + return 1; /* device returned failure */ +} + +ide_hwif_t *hwif_required = NULL; + +void setup_dc4030 (ide_hwif_t *hwif) +{ + hwif_required = hwif; +} + +/* +init_dc4030: Test for presence of a Promise caching controller card. +Returns: 0 if no Promise card present at this io_base + 1 if Promise card found +*/ +int init_dc4030 (void) +{ + ide_hwif_t *hwif = hwif_required; + ide_drive_t *drive; + ide_hwif_t *second_hwif; + struct dc_ident ident; + int i; + + if (!hwif) return 0; + + drive = &hwif->drives[0]; + second_hwif = &ide_hwifs[hwif->index+1]; + if(hwif->is_promise2) /* we've already been found ! */ + return 1; + + if(IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) + { + return 0; + } + OUT_BYTE(0x08,IDE_CONTROL_REG); + if(promise_cmd(drive,PROMISE_GET_CONFIG)) { + return 0; + } + if(ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) { + printk("%s: Failed Promise read config!\n",hwif->name); + return 0; + } + ide_input_data(drive,&ident,SECTOR_WORDS); + if(ident.id[1] != 'P' || ident.id[0] != 'T') { + return 0; + } + printk("%s: Promise caching controller, ",hwif->name); + switch(ident.type) { + case 0x43: printk("DC4030VL, "); break; + default: printk("unknown - type 0x%02x - please report!, " + ,ident.type); + return 0; + } + printk("%dKB cache, ",(int)ident.cache_mem); + switch(ident.irq) { + case 0x00: hwif->irq = 14; break; + case 0x01: hwif->irq = 12; break; + default: hwif->irq = 15; break; + } + printk("on IRQ %d\n",hwif->irq); + hwif->chipset = second_hwif->chipset = ide_promise; + hwif->selectproc = second_hwif->selectproc = &promise_selectproc; + second_hwif->is_promise2 = 1; + second_hwif->io_base = hwif->io_base; + second_hwif->ctl_port = hwif->ctl_port; + second_hwif->irq = hwif->irq; + for (i=0; i<2 ; i++) { + hwif->drives[i].io_32bit = 3; + second_hwif->drives[i].io_32bit = 3; + if(!ident.current_tm[i+2].cyl) second_hwif->drives[i].noprobe=1; + } + return 1; +} + +/* + * promise_read_intr() is the handler for disk read/multread interrupts + */ +static void promise_read_intr (ide_drive_t *drive) +{ + byte stat; + int i; + unsigned int sectors_left, sectors_avail, nsect; + struct request *rq; + + if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { + ide_error(drive, "promise_read_intr", stat); + return; + } + +read_again: + do { + sectors_left = IN_BYTE(IDE_NSECTOR_REG); + IN_BYTE(IDE_SECTOR_REG); + } while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left); + rq = HWGROUP(drive)->rq; + sectors_avail = rq->nr_sectors - sectors_left; + +read_next: + rq = HWGROUP(drive)->rq; + if ((nsect = rq->current_nr_sectors) > sectors_avail) + nsect = sectors_avail; + sectors_avail -= nsect; + ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); +#ifdef DEBUG + printk("%s: promise_read: sectors(%ld-%ld), buffer=0x%08lx, " + "remaining=%ld\n", drive->name, rq->sector, rq->sector+nsect-1, + (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect); +#endif + rq->sector += nsect; + rq->buffer += nsect<<9; + rq->errors = 0; + i = (rq->nr_sectors -= nsect); + if ((rq->current_nr_sectors -= nsect) <= 0) + ide_end_request(1, HWGROUP(drive)); + if (i > 0) { + if (sectors_avail) + goto read_next; + stat = GET_STAT(); + if(stat & DRQ_STAT) + goto read_again; + if(stat & BUSY_STAT) { + ide_set_handler (drive, &promise_read_intr, WAIT_CMD); + return; + } + printk("Ah! promise read intr: sectors left !DRQ !BUSY\n"); + ide_error(drive, "promise read intr", stat); + } +} + +/* + * promise_write_pollfunc() is the handler for disk write completion polling. + */ +static void promise_write_pollfunc (ide_drive_t *drive) +{ + int i; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + struct request *rq; + + if (IN_BYTE(IDE_NSECTOR_REG) != 0) { + if (jiffies < hwgroup->poll_timeout) { + ide_set_handler (drive, &promise_write_pollfunc, 1); + return; /* continue polling... */ + } + printk("%s: write timed-out!\n",drive->name); + ide_error (drive, "write timeout", GET_STAT()); + return; + } + + ide_multwrite(drive, 4); + rq = hwgroup->rq; + for (i = rq->nr_sectors; i > 0;) { + i -= rq->current_nr_sectors; + ide_end_request(1, hwgroup); + } + return; +} + +/* + * promise_write() transfers a block of one or more sectors of data to a + * drive as part of a disk write operation. All but 4 sectors are transfered + * in the first attempt, then the interface is polled (nicely!) for completion + * before the final 4 sectors are transfered. Don't ask me why, but this is + * how it's done in the drivers for other O/Ses. There is no interrupt + * generated on writes, which is why we have to do it like this. + */ +static void promise_write (ide_drive_t *drive) +{ + ide_hwgroup_t *hwgroup = HWGROUP(drive); + struct request *rq = &hwgroup->wrq; + int i; + + if (rq->nr_sectors > 4) { + ide_multwrite(drive, rq->nr_sectors - 4); + hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + ide_set_handler (drive, &promise_write_pollfunc, 1); + return; + } else { + ide_multwrite(drive, rq->nr_sectors); + rq = hwgroup->rq; + for (i = rq->nr_sectors; i > 0;) { + i -= rq->current_nr_sectors; + ide_end_request(1, hwgroup); + } + } +} + +/* + * do_promise_rw_disk() issues READ and WRITE commands to a + * disk on a promise controller, using LBA to address sectors. It also + * takes care of issuing special DRIVE_CMDs. + */ +void do_promise_io (ide_drive_t *drive, struct request *rq) +{ + unsigned long timeout; + unsigned short io_base = HWIF(drive)->io_base; + byte stat; + + if (rq->cmd == READ) { + ide_set_handler(drive, &promise_read_intr, WAIT_CMD); + OUT_BYTE(PROMISE_READ, io_base+IDE_COMMAND_OFFSET); + /* The card's behaviour is odd at this point. If the data is + available, DRQ will be true, and no interrupt will be + generated by the card. If this is the case, we need to simulate + an interrupt. Ugh! Otherwise, if an interrupt will occur, bit0 + of the SELECT register will be high, so we can just return and + be interrupted.*/ + timeout = jiffies + HZ/20; /* 50ms wait */ + do { + stat=GET_STAT(); + if(stat & DRQ_STAT) { + ide_intr(HWIF(drive)->irq,NULL,NULL); + return; + } + if(IN_BYTE(io_base+IDE_SELECT_OFFSET) & 0x01) + return; + } while (jiffies < timeout); + printk("%s: reading: No DRQ and not waiting - Odd!\n", + drive->name); + return; + } + if (rq->cmd == WRITE) { + OUT_BYTE(PROMISE_WRITE, io_base+IDE_COMMAND_OFFSET); + if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { + printk("%s: no DRQ after issuing PROMISE_WRITE\n", drive->name); + return; + } + if (!drive->unmask) + cli(); + HWGROUP(drive)->wrq = *rq; /* scratchpad */ + promise_write(drive); + return; + } + printk("%s: bad command: %d\n", drive->name, rq->cmd); + ide_end_request(0, HWGROUP(drive)); +} diff -u --recursive --new-file v1.3.74/linux/drivers/block/promise.h linux/drivers/block/promise.h --- v1.3.74/linux/drivers/block/promise.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/promise.h Sat Mar 16 13:52:15 1996 @@ -0,0 +1,52 @@ +/* + * linux/drivers/block/promise.h + * + * Copyright (C) 1995-6 Linus Torvalds & authors + */ + +/* + * Principal author: Peter Denison + */ + +#ifndef IDE_PROMISE_H +#define IDE_PROMISE_H + +#define PROMISE_EXTENDED_COMMAND 0xF0 +#define PROMISE_READ 0xF2 +#define PROMISE_WRITE 0xF3 +/* Extended commands - main command code = 0xf0 */ +#define PROMISE_GET_CONFIG 0x10 +#define PROMISE_IDENTIFY 0x20 + +struct translation_mode { + u16 cyl; + u8 head; + u8 sect; +}; + +struct dc_ident { + u8 type; + u8 unknown1; + u8 hw_revision; + u8 firmware_major; + u8 firmware_minor; + u8 bios_address; + u8 irq; + u8 unknown2; + u16 cache_mem; + u16 unknown3; + u8 id[2]; + u16 info; + struct translation_mode current_tm[4]; + u8 pad[SECTOR_WORDS*4 - 32]; +}; + +/* + * Routines exported to ide.c: + */ +void do_promise_io (ide_drive_t *, struct request *); +int promise_cmd(ide_drive_t *, byte); +void setup_dc4030 (ide_hwif_t *); +int init_dc4030 (void); + +#endif IDE_PROMISE_H diff -u --recursive --new-file v1.3.74/linux/drivers/block/rz1000.c linux/drivers/block/rz1000.c --- v1.3.74/linux/drivers/block/rz1000.c Sat Mar 2 10:43:22 1996 +++ linux/drivers/block/rz1000.c Sat Mar 16 13:52:15 1996 @@ -48,6 +48,7 @@ ide_hwifs[0].no_unmask = 1; ide_hwifs[1].no_unmask = 1; ide_hwifs[0].serialized = 1; + ide_hwifs[1].serialized = 1; ide_pci_access_error (rc); printk("serialized, disabled unmasking\n"); } else diff -u --recursive --new-file v1.3.74/linux/drivers/block/triton.c linux/drivers/block/triton.c --- v1.3.74/linux/drivers/block/triton.c Sat Mar 2 10:43:22 1996 +++ linux/drivers/block/triton.c Sat Mar 16 13:52:15 1996 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/triton.c Version 1.06 Feb 6, 1996 + * linux/drivers/block/triton.c Version 1.08 Mar 13, 1996 * * Copyright (c) 1995-1996 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -142,6 +142,7 @@ */ #define PRD_BYTES 8 #define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES)) +#define DEFAULT_BMIBA 0xe800 /* in case BIOS did not init it */ /* * dma_intr() is the handler for disk read/write DMA interrupts @@ -321,7 +322,7 @@ /* * print_triton_drive_flags() displays the currently programmed options - * in the Triton chipset for a given drive. + * in the 430FX (Triton) chipset for a given drive. * * If fastDMA is "no", then slow ISA timings are used for DMA data xfers. * If fastPIO is "no", then slow ISA timings are used for PIO data xfers. @@ -345,11 +346,11 @@ { static unsigned long dmatable = 0; - printk(" %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+7); + printk(" %s: BM-DMA at 0x%04x-0x%04x", hwif->name, base, base+7); if (check_region(base, 8)) { printk(" -- ERROR, PORTS ALREADY IN USE"); } else { - request_region(base, 8, "triton DMA"); + request_region(base, 8, "IDE DMA"); hwif->dma_base = base; if (!dmatable) { /* @@ -370,20 +371,6 @@ } /* - * calc_mode() returns the ATA PIO mode number, based on the number - * of cycle clks passed in. Assumes 33Mhz bus operation (30ns per clk). - */ -byte calc_mode (byte clks) -{ - if (clks == 3) return 5; - if (clks == 4) return 4; - if (clks < 6) return 3; - if (clks < 8) return 2; - if (clks < 13) return 1; - return 0; -} - -/* * ide_init_triton() prepares the IDE driver for DMA operation. * This routine is called once, from ide.c during driver initialization, * for each triton chipset which is found (unlikely to be more than one). @@ -395,26 +382,38 @@ unsigned short bmiba, pcicmd; unsigned int timings; - printk("ide: Triton BM-IDE on PCI bus %d function %d\n", bus, fn); + printk("ide: 430FX (Triton) on PCI bus %d function %d\n", bus, fn); /* * See if IDE and BM-DMA features are enabled: */ if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd))) goto quit; if ((pcicmd & 1) == 0) { - printk("ide: Triton IDE ports are not enabled\n"); + printk("ide: ports are not enabled (BIOS)\n"); goto quit; } if ((pcicmd & 4) == 0) { - printk("ide: Triton BM-DMA feature is not enabled -- upgrade your BIOS\n"); + printk("ide: BM-DMA feature is not enabled (BIOS)\n"); } else { /* * Get the bmiba base address */ - if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba))) - goto quit; - bmiba &= 0xfff0; /* extract port base address */ - dma_enabled = 1; + int try_again = 1; + do { + if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba))) + goto quit; + bmiba &= 0xfff0; /* extract port base address */ + if (bmiba) { + dma_enabled = 1; + } else { + printk("ide: BM-DMA base register is invalid (BIOS problem)\n"); + if (inb(DEFAULT_BMIBA) == 0xff) { + printk("ide: setting BM-DMA base register to 0x%04x\n", DEFAULT_BMIBA); + if ((rc = pcibios_write_config_word(bus, fn, 0x20, DEFAULT_BMIBA))) + goto quit; + } + } + } while (!dma_enabled && try_again--); } /* @@ -423,7 +422,7 @@ if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings))) goto quit; if (!(timings & 0x80008000)) { - printk("ide: neither Triton IDE port is enabled\n"); + printk("ide: neither port is enabled\n"); goto quit; } @@ -452,8 +451,8 @@ continue; s_clks = ((~time >> 12) & 3) + 2; r_clks = ((~time >> 8) & 3) + 1; - printk(" %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d (PIO mode%d)\n", - hwif->name, time, s_clks, r_clks, calc_mode(s_clks+r_clks)); + printk(" %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n", + hwif->name, time, s_clks, r_clks); print_triton_drive_flags (0, time & 0xf); print_triton_drive_flags (1, (time >> 4) & 0xf); } diff -u --recursive --new-file v1.3.74/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c --- v1.3.74/linux/drivers/cdrom/mcdx.c Tue Mar 5 10:10:54 1996 +++ linux/drivers/cdrom/mcdx.c Fri Mar 15 10:58:45 1996 @@ -1,7 +1,16 @@ /* * The Mitsumi CDROM interface * Copyright (C) 1995 Heiko Schlittermann - * VERSION: 1.7 + * VERSION: 1.8 + * + ****************** H E L P ********************************* + * If you ever plan to update your CD ROM drive and perhaps + * want to sell or simply give away your Mitsumi FX-001[DS] + * -- Please, Please -- + * mail me (heiko@lotte.sax.de). When my last drive goes + * ballistic no more driver support will be available from me !!! + ************************************************************* + * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,7 +44,7 @@ #if RCS static const char *mcdx_c_version - = "mcdx.c,v 1.31 1996/03/02 00:21:18 heiko Exp"; + = "$Id: mcdx.c,v 1.39 1996/03/15 00:00:59 heiko Exp $"; #endif #include @@ -582,13 +591,14 @@ CURRENT->buffer, CURRENT->sector, CURRENT->nr_sectors))) { - INFO(("do_request() read error\n")); + /*INFO(("do_request() read error\n"));*/ + xwarn("do_requst() read error\n"); if (stuffp->status & MCDX_ST_EOM) { CURRENT->sector += CURRENT->nr_sectors; CURRENT->nr_sectors = 0; } + invalidate_buffers(CURRENT->rq_dev); end_request(0); - /* return; */ goto again; } CURRENT->sector += i; @@ -820,12 +830,8 @@ stuffp = mcdx_stuffp[MINOR(full_dev)]; mcdx_getstatus(stuffp, 1); - if (stuffp->yyy == 0) { - INFO((" ... not changed\n")); - return 0; - } + if (stuffp->yyy == 0) return 0; - INFO((" ... changed\n")); stuffp->yyy = 0; return 1; } @@ -844,9 +850,9 @@ I wanna make this independend of cpu speed. [1 jiffie is 1/HZ] sec */ { unsigned long tout = jiffies + jifs; + if (jifs < 0) printk ("********\n"); /* TRACE((INIT, "mcdx_delay %d\n", jifs)); */ - if (jifs <= 0) return; if (current->pid == 0) { /* no sleep allowed */ while (jiffies < tout) { @@ -873,7 +879,7 @@ stuffp = mcdx_irq_map[irq]; if (stuffp == NULL ) { - WARN(("mcdx: no device for intr %d\n", irq)); + xwarn("mcdx: no device for intr %d\n", irq); return; } @@ -890,10 +896,10 @@ if (!stuffp->introk) { TRACE((IRQ, "intr() irq %d hw status 0x%02x\n", irq, b)); if (~b & MCDX_RBIT_STEN) { - INFO(( "intr() irq %d status 0x%02x\n", - irq, inb((unsigned int) stuffp->rreg_data))); + xinfo( "intr() irq %d status 0x%02x\n", + irq, inb((unsigned int) stuffp->rreg_data)); } else { - INFO(( "intr() irq %d ambigous hw status\n", irq)); + xinfo( "intr() irq %d ambigous hw status\n", irq); } } else { TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, b)); @@ -988,7 +994,7 @@ /* now actually get the data */ while (sz--) { - if (-1 == mcdx_getval(stuffp, timeout, -1, bp)) { + if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { INFO(("talk() %02x timed out (data), %d tr%s left\n", cmd[0], tries - 1, tries == 2 ? "y" : "ies")); st = -1; break; @@ -1095,8 +1101,13 @@ { int drive; - WARN(("Version 1.7 for %s\n", kernel_version)); - WARN(("mcdx.c,v 1.31 1996/03/02 00:21:18 heiko Exp\n")); +#ifdef MODULE + WARN(("Version 1.8 for %s\n", kernel_version)); +#else + WARN(("Version 1.8\n")); +#endif + + WARN(("$Id: mcdx.c,v 1.39 1996/03/15 00:00:59 heiko Exp $\n")); /* zero the pointer array */ for (drive = 0; drive < MCDX_NDRIVES; drive++) @@ -1677,7 +1688,7 @@ int ans; if (stuffp->present & MULTI) { - ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 1 * HZ, tries); + ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, tries); multi->multi = buf[1]; multi->msf_last.minute = buf[2]; multi->msf_last.second = buf[3]; @@ -1694,7 +1705,7 @@ { char buf[9]; int ans; - ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 1 * HZ, tries); + ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries); if (ans == -1) { info->n_first = 0; info->n_last = 0; @@ -1775,7 +1786,7 @@ int ans; if (-1 == (ans = mcdx_talk(stuffp, "\xdc", - 1, buf, sizeof(buf), 1 * HZ, tries))) + 1, buf, sizeof(buf), 2 * HZ, tries))) return ans; ver->code = buf[1]; diff -u --recursive --new-file v1.3.74/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog --- v1.3.74/linux/drivers/char/ChangeLog Sun Feb 11 15:32:44 1996 +++ linux/drivers/char/ChangeLog Sat Mar 16 20:17:23 1996 @@ -1,3 +1,8 @@ +Sat Mar 16 14:33:13 1996 + + * tty_io.c (disassociate_ctty): If disassociate_ctty is called by + exit, do not perform an implicit vhangup on a pty. + Fri Feb 9 14:15:47 1996 * serial.c (block_til_ready): Fixed another race condition which @@ -42,7 +47,7 @@ Wed Oct 11 12:45:24 1995 - * tty_io.c (disassociate_ctty): If dissassociate_ctty is called by + * tty_io.c (disassociate_ctty): If disassociate_ctty is called by exit, perform an implicit vhangup on the tty. * pty.c (pty_close): When the master pty is closed, send a hangup diff -u --recursive --new-file v1.3.74/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c --- v1.3.74/linux/drivers/char/apm_bios.c Sun Mar 10 09:49:47 1996 +++ linux/drivers/char/apm_bios.c Sat Mar 16 20:17:27 1996 @@ -1127,6 +1127,8 @@ error = apm_enable_power_management(); if (error) apm_error("enable power management", error); + if (error == APM_DISABLED) + return -1; #endif init_timer(&apm_timer); diff -u --recursive --new-file v1.3.74/linux/drivers/char/console.c linux/drivers/char/console.c --- v1.3.74/linux/drivers/char/console.c Tue Mar 5 10:10:54 1996 +++ linux/drivers/char/console.c Fri Mar 15 11:01:45 1996 @@ -123,6 +123,8 @@ static struct tty_struct *console_table[MAX_NR_CONSOLES]; static struct termios *console_termios[MAX_NR_CONSOLES]; static struct termios *console_termios_locked[MAX_NR_CONSOLES]; +unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; +struct vc vc_cons [MAX_NR_CONSOLES]; static void con_setsize(unsigned long rows, unsigned long cols); static void vc_init(unsigned int console, unsigned long rows, @@ -153,31 +155,26 @@ extern int set_get_font(unsigned char *, int, int); /* Description of the hardware situation */ -/* used in vga.c/tga.c/etc.c... :-) */ - unsigned char video_type; /* Type of display being used */ - unsigned long video_mem_base; /* Base of video memory */ - unsigned long video_mem_term; /* End of video memory */ -static unsigned char video_page; /* Initial video page (unused) */ - /* these two also used in vesa_blank.c */ - unsigned short video_port_reg; /* Video register select port */ - unsigned short video_port_val; /* Video register value port */ - /* these three also used in selection.c */ - unsigned long video_num_columns; /* Number of text columns */ - unsigned long video_num_lines; /* Number of text lines */ - unsigned long video_size_row; - unsigned long video_screen_size; - int can_do_color = 0; -static int printable = 0; /* Is console ready for printing? */ - /* these also used in in vt.c */ - int video_mode_512ch = 0; /* 512-character mode */ - unsigned long video_font_height; /* Height of current screen font */ - unsigned long video_scan_lines; /* Number of scan lines on screen */ - unsigned long default_font_height; /* Height of default screen font */ - int video_font_is_default = 1; +unsigned char video_type; /* Type of display being used */ +unsigned long video_mem_base; /* Base of video memory */ +unsigned long video_mem_term; /* End of video memory */ +unsigned short video_port_reg; /* Video register select port */ +unsigned short video_port_val; /* Video register value port */ +unsigned long video_num_columns; /* Number of text columns */ +unsigned long video_num_lines; /* Number of text lines */ +unsigned long video_size_row; +unsigned long video_screen_size; + +int can_do_color = 0; +static int printable = 0; /* Is console ready for printing? */ + +int video_mode_512ch = 0; /* 512-character mode */ +unsigned long video_font_height; /* Height of current screen font */ +unsigned long video_scan_lines; /* Number of scan lines on screen */ +unsigned long default_font_height; /* Height of default screen font */ +int video_font_is_default = 1; static unsigned short console_charmask = 0x0ff; - unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; - /* used by kbd_bh - set by keyboard_interrupt */ int do_poke_blanked_console = 0; int console_blanked = 0; @@ -185,8 +182,6 @@ static int vesa_off_interval = 0; static long blank_origin, blank__origin, unblank_origin; -struct vc vc_cons [MAX_NR_CONSOLES]; - #ifdef CONFIG_SERIAL_ECHO @@ -515,63 +510,68 @@ /* * Hardware scrollback support */ -unsigned short __real_origin; -unsigned short __origin; /* offset of currently displayed screen */ -#define last_lpos (((video_mem_term-video_mem_base)/video_num_columns/2)-video_num_lines+1) -#define last_origin_rel ( last_lpos * video_num_columns ) -#define last_origin ( video_mem_base + last_origin_rel * 2 ) -unsigned short __scrollback_mode; /* 1 means scrollback can wrap */ extern void __set_origin(unsigned short); - -void scrollback(int lines) -{ - if (!lines) - lines = video_num_lines/2; - lines *= video_num_columns; - lines = __origin - lines; - if (__scrollback_mode == 0) { - if (lines < 0) - lines = 0; - } else { - int s_top = __real_origin+video_num_lines*video_num_columns ; - if (lines < 0) { - int count ; +unsigned short __real_origin; /* offset of non-scrolled screen */ +unsigned short __origin; /* offset of currently displayed screen */ +unsigned char has_wrapped; /* all of videomem is data of fg_console */ +static unsigned char hardscroll_enabled; +static unsigned char hardscroll_disabled_by_init = 0; + +void no_scroll(char *str, int *ints) +{ + /* + * Disabling scrollback is required for the Braillex ib80-piezo + * Braille reader made by F.H. Papenmeier (Germany). + * Use the "no-scroll" bootflag. + */ + hardscroll_disabled_by_init = 1; + hardscroll_enabled = 0; +} + +static void scrolldelta(int lines) +{ + int new_origin; + int last_origin_rel = (((video_mem_term - video_mem_base) + / video_num_columns / 2) - (video_num_lines - 1)) * video_num_columns; + + new_origin = __origin + lines * video_num_columns; + if (__origin > __real_origin) + new_origin -= last_origin_rel; + if (new_origin < 0) { + int s_top = __real_origin + video_num_lines*video_num_columns; + new_origin += last_origin_rel; + if (new_origin < s_top) + new_origin = s_top; + if (new_origin > last_origin_rel - video_num_columns + || has_wrapped == 0) + new_origin = 0; + else { unsigned short * d = (unsigned short *) video_mem_base; - unsigned short * s = (unsigned short *) last_origin; - - lines += last_origin_rel; - /* in case the top part of the screen has been modified since - * the scroll wrapped, copy the top bit back to the bottom */ - count = (video_num_lines-1)*video_num_columns; + unsigned short * s = d + last_origin_rel; + int count = (video_num_lines-1)*video_num_columns; while (count) { count--; scr_writew(scr_readw(d++),s++); } - } else if (__origin > __real_origin && lines < s_top) - lines = s_top ; - } - __set_origin(lines); + } + } else if (new_origin > __real_origin) + new_origin = __real_origin; + + __set_origin(new_origin); +} + +void scrollback(int lines) +{ + if (!lines) + lines = video_num_lines/2; + scrolldelta(-lines); } void scrollfront(int lines) { if (!lines) lines = video_num_lines/2; - lines *= video_num_columns; - if (__origin > __real_origin) { - /* assume __scrollback_mode == 1 */ - lines += __origin; - if (lines >= last_origin_rel) { - lines -= last_origin_rel ; - if (lines > __real_origin) - lines = __real_origin; - } - } else { - lines += __origin; - if (lines > __real_origin) - lines = __real_origin; - } - __set_origin(lines); + scrolldelta(lines); } static void set_origin(int currcons) @@ -587,20 +587,17 @@ void scrup(int currcons, unsigned int t, unsigned int b) { - int hardscroll = 1; + int hardscroll = hardscroll_enabled; if (b > video_num_lines || t >= b) return; - if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_VGAC - && video_type != VIDEO_TYPE_EGAM) - hardscroll = 0; - else if (t || b != video_num_lines) + if (t || b != video_num_lines) hardscroll = 0; if (hardscroll) { origin += video_size_row; pos += video_size_row; scr_end += video_size_row; - if (origin >= last_origin) { + if (scr_end > video_mem_end) { unsigned short * d = (unsigned short *) video_mem_start; unsigned short * s = (unsigned short *) origin; unsigned int count; @@ -620,7 +617,7 @@ origin = video_mem_start; has_scrolled = 1; if (currcons == fg_console) - __scrollback_mode = 1; + has_wrapped = 1; } else { unsigned short * d; unsigned int count; @@ -631,8 +628,6 @@ count--; scr_writew(video_erase_char, d++); } - if (scr_end > last_origin) /* we've wrapped into kept region */ - __scrollback_mode = 0; } set_origin(currcons); } else { @@ -2021,8 +2016,6 @@ panic("Couldn't register console driver\n"); con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS); - video_page = ORIG_VIDEO_PAGE; /* never used */ - __scrollback_mode = 0 ; timer_table[BLANK_TIMER].fn = blank_screen; timer_table[BLANK_TIMER].expires = 0; @@ -2033,7 +2026,11 @@ kmem_start = con_type_init(kmem_start, &display_desc); - /* Initialize the variables used for scrolling (mostly EGA/VGA) */ + hardscroll_enabled = (hardscroll_disabled_by_init ? 0 : + (video_type == VIDEO_TYPE_EGAC + || video_type == VIDEO_TYPE_VGAC + || video_type == VIDEO_TYPE_EGAM)); + has_wrapped = 0 ; /* Due to kmalloc roundup allocating statically is more efficient - so provide MIN_NR_CONSOLES for people with very little memory */ diff -u --recursive --new-file v1.3.74/linux/drivers/char/ftape/RELEASE-NOTES linux/drivers/char/ftape/RELEASE-NOTES --- v1.3.74/linux/drivers/char/ftape/RELEASE-NOTES Fri Mar 15 16:03:11 1996 +++ linux/drivers/char/ftape/RELEASE-NOTES Fri Mar 15 11:59:15 1996 @@ -1,3 +1,12 @@ +===== Release notes for ftape-2.08, 14/03/96 ===== + +If you correct a problem with ftape, please send your patch to +khp@pip.dknet.dk too. + +- Updated to reflect that NR_MEM_LISTS is gone in 1.3.74 +- Teac 700 added to list of known drives. +- The registered device name is now "ft" rather than "ftape". + ===== Release notes for ftape-2.07a, 14/03/96 ===== Bugfixes by Marcin Dalecki : diff -u --recursive --new-file v1.3.74/linux/drivers/char/ftape/kernel-interface.c linux/drivers/char/ftape/kernel-interface.c --- v1.3.74/linux/drivers/char/ftape/kernel-interface.c Fri Mar 15 16:03:14 1996 +++ linux/drivers/char/ftape/kernel-interface.c Fri Mar 15 12:03:33 1996 @@ -50,8 +50,7 @@ * NR_BUFFERS chunks of 32Kbyte. --khp */ -byte *tape_buffer[NR_BUFFERS] = -{NULL}; +byte *tape_buffer[NR_BUFFERS] = {NULL}; /* Local vars. */ @@ -66,25 +65,16 @@ int req_len); static int ftape_write(struct inode *ino, struct file *fp, const char *buff, int req_len); -static int ftape_lseek(struct inode *ino, struct file *filep, - off_t offset, int origin); -#if 0 -static int ftape_select(void); -static int ftape_mmap(int dev, unsigned off, int prot); -#else -#define ftape_select NULL -#define ftape_mmap NULL -#endif static struct file_operations ftape_cdev = { - ftape_lseek, /* lseek */ + NULL, /* lseek */ ftape_read, /* read */ ftape_write, /* write */ NULL, /* readdir */ - ftape_select, /* select */ + NULL, /* select */ ftape_ioctl, /* ioctl */ - ftape_mmap, /* mmap */ + NULL, /* mmap */ ftape_open, /* open */ ftape_close, /* release */ NULL, /* fsync */ @@ -94,15 +84,18 @@ * DMA'able memory allocation stuff. */ -static inline -int __get_order(int size) +/* Pure 2^n version of get_order */ +static inline int __get_order(unsigned long size) { int order; - for (order = 0; order < NR_MEM_LISTS; ++order) - if (size <= (PAGE_SIZE << order)) - return order; - return -1; + size >>= (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; } static inline @@ -130,9 +123,9 @@ { int n; int order; - TRACE_FUN(5, "init_module"); + TRACE_FUN(5, "ftape_init"); #ifdef MODULE - printk(KERN_INFO "ftape-2.07 960304\n" + printk(KERN_INFO "ftape-2.08 960314\n" KERN_INFO " (c) 1993-1995 Bas Laarhoven (bas@vimec.nl)\n" KERN_INFO " (c) 1995-1996 Kai Harrekilde-Petersen (khp@pip.dknet.dk)\n" KERN_INFO " QIC-117 driver for QIC-40/80/3010/3020 tape drives\n" @@ -141,28 +134,21 @@ " with versioned symbols" #endif "\n", kernel_version); -#else /* !MODULE */ +#else /* !MODULE */ /* print a short no-nonsense boot message */ - printk("ftape-2.07 960304 for Linux 1.3.70\n"); + printk("ftape-2.08 960314 for Linux 1.3.70\n"); #endif /* MODULE */ TRACE(3, "installing QIC-117 ftape driver..."); - if (register_chrdev(QIC117_TAPE_MAJOR, "ftape", &ftape_cdev)) { + if (register_chrdev(QIC117_TAPE_MAJOR, "ft", &ftape_cdev)) { TRACE(1, "register_chrdev failed"); TRACE_EXIT; return -EIO; } - TRACEx1(3, "init_module @ 0x%p", init_module); + TRACEx1(3, "ftape_init @ 0x%p", ftape_init); /* * Allocate the DMA buffers. They are deallocated at cleanup() time. */ order = __get_order(BUFF_SIZE); - if (order < 0) { - TRACE(1, "__get_order failed (no memory?)"); - if (unregister_chrdev(QIC117_TAPE_MAJOR, "ftape") != 0) { - TRACE(3, "unregister_chrdev failed"); - } - return -ENOMEM; - } for (n = 0; n < NR_BUFFERS; n++) { tape_buffer[n] = (byte *) dmaalloc(order); if (!tape_buffer[n]) { @@ -174,7 +160,7 @@ } } current->blocked = old_sigmask; /* restore mask */ - if (unregister_chrdev(QIC117_TAPE_MAJOR, "ftape") != 0) { + if (unregister_chrdev(QIC117_TAPE_MAJOR, "ft") != 0) { TRACE(3, "unregister_chrdev failed"); } TRACE_EXIT; @@ -205,23 +191,19 @@ int order; TRACE_FUN(5, "cleanup_module"); - if (unregister_chrdev(QIC117_TAPE_MAJOR, "ftape") != 0) { + if (unregister_chrdev(QIC117_TAPE_MAJOR, "ft") != 0) { TRACE(3, "failed"); } else { TRACE(3, "successful"); } order = __get_order(BUFF_SIZE); - if (order < 0) { - TRACE(1, "__get_order failed (but why?!)"); - } else { - for (n = 0; n < NR_BUFFERS; n++) { - if (tape_buffer[n]) { - dmafree(tape_buffer[n], order); - tape_buffer[n] = NULL; - TRACEx1(3, "removed dma-buffer #%d", n); - } else { - TRACEx1(1, "dma-buffer #%d == NULL (bug?)", n); - } + for (n = 0; n < NR_BUFFERS; n++) { + if (tape_buffer[n]) { + dmafree(tape_buffer[n], order); + tape_buffer[n] = NULL; + TRACEx1(3, "removed dma-buffer #%d", n); + } else { + TRACEx1(1, "dma-buffer #%d == NULL (bug?)", n); } } TRACE_EXIT; @@ -370,11 +352,4 @@ current->blocked = old_sigmask; /* restore mask */ TRACE_EXIT; return result; -} - -/* Seek tape device - not implemented ! - */ -static int ftape_lseek(struct inode *ino, struct file *filep, off_t offset, int origin) -{ - return -ESPIPE; } diff -u --recursive --new-file v1.3.74/linux/drivers/char/ftape/vendors.h linux/drivers/char/ftape/vendors.h --- v1.3.74/linux/drivers/char/ftape/vendors.h Sun Mar 10 09:49:48 1996 +++ linux/drivers/char/ftape/vendors.h Fri Mar 15 12:04:09 1996 @@ -88,7 +88,7 @@ { 0x001c8, 64, no_wake_up, "Wangtek 3080F" }, \ { 0x001c8, 64, wake_up_colorado, "Wangtek 3080F" }, \ { 0x001ca, 67, no_wake_up, "Wangtek 3080F (new)" }, \ - { 0x001cc, 77, wake_up_colorado, "Wangtek 3200" }, \ + { 0x001cc, 77, wake_up_colorado, "Wangtek 3200 / Teac 700" }, \ { 0x001cd, 75, wake_up_colorado, "Reveal TB1400" }, \ { 0x00380, 0, wake_up_colorado, "Exabyte EXB-1500" }, \ { 0x08880, 64, no_wake_up, "Iomega 250" }, \ diff -u --recursive --new-file v1.3.74/linux/drivers/char/selection.h linux/drivers/char/selection.h --- v1.3.74/linux/drivers/char/selection.h Tue Mar 5 10:10:55 1996 +++ linux/drivers/char/selection.h Sat Mar 16 15:01:54 1996 @@ -37,7 +37,7 @@ extern unsigned short __real_origin; extern unsigned short __origin; -extern unsigned short __scrollback_mode; +extern unsigned char has_wrapped; extern unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; diff -u --recursive --new-file v1.3.74/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v1.3.74/linux/drivers/char/tty_io.c Wed Feb 28 11:50:01 1996 +++ linux/drivers/char/tty_io.c Sat Mar 16 20:17:23 1996 @@ -477,7 +477,7 @@ struct task_struct *p; if (tty) { - if (on_exit) + if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); } else { if (current->tty_old_pgrp) { diff -u --recursive --new-file v1.3.74/linux/drivers/char/vesa_blank.c linux/drivers/char/vesa_blank.c --- v1.3.74/linux/drivers/char/vesa_blank.c Fri Feb 9 17:53:01 1996 +++ linux/drivers/char/vesa_blank.c Fri Mar 15 11:01:45 1996 @@ -26,9 +26,7 @@ | fd = 0; | arg.ten = 10; | arg.onoff = 0; -| if (!strcmp(argv[1], "on")) -| arg.onoff = 1; -| else if (!strcmp(argv[1], "vsync")) +| if (!strcmp(argv[1], "on") || !strcmp(argv[1], "vsync")) | arg.onoff = 1; | else if (!strcmp(argv[1], "hsync")) | arg.onoff = 2; diff -u --recursive --new-file v1.3.74/linux/drivers/char/vga.c linux/drivers/char/vga.c --- v1.3.74/linux/drivers/char/vga.c Tue Nov 21 13:22:10 1995 +++ linux/drivers/char/vga.c Fri Mar 15 11:01:46 1996 @@ -26,7 +26,7 @@ * Improved loadable font/UTF-8 support by H. Peter Anvin * Feb-Sep 1995 * - * improved scrollback, plus colour palette handling, by Simon Tatham + * Colour palette handling, by Simon Tatham * 17-Jun-95 * */ @@ -190,8 +190,11 @@ outb_p (6, 0x3cf) ; #endif - /* normalise the palette registers, to point the - * 16 screen colours to the first 16 DAC entries */ + /* + * Normalise the palette registers, to point + * the 16 screen colours to the first 16 + * DAC entries. + */ for (i=0; i<16; i++) { inb_p (0x3da) ; @@ -200,8 +203,8 @@ } outb_p (0x20, 0x3c0) ; - /* now set the DAC registers back to their default - * values */ + /* now set the DAC registers back to their + * default values */ for (i=0; i<16; i++) { outb_p (color_table[i], 0x3c8) ; @@ -227,7 +230,6 @@ { memcpyw((unsigned short *)vc_scrbuf[currcons], (unsigned short *)origin, video_screen_size); - __scrollback_mode = 0 ; origin = video_mem_start = (unsigned long)vc_scrbuf[currcons]; scr_end = video_mem_end = video_mem_start + video_screen_size; pos = origin + y*video_size_row + (x<<1); @@ -276,6 +278,7 @@ origin = video_mem_base + offset; scr_end = origin + video_screen_size; pos = origin + y*video_size_row + (x<<1); + has_wrapped = 0; } /* diff -u --recursive --new-file v1.3.74/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v1.3.74/linux/drivers/net/3c503.c Wed Mar 13 10:09:16 1996 +++ linux/drivers/net/3c503.c Sat Mar 16 13:52:12 1996 @@ -436,7 +436,7 @@ { unsigned short int *wrd; int boguscount; /* timeout counter */ - unsigned short tmp_rev; /* temporary for reversed values */ + unsigned short word; /* temporary for better machine code */ if (ei_status.word16) /* Tx packets go into bank 0 on EL2/16 card */ outb(EGACFR_RSEL|EGACFR_TCM, E33G_GACFR); @@ -456,9 +456,9 @@ * Set up then start the internal memory transfer to Tx Start Page */ - tmp_rev = (unsigned short)start_page; - outb(tmp_rev&0xFF, E33G_DMAAL); - outb(tmp_rev>>8, E33G_DMAAH); + word = (unsigned short)start_page; + outb(word&0xFF, E33G_DMAAH); + outb(word>>8, E33G_DMAAL); outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT | ECNTRL_START, E33G_CNTRL); @@ -508,7 +508,7 @@ { int boguscount; unsigned long hdr_start = dev->mem_start + ((ring_page - EL2_MB1_START_PG)<<8); - unsigned short tmp_rev; + unsigned short word; if (dev->mem_start) { /* Use the shared memory. */ memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); @@ -519,9 +519,9 @@ * No shared memory, use programmed I/O. */ - tmp_rev = (unsigned short)ring_page; - outb(tmp_rev&0xFF, E33G_DMAAL); - outb(tmp_rev>>8, E33G_DMAAH); + word = (unsigned short)ring_page; + outb(word&0xFF, E33G_DMAAH); + outb(word>>8, E33G_DMAAL); outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT | ECNTRL_START, E33G_CNTRL); @@ -547,7 +547,7 @@ { int boguscount = 0; unsigned short int *buf; - unsigned short tmp_rev; + unsigned short word; int end_of_ring = dev->rmem_end; @@ -570,9 +570,9 @@ /* * No shared memory, use programmed I/O. */ - tmp_rev = (unsigned short) ring_offset; - outb(tmp_rev&0xFF, E33G_DMAAL); - outb(tmp_rev>>8, E33G_DMAAH); + word = (unsigned short) ring_offset; + outb(word>>8, E33G_DMAAH); + outb(word&0xFF, E33G_DMAAL); outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT | ECNTRL_START, E33G_CNTRL); diff -u --recursive --new-file v1.3.74/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v1.3.74/linux/drivers/net/3c509.c Wed Mar 13 10:09:16 1996 +++ linux/drivers/net/3c509.c Sat Mar 16 14:33:15 1996 @@ -22,6 +22,10 @@ packet latency but lower overhead. If interrupts are disabled for an unusually long time it could also result in missed packets, but in practice this rarely happens. + + + FIXES: + Alan Cox: Removed the 'Unexpected interrupt' bug. */ static const char *version = "3c509.c:1.03 10/8/94 becker@cesdis.gsfc.nasa.gov\n"; @@ -321,9 +325,8 @@ outw(RxReset, ioaddr + EL3_CMD); outw(SetReadZero | 0x00, ioaddr + EL3_CMD); - if (request_irq(dev->irq, &el3_interrupt, 0, "3c509", NULL)) { + if (request_irq(dev->irq, &el3_interrupt, 0, "3c509", dev)) return -EAGAIN; - } EL3WINDOW(0); if (el3_debug > 3) @@ -333,7 +336,6 @@ /* Activate board: this is probably unnecessary. */ outw(0x0001, ioaddr + 4); - irq2dev_map[dev->irq] = dev; /* Set the IRQ line. */ outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ); @@ -478,7 +480,7 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct device *dev = (struct device *)(irq2dev_map[irq]); + struct device *dev = (struct device *)dev_id; int ioaddr, status; int i = 0; @@ -687,14 +689,11 @@ outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); } - free_irq(dev->irq, NULL); + free_irq(dev->irq, dev); /* Switching back to window 0 disables the IRQ. */ EL3WINDOW(0); /* But we explicitly zero the IRQ line select anyway. */ outw(0x0f00, ioaddr + WN0_IRQ); - - - irq2dev_map[dev->irq] = 0; update_stats(ioaddr, dev); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v1.3.74/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.3.74/linux/drivers/net/Makefile Fri Mar 15 16:03:14 1996 +++ linux/drivers/net/Makefile Sat Mar 16 13:52:10 1996 @@ -383,7 +383,6 @@ ifeq ($(CONFIG_PI),y) L_OBJS += pi2.o -CONFIG_PI = CONFIG_PI endif ifeq ($(CONFIG_PT),y) diff -u --recursive --new-file v1.3.74/linux/drivers/sound/configure.c linux/drivers/sound/configure.c --- v1.3.74/linux/drivers/sound/configure.c Fri Mar 15 16:03:17 1996 +++ linux/drivers/sound/configure.c Sat Mar 16 13:52:16 1996 @@ -3,7 +3,7 @@ * * AEDSP16 will not work without significant changes. */ -#define DISABLED_OPTIONS (B(OPT_PNP)|B(OPT_AEDSP16)|B(OPT_UNUSED1)|B(OPT_UNUSED2)) +#define DISABLED_OPTIONS (B(OPT_SPNP)|B(OPT_AEDSP16)|B(OPT_UNUSED1)|B(OPT_UNUSED2)) /* * sound/configure.c - Configuration program for the Linux Sound Driver */ @@ -38,7 +38,7 @@ #define OPT_MAD16 12 #define OPT_CS4232 13 #define OPT_MAUI 14 -#define OPT_PNP 15 +#define OPT_SPNP 15 #define OPT_HIGHLEVEL 16 /* This must be same than the next one */ #define OPT_UNUSED1 16 @@ -64,10 +64,10 @@ B (OPT_GUS) | B (OPT_TRIX) | B (OPT_SSCAPE)|B(OPT_MAD16) | \ B (OPT_CS4232)|B(OPT_MAUI)) #define MPU_DEVS (B(OPT_PSS)|B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|\ - B(OPT_CS4232)|B(OPT_PNP)|B(OPT_MAUI)) + B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI)) #define AD1848_DEVS (B(OPT_GUS16)|B(OPT_MSS)|B(OPT_PSS)|B(OPT_GUSMAX)|\ B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_CS4232)|\ - B(OPT_PNP)) + B(OPT_SPNP)) #define SEQUENCER_DEVS (OPT_MIDI|OPT_YM3812|OPT_ADLIB|OPT_GUS|OPT_MAUI|MIDI_CARDS) /* * Options that have been disabled for some reason (incompletely implemented @@ -123,7 +123,7 @@ {0, 0, "MAD16", 1, 0, 0}, {0, 0, "CS4232", 1, 0, 0}, {0, 0, "MAUI", 1, 0, 0}, - {0, 0, "PNP", 1, 0, 0}, + {0, 0, "SPNP", 1, 0, 0}, {B (OPT_SB), B (OPT_PAS), "UNUSED1", 1, 0, 1}, {B (OPT_SB) | B (OPT_UNUSED1), B (OPT_PAS), "UNUSED2", 1, 0, 1}, @@ -418,6 +418,7 @@ { for (i = 0; i < OPT_LAST; i++) + if (!(DISABLED_OPTIONS & B (i))) if (mask == B (i)) { unsigned int j; diff -u --recursive --new-file v1.3.74/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v1.3.74/linux/drivers/sound/dev_table.h Fri Mar 15 16:03:17 1996 +++ linux/drivers/sound/dev_table.h Sat Mar 16 13:52:16 1996 @@ -345,7 +345,7 @@ {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTriX MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, #endif -#ifdef CONFIG_PNP +#ifdef CONFIG_SPNP {"AD1848", 0, 500, "SoundPort", attach_pnp_ad1848, probe_pnp_ad1848, unload_pnp_ad1848}, #endif {NULL, 0, 0, "*?*", NULL, NULL, NULL} diff -u --recursive --new-file v1.3.74/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c --- v1.3.74/linux/drivers/sound/sb_dsp.c Fri Mar 15 16:03:18 1996 +++ linux/drivers/sound/sb_dsp.c Sat Mar 16 13:52:35 1996 @@ -827,9 +827,6 @@ return -ENXIO; } - if (!sb_midi_busy) - sb_reset_dsp (); - if (sb_no_recording && mode & OPEN_READ) { printk ("SB Warning: Recording not supported by this device\n"); @@ -837,9 +834,12 @@ if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI)) { - printk ("SB: PCM not possible during MIDI input\n"); + printk ("SB: Audio device or MIDI already in use\n"); return -EBUSY; } + + if (!sb_midi_busy) + sb_reset_dsp (); if (!irq_verified) { diff -u --recursive --new-file v1.3.74/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- v1.3.74/linux/fs/binfmt_aout.c Wed Mar 13 10:09:18 1996 +++ linux/fs/binfmt_aout.c Fri Mar 15 15:22:59 1996 @@ -202,7 +202,7 @@ * memory and creates the pointer tables from them, and puts their * addresses on the "stack", returning the new stack pointer value. */ -static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm, int ibcs) +static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm) { unsigned long *argv,*envp; unsigned long * sp; @@ -228,10 +228,8 @@ sp -= argc+1; argv = sp; #ifdef __i386__ - if (!ibcs) { - put_user(envp,--sp); - put_user(argv,--sp); - } + put_user(envp,--sp); + put_user(argv,--sp); #endif put_user(argc,--sp); current->mm->arg_start = (unsigned long) p; @@ -385,8 +383,7 @@ p = setup_arg_pages(p, bprm); - p = (unsigned long) create_aout_tables((char *)p, bprm, - current->personality != PER_LINUX); + p = (unsigned long) create_aout_tables((char *)p, bprm); current->mm->start_stack = p; #ifdef __alpha__ regs->gp = ex.a_gpvalue; diff -u --recursive --new-file v1.3.74/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v1.3.74/linux/fs/nfs/nfsroot.c Sat Feb 17 16:02:53 1996 +++ linux/fs/nfs/nfsroot.c Sat Mar 16 13:52:10 1996 @@ -1,31 +1,55 @@ /* - * linux/fs/nfs/nfsroot.c + * linux/fs/nfs/nfsroot.c -- version 2.0 * * Copyright (C) 1995 Gero Kuhlmann + * Copyright (C) 1996 Martin Mares + * + * Allow an NFS filesystem to be mounted as root. The way this works is: + * (1) Determine the local IP address via RARP or BOOTP or from the + * kernel command line. + * (2) Handle RPC negotiation with the system which replied to RARP or + * was reported as a boot server by BOOTP or manually. + * (3) The actual mounting is done later, when init() is running. * - * Allow an NFS filesystem to be mounted as root. The way this works - * is to first determine the local IP address via RARP. Then handle - * the RPC negotiation with the system which replied to the RARP. The - * actual mounting is done later, when init() is running. In addition - * it's possible to avoid using RARP if the necessary addresses are - * provided on the kernel command line. This is necessary to use boot- - * roms which use bootp instead of RARP. * * Changes: * * Alan Cox : Removed get_address name clash with FPU. * Alan Cox : Reformatted a bit. * Michael Rausch : Fixed recognition of an incoming RARP answer. + * Martin Mares : (2.0) Auto-configuration via BOOTP supported. + * Martin Mares : Manual selection of interface & BOOTP/RARP. + * Martin Mares : Using network routes instead of host routes, + * allowing the default configuration to be used + * for normal operation of the host. + * Martin Mares : Randomized timer with exponential backoff + * installed to minimize network congestion. + * Martin Mares : Code cleanup. + * + * + * Known bugs and caveats: + * + * - BOOTP code doesn't handle multiple network interfaces properly. + * For now, it uses the first one, trying to prefer ethernet-like + * devices. Not critical as diskless stations are usually single-homed. * */ /* Define this to allow debugging output */ -#undef NFSROOT_DEBUG 1 +#undef NFSROOT_DEBUG +#undef NFSROOT_MORE_DEBUG -/* Define the timeout for waiting for a RARP reply */ -#define RARP_TIMEOUT 30 /* 30 seconds */ -#define RARP_RETRIES 5 /* 5 retries */ +/* Choose default protocol(s) */ +#define CONFIG_USE_BOOTP +#define CONFIG_USE_RARP + +/* Define the timeout for waiting for a RARP/BOOTP reply */ +#define CONF_BASE_TIMEOUT (HZ*5) /* Initial timeout: 5 seconds */ +#define CONF_RETRIES 10 /* 10 retries */ +#define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */ +#define CONF_TIMEOUT_MULT *5/4 /* Speed of timeout growth */ +#define CONF_TIMEOUT_MAX (HZ*30) /* Maximum allowed timeout */ #include #include @@ -53,6 +77,9 @@ #include #include #include +#include +#include +#include /* Range of privileged ports */ @@ -61,7 +88,7 @@ #define NPORTS (ENDPORT - STARTPORT + 1) - +/* List of open devices */ struct open_dev { struct device *dev; unsigned short old_flags; @@ -69,15 +96,35 @@ }; static struct open_dev *open_base = NULL; -static struct device *root_dev = NULL; + +/* IP configuration */ +static struct device *root_dev = NULL; /* Device selected for booting */ +static char user_dev_name[IFNAMSIZ]; /* Name of user-selected boot device */ static struct sockaddr_in myaddr; /* My IP address */ static struct sockaddr_in server; /* Server IP address */ static struct sockaddr_in gateway; /* Gateway IP address */ static struct sockaddr_in netmask; /* Netmask for local subnet */ + +/* BOOTP/RARP variables */ +static int bootp_flag; /* User said: Use BOOTP! */ +static int rarp_flag; /* User said: Use RARP! */ +static int bootp_dev_count = 0; /* Number of devices allowing BOOTP */ +static int rarp_dev_count = 0; /* Number of devices allowing RARP */ +volatile static int pkt_arrived; /* BOOTP/RARP packet detected */ + +#define ARRIVED_BOOTP 1 +#define ARRIVED_RARP 2 + +/* NFS-related data */ static struct nfs_mount_data nfs_data; /* NFS mount info */ static char nfs_path[NFS_MAXPATHLEN]; /* Name of directory to mount */ static int nfs_port; /* Port to connect to for NFS service */ +/* Macro for formatting of addresses in debug dumps */ +#define IN_NTOA(x) (((x) == INADDR_NONE) ? "none" : in_ntoa(x)) + +/* Yes, we use sys_socket, but there's no include file for it */ +extern asmlinkage int sys_socket(int family, int type, int protocol); /*************************************************************************** @@ -87,19 +134,21 @@ ***************************************************************************/ /* - * Setup and initialize all network devices + * Setup and initialize all network devices. If there is a user-prefered + * interface, ignore all other interfaces. */ static int root_dev_open(void) { - struct open_dev *openp; + struct open_dev *openp, **last; struct device *dev; unsigned short old_flags; - int num = 0; + last = &open_base; for (dev = dev_base; dev != NULL; dev = dev->next) { if (dev->type < ARPHRD_SLIP && dev->family == AF_INET && - !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) { + !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) && + (!user_dev_name[0] || !strcmp(dev->name, user_dev_name))) { /* First up the interface */ old_flags = dev->flags; dev->flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; @@ -113,19 +162,22 @@ continue; openp->dev = dev; openp->old_flags = old_flags; - openp->next = open_base; - open_base = openp; - num++; + *last = openp; + last = &openp->next; + bootp_dev_count++; + if (!(dev->flags & IFF_NOARP)) + rarp_dev_count++; +#ifdef NFSROOT_DEBUG + printk(KERN_NOTICE "Root-NFS: Opened %s\n", dev->name); +#endif } } + *last = NULL; - if (num == 0) { - printk(KERN_ERR "NFS: Unable to open at least one network device\n"); + if (!bootp_dev_count && !rarp_dev_count) { + printk(KERN_ERR "Root-NFS: Unable to open at least one network device\n"); return -1; } -#ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Opened %d network interfaces\n", num); -#endif return 0; } @@ -154,11 +206,9 @@ } - - /*************************************************************************** - RARP Subroutines + RARP Subroutines ***************************************************************************/ @@ -259,13 +309,14 @@ * variables. */ cli(); - if (root_dev != NULL) { + if (pkt_arrived) { sti(); kfree_skb(skb, FREE_READ); return 0; } - root_dev = dev; + pkt_arrived = ARRIVED_RARP; sti(); + root_dev = dev; if (myaddr.sin_addr.s_addr == INADDR_NONE) { myaddr.sin_family = dev->family; @@ -283,14 +334,12 @@ /* * Send RARP request packet over all devices which allow RARP. */ -static int root_rarp_send(void) +static void root_rarp_send(void) { struct open_dev *openp; struct device *dev; int num = 0; - /* always print this message so user knows what's going on... */ - printk(KERN_NOTICE "NFS: Sending RARP request...\n"); for (openp = open_base; openp != NULL; openp = openp->next) { dev = openp->dev; if (!(dev->flags & IFF_NOARP)) { @@ -299,67 +348,600 @@ num++; } } +} + + +/*************************************************************************** + + BOOTP Subroutines + + ***************************************************************************/ + +static struct device *bootp_dev = NULL; /* Device selected as best BOOTP target */ + +static int bootp_xmit_fd = -1; /* Socket descriptor for transmit */ +static struct socket *bootp_xmit_sock; /* The socket itself */ +static int bootp_recv_fd = -1; /* Socket descriptor for receive */ +static struct socket *bootp_recv_sock; /* The socket itself */ + +struct bootp_pkt { /* BOOTP packet format */ + u8 op; /* 1=request, 2=reply */ + u8 htype; /* HW address type */ + u8 hlen; /* HW address length */ + u8 hops; /* Used only by gateways */ + u32 xid; /* Transaction ID */ + u16 secs; /* Seconds since we started */ + u16 flags; /* Just what is says */ + u32 client_ip; /* Client's IP address if known */ + u32 your_ip; /* Assigned IP address */ + u32 server_ip; /* Server's IP address */ + u32 relay_ip; /* IP address of BOOTP relay */ + u8 hw_addr[16]; /* Client's HW address */ + u8 serv_name[64]; /* Server host name */ + u8 boot_file[128]; /* Name of boot file */ + u8 vendor_area[128]; /* Area for extensions */ +}; + +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +static struct bootp_pkt *xmit_bootp; /* Packet being transmitted */ +static struct bootp_pkt *recv_bootp; /* Packet being received */ + +static int bootp_have_route = 0; /* BOOTP route installed */ + +/* + * Free BOOTP packet buffers + */ +static void root_free_bootp(void) +{ + if (xmit_bootp) { + kfree_s(xmit_bootp, sizeof(struct bootp_pkt)); + xmit_bootp = NULL; + } + if (recv_bootp) { + kfree_s(recv_bootp, sizeof(struct bootp_pkt)); + recv_bootp = NULL; + } +} + + +/* + * Allocate memory for BOOTP packet buffers + */ +static inline int root_alloc_bootp(void) +{ + if (!(xmit_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL)) || + !(recv_bootp = kmalloc(sizeof(struct bootp_pkt), GFP_KERNEL))) { + printk("BOOTP: Out of memory!"); + return -1; + } + return 0; +} + + +/* + * Create default route for BOOTP sending + */ +static int root_add_bootp_route(void) +{ + struct rtentry route; + + memset(&route, 0, sizeof(route)); + route.rt_dev = bootp_dev->name; + route.rt_mss = bootp_dev->mtu; + route.rt_flags = RTF_UP; + ((struct sockaddr_in *) &(route.rt_dst)) -> sin_addr.s_addr = 0; + ((struct sockaddr_in *) &(route.rt_dst)) -> sin_family = AF_INET; + ((struct sockaddr_in *) &(route.rt_genmask)) -> sin_addr.s_addr = 0; + ((struct sockaddr_in *) &(route.rt_genmask)) -> sin_family = AF_INET; + if (ip_rt_new(&route)) { + printk(KERN_ERR "BOOTP: Adding of route failed!\n"); + return -1; + } + bootp_have_route = 1; + return 0; +} + - if (num == 0) { - printk(KERN_ERR "NFS: Couldn't find device to send RARP request to\n"); +/* + * Delete default route for BOOTP sending + */ +static int root_del_bootp_route(void) +{ + struct rtentry route; + + if (!bootp_have_route) + return 0; + memset(&route, 0, sizeof(route)); + ((struct sockaddr_in *) &(route.rt_dst)) -> sin_addr.s_addr = 0; + ((struct sockaddr_in *) &(route.rt_genmask)) -> sin_addr.s_addr = 0; + if (ip_rt_kill(&route)) { + printk(KERN_ERR "BOOTP: Deleting of route failed!\n"); return -1; } + bootp_have_route = 0; return 0; } /* + * Open UDP socket. + */ +static int root_open_udp_sock(int *fd, struct socket **sock) +{ + struct file *file; + struct inode *inode; + + *fd = sys_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (*fd >= 0) { + file = current->files->fd[*fd]; + inode = file->f_inode; + *sock = &inode->u.socket_i; + return 0; + } + + printk(KERN_ERR "BOOTP: Cannot open UDP socket!\n"); + return -1; +} + + +/* + * Connect UDP socket. + */ +static int root_connect_udp_sock(struct socket *sock, u32 addr, u16 port) +{ + struct sockaddr_in sa; + int result; + + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl(addr); + sa.sin_port = htons(port); + result = sock->ops->connect(sock, (struct sockaddr *) &sa, sizeof(sa), 0); + if (result < 0) { + printk(KERN_ERR "BOOTP: connect() failed\n"); + return -1; + } + return 0; +} + + +/* + * Bind UDP socket. + */ +static int root_bind_udp_sock(struct socket *sock, u32 addr, u16 port) +{ + struct sockaddr_in sa; + int result; + + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl(addr); + sa.sin_port = htons(port); + result = sock->ops->bind(sock, (struct sockaddr *) &sa, sizeof(sa)); + if (result < 0) { + printk(KERN_ERR "BOOTP: bind() failed\n"); + return -1; + } + return 0; +} + + +/* + * Send UDP packet. + */ +static inline int root_send_udp(struct socket *sock, void *buf, int size) +{ + u32 oldfs; + int result; + struct msghdr msg; + struct iovec iov; + + oldfs = get_fs(); + set_fs(get_ds()); + iov.iov_base = buf; + iov.iov_len = size; + msg.msg_name = NULL; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_accrights = NULL; + result = sock->ops->sendmsg(sock, &msg, size, 0, 0); + set_fs(oldfs); + return (result != size); +} + + +/* + * Try to receive UDP packet. + */ +static inline int root_recv_udp(struct socket *sock, void *buf, int size) +{ + u32 oldfs; + int result; + struct msghdr msg; + struct iovec iov; + + oldfs = get_fs(); + set_fs(get_ds()); + iov.iov_base = buf; + iov.iov_len = size; + msg.msg_name = NULL; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_accrights = NULL; + msg.msg_namelen = 0; + result = sock->ops->recvmsg(sock, &msg, size, O_NONBLOCK, 0, &msg.msg_namelen); + set_fs(oldfs); + return result; +} + + +/* + * Initialize BOOTP extension fields in the request. + */ +static void root_bootp_init_ext(u8 *e) +{ + *e++ = 99; /* RFC1048 Magic Cookie */ + *e++ = 130; + *e++ = 83; + *e++ = 99; + *e++ = 1; /* Subnet mask request */ + *e++ = 4; + e += 4; + *e++ = 3; /* Default gateway request */ + *e++ = 4; + e += 4; + *e++ = 12; /* Host name request */ + *e++ = 32; + e += 32; + *e++ = 15; /* Domain name request */ + *e++ = 32; + e += 32; + *e++ = 17; /* Boot path */ + *e++ = 32; + e += 32; + *e = 255; /* End of the list */ +} + + +/* + * Deinitialize the BOOTP mechanism. + */ +static void root_bootp_close(void) +{ + if (bootp_xmit_fd != -1) + sys_close(bootp_xmit_fd); + if (bootp_recv_fd != -1) + sys_close(bootp_recv_fd); + root_del_bootp_route(); + root_free_bootp(); +} + + +/* + * Initialize the BOOTP mechanism. + */ +static int root_bootp_open(void) +{ + struct open_dev *openp; + struct device *dev, *best_dev; + + /* + * Select the best interface for BOOTP. We try to select a first + * Ethernet-like interface. It's shame I know no simple way how to send + * BOOTP's to all interfaces, but it doesn't apply to usual diskless + * stations as they don't have multiple interfaces. + */ + + best_dev = NULL; + for (openp = open_base; openp != NULL; openp = openp->next) { + dev = openp->dev; + if (dev->flags & IFF_BROADCAST) { + if (!best_dev || + ((best_dev->flags & IFF_NOARP) && !(dev->flags & IFF_NOARP))) + best_dev = dev; + } + } + + if (!best_dev) { + printk(KERN_ERR "BOOTP: This cannot happen!\n"); + return -1; + } + bootp_dev = best_dev; + + /* Allocate memory for BOOTP packets */ + if (root_alloc_bootp()) + return -1; + + /* Construct BOOTP request */ + memset(xmit_bootp, 0, sizeof(struct bootp_pkt)); + xmit_bootp->op = BOOTP_REQUEST; + get_random_bytes(&xmit_bootp->xid, sizeof(xmit_bootp->xid)); + xmit_bootp->htype = best_dev->type; + xmit_bootp->hlen = best_dev->addr_len; + memcpy(xmit_bootp->hw_addr, best_dev->dev_addr, best_dev->addr_len); + root_bootp_init_ext(xmit_bootp->vendor_area); +#ifdef NFSROOT_DEBUG + { + int x; + printk(KERN_NOTICE "BOOTP: XID=%08x, DE=%s, HT=%02x, HL=%02x, HA=", + xmit_bootp->xid, + best_dev->name, + xmit_bootp->htype, + xmit_bootp->hlen); + for(x=0; xhlen; x++) + printk("%02x", xmit_bootp->hw_addr[x]); + printk("\n"); + } +#endif + + /* Create default route to that interface */ + if (root_add_bootp_route()) + return -1; + + /* Open the sockets */ + if (root_open_udp_sock(&bootp_xmit_fd, &bootp_xmit_sock) || + root_open_udp_sock(&bootp_recv_fd, &bootp_recv_sock)) + return -1; + + /* Bind/connect the sockets */ + ((struct sock *) bootp_xmit_sock->data) -> broadcast = 1; + ((struct sock *) bootp_xmit_sock->data) -> reuse = 1; + ((struct sock *) bootp_recv_sock->data) -> reuse = 1; + if (root_bind_udp_sock(bootp_recv_sock, INADDR_ANY, 68) || + root_bind_udp_sock(bootp_xmit_sock, INADDR_ANY, 68) || + root_connect_udp_sock(bootp_xmit_sock, INADDR_BROADCAST, 67)) + return -1; + + return 0; +} + + +/* + * Send BOOTP request. + */ +static int root_bootp_send(u32 jiffies) +{ + xmit_bootp->secs = htons(jiffies / HZ); + return root_send_udp(bootp_xmit_sock, xmit_bootp, sizeof(struct bootp_pkt)); +} + + +/* + * Copy BOOTP-supplied string if not already set. + */ +static int root_bootp_string(char *dest, char *src, int len, int max) +{ + if (*dest || !len) + return 0; + if (len > max-1) + len = max-1; + strncpy(dest, src, len); + dest[len] = '\0'; + return 1; +} + + +/* + * Process BOOTP extension. + */ +static void root_do_bootp_ext(u8 *ext) +{ + u8 *c; + static int got_bootp_domain = 0; + +#ifdef NFSROOT_MORE_DEBUG + printk("BOOTP: Got extension %02x",*ext); + for(c=ext+2; cop != BOOTP_REPLY || + recv_bootp->htype != xmit_bootp->htype || + recv_bootp->hlen != xmit_bootp->hlen || + recv_bootp->xid != xmit_bootp->xid) { +#ifdef NFSROOT_DEBUG + printk("?"); +#endif + return; + } + + /* Record BOOTP packet arrival in the global variables */ + cli(); + if (pkt_arrived) { + sti(); + return; + } + pkt_arrived = ARRIVED_BOOTP; + sti(); + root_dev = bootp_dev; + + /* Extract basic fields */ + myaddr.sin_addr.s_addr = recv_bootp->your_ip; + server.sin_addr.s_addr = recv_bootp->server_ip; + + /* Parse extensions */ + if (recv_bootp->vendor_area[0] == 99 && /* Check magic cookie */ + recv_bootp->vendor_area[1] == 130 && + recv_bootp->vendor_area[2] == 83 && + recv_bootp->vendor_area[3] == 99) { + ext = &recv_bootp->vendor_area[4]; + end = (u8 *) recv_bootp + len; + while (ext < end && *ext != 255) { + if (*ext == 0) /* Padding */ + ext++; + else { + opt = ext; + ext += ext[1] + 2; + if (ext <= end) + root_do_bootp_ext(opt); + } + } + } +} + + +/*************************************************************************** + + Dynamic configuration of IP. + + ***************************************************************************/ + +/* * Determine client and server IP numbers and appropriate device by using - * the RARP protocol. + * the RARP and BOOTP protocols. */ -static int do_rarp(void) +static int root_auto_config(void) { - int retries = 0; - unsigned long timeout = 0; - volatile struct device **root_dev_ptr = (volatile struct device **) &root_dev; + int retries; + u32 timeout, jiff; + u32 start_jiffies; + + /* Check devices */ + if (bootp_flag && !bootp_dev_count) { + printk(KERN_ERR "BOOTP: No suitable device found.\n"); + bootp_flag = 0; + } + if (rarp_flag && !rarp_dev_count) { + printk(KERN_ERR "RARP: No suitable device found.\n"); + rarp_flag = 0; + } + + /* If neither BOOTP nor RARP was selected manually, use both of them */ + if (!bootp_flag && !rarp_flag) { +#ifdef CONFIG_USE_BOOTP + if (bootp_dev_count) + bootp_flag = 1; +#endif +#ifdef CONFIG_USE_RARP + if (rarp_dev_count) + rarp_flag = 1; +#endif + if (!bootp_flag && !rarp_flag) + return -1; + } - /* Setup RARP protocol */ - root_rarp_open(); + /* Setup RARP and BOOTP protocols */ + if (rarp_flag) + root_rarp_open(); + if (bootp_flag && root_bootp_open()) { + root_bootp_close(); + return -1; + } /* - * Send RARP request and wait, until we get an answer. This loop - * seems to be a terrible waste of cpu time, but actually there is - * no process running at all, so we don't need to use any + * Send requests and wait, until we get an answer. This loop + * seems to be a terrible waste of CPU time, but actually there is + * only one process running at all, so we don't need to use any * scheduler functions. * [Actually we could now, but the nothing else running note still * applies.. - AC] */ - for (retries = 0; retries < RARP_RETRIES && *root_dev_ptr == NULL; retries++) { - if (root_rarp_send() < 0) + printk(KERN_NOTICE "Sending %s%s%s requests...", + bootp_flag ? "BOOTP" : "", + bootp_flag && rarp_flag ? " and " : "", + rarp_flag ? "RARP" : ""); + start_jiffies = jiffies; + retries = CONF_RETRIES; + get_random_bytes(&timeout, sizeof(timeout)); + timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM); + for(;;) { + if (bootp_flag && root_bootp_send(jiffies - start_jiffies)) { + printk("...BOOTP failed!\n"); + root_bootp_close(); + bootp_flag = 0; + if (!rarp_flag) + break; + } + if (rarp_flag) + root_rarp_send(); + printk("."); + jiff = jiffies + timeout; + while (jiffies < jiff && !pkt_arrived) + root_bootp_recv(); + if (pkt_arrived) break; - timeout = jiffies + (RARP_TIMEOUT * HZ); - while (jiffies < timeout && *root_dev_ptr == NULL) - ; + if (! --retries) { + printk("timed out!\n"); + break; + } + timeout = timeout CONF_TIMEOUT_MULT; + if (timeout > CONF_TIMEOUT_MAX) + timeout = CONF_TIMEOUT_MAX; } - root_rarp_close(); - if (*root_dev_ptr == NULL && timeout > 0) { - printk(KERN_ERR "NFS: Timed out while waiting for RARP answer\n"); + if (rarp_flag) + root_rarp_close(); + if (bootp_flag) + root_bootp_close(); + + if (!pkt_arrived) return -1; - } - printk(KERN_NOTICE "NFS: "); - printk("Got RARP answer from %s, ", in_ntoa(server.sin_addr.s_addr)); + + printk("OK\n"); + printk(KERN_NOTICE "Root-NFS: Got %s answer from %s, ", + (pkt_arrived == ARRIVED_BOOTP) ? "BOOTP" : "RARP", + in_ntoa(server.sin_addr.s_addr)); printk("my address is %s\n", in_ntoa(myaddr.sin_addr.s_addr)); return 0; } - - /*************************************************************************** - Routines to setup NFS + Parsing of options ***************************************************************************/ - /* * The following integer options are recognized */ @@ -410,12 +992,7 @@ char buf[NFS_MAXPATHLEN]; char *cp, *options, *val; - /* Set the default system name in case none was previously found */ - if (!system_utsname.nodename[0]) { - strncpy(system_utsname.nodename, in_ntoa(myaddr.sin_addr.s_addr), __NEW_UTS_LEN); - system_utsname.nodename[__NEW_UTS_LEN] = '\0'; - } - /* It is possible to override the host IP number here */ + /* It is possible to override the server IP number here */ if (*name >= '0' && *name <= '9' && (cp = strchr(name, ':')) != NULL) { *cp++ = '\0'; server.sin_addr.s_addr = in_aton(name); @@ -432,7 +1009,7 @@ if ((options = strchr(buf, ','))) *options++ = '\0'; if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) { - printk(KERN_ERR "NFS: Pathname for remote directory too long\n"); + printk(KERN_ERR "Root-NFS: Pathname for remote directory too long\n"); return -1; } sprintf(nfs_path, buf, cp); @@ -480,26 +1057,40 @@ /* * Tell the user what's going on. */ +#ifdef NFSROOT_DEBUG static void root_nfs_print(void) { -#ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Mounting %s on server %s as root\n", + printk(KERN_NOTICE "Root-NFS: IP config: dev=%s, ", + root_dev ? root_dev->name : "none"); + printk("local=%s, ", IN_NTOA(myaddr.sin_addr.s_addr)); + printk("server=%s, ", IN_NTOA(server.sin_addr.s_addr)); + printk("gw=%s, ", IN_NTOA(gateway.sin_addr.s_addr)); + printk("mask=%s, ", IN_NTOA(netmask.sin_addr.s_addr)); + printk("host=%s, domain=%s\n", + system_utsname.nodename[0] ? system_utsname.nodename : "none", + system_utsname.domainname[0] ? system_utsname.domainname : "none"); + printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n", nfs_path, nfs_data.hostname); - printk(KERN_NOTICE "NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", + printk(KERN_NOTICE "Root-NFS: rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", nfs_data.rsize, nfs_data.wsize, nfs_data.timeo, nfs_data.retrans); - printk(KERN_NOTICE "NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n", + printk(KERN_NOTICE "Root-NFS: acreg (min,max) = (%d,%d), acdir (min,max) = (%d,%d)\n", nfs_data.acregmin, nfs_data.acregmax, nfs_data.acdirmin, nfs_data.acdirmax); - printk(KERN_NOTICE "NFS: port = %d, flags = %08x\n", + printk(KERN_NOTICE "Root-NFS: port = %d, flags = %08x\n", nfs_port, nfs_data.flags); -#endif } +#endif /* - * Parse any IP addresses + * Parse any IP configuration options (the "nfsaddrs" parameter). + * The parameter consists of option fields separated by colons. It can start + * with device name and possibly with auto-config type ("bootp" or "rarp") + * followed by own IP address, IP address of the server, IP address of + * default gateway, local netmask and a host name. Any of the addresses can + * be blank to indicate that default value should be used. */ -static void root_nfs_addrs(char *addrs) +static void root_nfs_ip_config(char *addrs) { char *cp, *ip, *dp; int num = 0; @@ -511,21 +1102,32 @@ gateway.sin_addr.s_addr = netmask.sin_addr.s_addr = INADDR_NONE; system_utsname.nodename[0] = '\0'; system_utsname.domainname[0] = '\0'; + user_dev_name[0] = '\0'; + bootp_flag = rarp_flag = 0; - /* - * Parse the address field. It contains 4 IP addresses which are - * separated by colons: Field 0 = my own address Field 1 = server - * address Field 2 = gateway address Field 3 = netmask address - * Field 4 = client host name - */ + /* Check for device name and BOOTP/RARP flags */ ip = addrs; + while (ip && *ip && (*ip < '0' || *ip > '9')) { + if ((cp = strchr(ip, ':'))) + *cp++ = '\0'; + if (*ip) { + if (!strcmp(ip, "rarp")) + rarp_flag = 1; + else if (!strcmp(ip, "bootp")) + bootp_flag = 1; + else if (!user_dev_name[0]) { + strncpy(user_dev_name, ip, IFNAMSIZ); + user_dev_name[IFNAMSIZ-1] = '\0'; + } + } + ip = cp; + } + + /* Parse the IP addresses */ while (ip && *ip) { if ((cp = strchr(ip, ':'))) *cp++ = '\0'; if (strlen(ip) > 0) { -#ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: IP address num %d is \"%s\"\n", num, ip); -#endif switch (num) { case 0: myaddr.sin_addr.s_addr = in_aton(ip); @@ -555,16 +1157,35 @@ ip = cp; num++; } +#ifdef NFSROOT_DEBUG + printk(KERN_NOTICE "Root-NFS: IP options: dev=%s, RARP=%d, BOOTP=%d, ", + user_dev_name[0] ? user_dev_name : "none", + rarp_flag, + bootp_flag); + printk("local=%s, ", IN_NTOA(myaddr.sin_addr.s_addr)); + printk("server=%s, ", IN_NTOA(server.sin_addr.s_addr)); + printk("gw=%s, ", IN_NTOA(gateway.sin_addr.s_addr)); + printk("mask=%s, ", IN_NTOA(netmask.sin_addr.s_addr)); + printk("host=%s, domain=%s\n", + system_utsname.nodename[0] ? system_utsname.nodename : "none", + system_utsname.domainname[0] ? system_utsname.domainname : "none"); +#endif } /* * Set the interface address and configure a route to the server. */ -static void root_nfs_setup(void) +static int root_nfs_setup(void) { struct rtentry route; + /* Set the default system name in case none was previously found */ + if (!system_utsname.nodename[0]) { + strncpy(system_utsname.nodename, in_ntoa(myaddr.sin_addr.s_addr), __NEW_UTS_LEN); + system_utsname.nodename[__NEW_UTS_LEN] = '\0'; + } + /* Set the correct netmask */ if (netmask.sin_addr.s_addr == INADDR_NONE) netmask.sin_addr.s_addr = ip_get_mask(myaddr.sin_addr.s_addr); @@ -578,31 +1199,43 @@ /* * Now add a route to the server. If there is no gateway given, - * the server is on our own local network, so a host route is - * sufficient. Otherwise we first have to create a host route to - * the gateway, and then setup a gatewayed host route to the - * server. Note that it's not possible to setup a network route - * because we don't know the network mask of the server network. + * the server is on the same subnet, so we establish only a route to + * the local network. Otherwise we create a route to the gateway (the + * same local network router as in the former case) and then setup a + * gatewayed default route. Note that this gives sufficient network + * setup even for full system operation in all common cases. */ - memset(&route, 0, sizeof(route)); + memset(&route, 0, sizeof(route)); /* Local subnet route */ route.rt_dev = root_dev->name; route.rt_mss = root_dev->mtu; - route.rt_flags = RTF_HOST | RTF_UP; + route.rt_flags = RTF_UP; + *((struct sockaddr_in *) &(route.rt_dst)) = myaddr; + (((struct sockaddr_in *) &(route.rt_dst))) -> sin_addr.s_addr &= netmask.sin_addr.s_addr; *((struct sockaddr_in *) &(route.rt_genmask)) = netmask; + if (ip_rt_new(&route)) { + printk(KERN_ERR "Root-NFS: Adding of local route failed!\n"); + return -1; + } - if (gateway.sin_addr.s_addr == INADDR_NONE || - gateway.sin_addr.s_addr == server.sin_addr.s_addr || - !((server.sin_addr.s_addr ^ root_dev->pa_addr) & root_dev->pa_mask)) { - *((struct sockaddr_in *) &(route.rt_dst)) = server; - ip_rt_new(&route); - } else { - *((struct sockaddr_in *) &(route.rt_dst)) = gateway; - ip_rt_new(&route); - route.rt_flags |= RTF_GATEWAY; + if (gateway.sin_addr.s_addr != INADDR_NONE) { /* Default route */ + (((struct sockaddr_in *) &(route.rt_dst))) -> sin_addr.s_addr = 0; + (((struct sockaddr_in *) &(route.rt_genmask))) -> sin_addr.s_addr = 0; *((struct sockaddr_in *) &(route.rt_gateway)) = gateway; - *((struct sockaddr_in *) &(route.rt_dst)) = server; - ip_rt_new(&route); + route.rt_flags |= RTF_GATEWAY; + if ((gateway.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) { + printk(KERN_ERR "Root-NFS: Gateway not on local network!\n"); + return -1; + } + if (ip_rt_new(&route)) { + printk(KERN_ERR "Root-NFS: Adding of default route failed!\n"); + return -1; + } + } else if ((server.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) { + printk(KERN_ERR "Root-NFS: Boot server not on local network and no default gateway configured!\n"); + return -1; } + + return 0; } @@ -612,27 +1245,36 @@ */ int nfs_root_init(char *nfsname, char *nfsaddrs) { + /* + * Get local and server IP address. First check for network config + * parameters in the command line parameter. + */ + root_nfs_ip_config(nfsaddrs); + + /* Parse NFS options */ + if (root_nfs_parse(nfsname)) + return -1; + /* Setup all network devices */ if (root_dev_open() < 0) return -1; /* - * Get local and server IP address. First check for addresses in - * command line parameter. If one of the IP addresses is missing, - * or there's more than one network interface in the system, use - * RARP to get the missing values and routing information. If all - * addresses are given, the best way to find a proper routing is - * to use icmp echo requests ("ping"), but that would add a lot of - * code to this module, which is only really necessary in the rare - * case of multiple ethernet devices in the (diskless) system and - * if the server is on another subnet (otherwise RARP can serve as - * a ping substitute). If only one device is installed the routing - * is obvious. + * If the config information is insufficient (e.g., our IP address or + * IP address of the boot server is missing or we have multiple network + * interfaces and no default was set), use BOOTP or RARP to get the + * missing values. + * + * Note that we don't try to set up correct routes for multiple + * interfaces (could be solved by trying icmp echo requests), because + * it's only necessary in the rare case of multiple ethernet devices + * in the (diskless) system and if the server is on another subnet. + * If only one interface is installed, the routing is obvious. */ - root_nfs_addrs(nfsaddrs); if ((myaddr.sin_addr.s_addr == INADDR_NONE || server.sin_addr.s_addr == INADDR_NONE || - (open_base != NULL && open_base->next != NULL)) && do_rarp() < 0) { + (open_base != NULL && open_base->next != NULL)) && + root_auto_config() < 0) { root_dev_close(); return -1; } @@ -640,7 +1282,8 @@ if (open_base != NULL && open_base->next == NULL) { root_dev = open_base->dev; } else { - printk(KERN_ERR "NFS: Unable to find routing to server\n"); + /* I hope this cannot happen */ + printk(KERN_ERR "Root-NFS: 1 == 0!\n"); root_dev_close(); return -1; } @@ -651,23 +1294,21 @@ */ root_dev_close(); - /* - * Initialize the global variables necessary for NFS. The server - * directory is actually mounted after init() has been started. - */ - if (root_nfs_parse(nfsname) < 0) + /* Setup devices and routes */ + if (root_nfs_setup()) return -1; + +#ifdef NFSROOT_DEBUG root_nfs_print(); - root_nfs_setup(); +#endif + return 0; } - - /*************************************************************************** - Routines to actually mount the root directory + Routines to actually mount the root directory ***************************************************************************/ @@ -675,8 +1316,6 @@ static struct inode nfs_inode; /* Inode containing socket */ static int *rpc_packet = NULL; /* RPC packet */ -extern asmlinkage int sys_socket(int family, int type, int protocol); - /* * Open a UDP socket. @@ -687,7 +1326,7 @@ /* Open the socket */ if ((nfs_data.fd = sys_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - printk(KERN_ERR "NFS: Cannot open UDP socket\n"); + printk(KERN_ERR "Root-NFS: Cannot open UDP socket!\n"); return -1; } /* @@ -764,12 +1403,12 @@ } } if (res < 0) { - printk(KERN_ERR "NFS: Cannot find a suitable listening port\n"); + printk(KERN_ERR "Root-NFS: Cannot find a suitable listening port\n"); root_nfs_close(1); return -1; } #ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Binding to listening port %d\n", port); + printk(KERN_NOTICE "Root-NFS: Binding to listening port %d\n", port); #endif return 0; } @@ -840,7 +1479,7 @@ if (rpc_packet == NULL) { if (!(rpc_packet = kmalloc(nfs_data.wsize + 1024, GFP_NFS))) { - printk(KERN_ERR "NFS: Cannot allocate UDP buffer\n"); + printk(KERN_ERR "Root-NFS: Cannot allocate UDP buffer\n"); return NULL; } } @@ -884,21 +1523,21 @@ if (nfs_port < 0) { if ((port = root_nfs_get_port(NFS_NFS_PROGRAM, NFS_NFS_VERSION)) < 0) { - printk(KERN_ERR "NFS: Unable to get nfsd port number from server, using default\n"); + printk(KERN_ERR "Root-NFS: Unable to get nfsd port number from server, using default\n"); port = NFS_NFS_PORT; } nfs_port = port; #ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Portmapper on server returned %d as nfsd port\n", port); + printk(KERN_NOTICE "Root-NFS: Portmapper on server returned %d as nfsd port\n", port); #endif } if ((port = root_nfs_get_port(NFS_MOUNT_PROGRAM, NFS_MOUNT_VERSION)) < 0) { - printk(KERN_ERR "NFS: Unable to get mountd port number from server, using default\n"); + printk(KERN_ERR "Root-NFS: Unable to get mountd port number from server, using default\n"); port = NFS_MOUNT_PORT; } server.sin_port = htons(port); #ifdef NFSROOT_DEBUG - printk(KERN_NOTICE "NFS: Portmapper on server returned %d as mountd port\n", port); + printk(KERN_NOTICE "Root-NFS: Portmapper on server returned %d as mountd port\n", port); #endif return 0; @@ -935,10 +1574,9 @@ status = ntohl(*p++); if (status == 0) { nfs_data.root = *((struct nfs_fh *) p); - printk(KERN_NOTICE "NFS: "); - printk("Got file handle for %s via RPC\n", nfs_path); + printk(KERN_NOTICE "Root-NFS: Got file handle for %s via RPC\n", nfs_path); } else { - printk(KERN_ERR "NFS: Server returned error %d while mounting %s\n", + printk(KERN_ERR "Root-NFS: Server returned error %d while mounting %s\n", status, nfs_path); root_nfs_close(1); return -1; diff -u --recursive --new-file v1.3.74/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h --- v1.3.74/linux/include/asm-i386/bitops.h Mon Dec 11 15:42:05 1995 +++ linux/include/asm-i386/bitops.h Sat Mar 16 13:52:10 1996 @@ -15,8 +15,10 @@ #ifdef __SMP__ #define LOCK_PREFIX "lock ; " +#define SMPVOL volatile #else #define LOCK_PREFIX "" +#define SMPVOL #endif /* @@ -26,7 +28,7 @@ #define ADDR (*(struct __dummy *) addr) #define CONST_ADDR (*(const struct __dummy *) addr) -extern __inline__ int set_bit(int nr, void * addr) +extern __inline__ int set_bit(int nr, SMPVOL void * addr) { int oldbit; @@ -37,7 +39,7 @@ return oldbit; } -extern __inline__ int clear_bit(int nr, void * addr) +extern __inline__ int clear_bit(int nr, SMPVOL void * addr) { int oldbit; @@ -48,7 +50,7 @@ return oldbit; } -extern __inline__ int change_bit(int nr, void * addr) +extern __inline__ int change_bit(int nr, SMPVOL void * addr) { int oldbit; @@ -62,7 +64,7 @@ /* * This routine doesn't need to be atomic. */ -extern __inline__ int test_bit(int nr, const void * addr) +extern __inline__ int test_bit(int nr, const SMPVOL void * addr) { return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31)); } diff -u --recursive --new-file v1.3.74/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h --- v1.3.74/linux/include/asm-i386/smp.h Wed Mar 13 10:09:22 1996 +++ linux/include/asm-i386/smp.h Sat Mar 16 13:52:10 1996 @@ -184,6 +184,7 @@ extern volatile unsigned long smp_invalidate_needed; extern void smp_invalidate(void); extern volatile unsigned long kernel_flag, kernel_counter; +extern volatile unsigned long cpu_callin_map[NR_CPUS]; extern volatile unsigned char active_kernel_processor; extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_reschedule_irq(int cpl, struct pt_regs *regs); diff -u --recursive --new-file v1.3.74/linux/include/linux/ax25.h linux/include/linux/ax25.h --- v1.3.74/linux/include/linux/ax25.h Wed Mar 13 10:09:22 1996 +++ linux/include/linux/ax25.h Sat Mar 16 13:52:10 1996 @@ -32,6 +32,23 @@ ax25_address digi_addr[AX25_MAX_DIGIS]; }; +struct ax25_route_opt_struct +{ + ax25_address port_addr; + ax25_address dest_addr; + int cmd; + int arg; +}; + +struct ax25_ctl_struct +{ + ax25_address port_addr; + ax25_address source_addr; + ax25_address dest_addr; + unsigned int cmd; + unsigned long arg; +}; + struct ax25_bpqaddr_struct { char dev[16]; @@ -49,6 +66,8 @@ #define AX25_IDLE 9 #define AX25_PACLEN 10 +#define AX25_KILL 99 + #define SIOCAX25GETUID (SIOCPROTOPRIVATE) #define SIOCAX25ADDUID (SIOCPROTOPRIVATE+1) #define SIOCAX25DELUID (SIOCPROTOPRIVATE+2) @@ -56,6 +75,18 @@ #define SIOCAX25BPQADDR (SIOCPROTOPRIVATE+4) #define SIOCAX25GETPARMS (SIOCPROTOPRIVATE+5) #define SIOCAX25SETPARMS (SIOCPROTOPRIVATE+6) +#define SIOCAX25OPTRT (SIOCPROTOPRIVATE+7) +#define SIOCAX25CTLCON (SIOCPROTOPRIVATE+8) + +#define AX25_SET_RT_PERMANENT 1 +#define AX25_SET_RT_IPMODE 2 + +#define AX25_RT_DYNAMIC 0 +#define AX25_RT_PERMANENT 1 + +#define AX25_RT_IPMODE_DEFAULT ' ' +#define AX25_RT_IPMODE_DATAGRAM 'D' +#define AX25_RT_IPMODE_VC 'V' #define AX25_NOUID_DEFAULT 0 #define AX25_NOUID_BLOCK 1 diff -u --recursive --new-file v1.3.74/linux/include/linux/binfmts.h linux/include/linux/binfmts.h --- v1.3.74/linux/include/linux/binfmts.h Sun Mar 10 09:49:56 1996 +++ linux/include/linux/binfmts.h Fri Mar 15 15:22:59 1996 @@ -32,7 +32,7 @@ */ struct linux_binfmt { struct linux_binfmt * next; - int *use_count; + long *use_count; int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); int (*load_shlib)(int fd); int (*core_dump)(long signr, struct pt_regs * regs); diff -u --recursive --new-file v1.3.74/linux/include/linux/hdreg.h linux/include/linux/hdreg.h --- v1.3.74/linux/include/linux/hdreg.h Sun Mar 10 09:49:56 1996 +++ linux/include/linux/hdreg.h Sat Mar 16 15:00:02 1996 @@ -164,8 +164,12 @@ #endif /* CONFIG_BLK_DEV_HD */ #ifdef CONFIG_BLK_DEV_IDE void ide_setup(char *); + +#ifdef CONFIG_BLK_DEV_IDE_PCMCIA int ide_register(int io_port, int ctl_port, int irq); -void ide_unregister(int h); +void ide_unregister(unsigned int); +#endif /* CONFIG_BLK_DEV_IDE_PCMCIA */ + #endif /* CONFIG_BLK_DEV_IDE */ #endif /* __KERNEL__ */ diff -u --recursive --new-file v1.3.74/linux/include/linux/if_packet.h linux/include/linux/if_packet.h --- v1.3.74/linux/include/linux/if_packet.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/if_packet.h Sat Mar 16 13:52:11 1996 @@ -0,0 +1,11 @@ +#ifndef __LINUX_IF_PACKET_H +#define __LINUX_IF_PACKET_H + +struct sockaddr_pkt +{ + unsigned short spkt_family; + unsigned char spkt_device[14]; + unsigned short spkt_protocol; +}; + +#endif diff -u --recursive --new-file v1.3.74/linux/include/linux/mcdx.h linux/include/linux/mcdx.h --- v1.3.74/linux/include/linux/mcdx.h Tue Mar 5 10:11:12 1996 +++ linux/include/linux/mcdx.h Fri Mar 15 10:58:46 1996 @@ -1,7 +1,7 @@ /* * Definitions for the Mitsumi CDROM interface * Copyright (C) 1995 Heiko Schlittermann - * VERSION: 1.7 + * VERSION: 1.8 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -82,12 +82,15 @@ #if MCDX_QUIET == 1 #define INFO(x) -#define WARN(x) warn x +#define xinfo(fmt, args...) #else #define INFO(x) warn x -#define WARN(x) warn x +#define xinfo(fmt, args...) _warn(fmt, ## args) #endif +#define WARN(x) warn x +#define xwarn(fmt, args...) _warn(fmt, ## args) +#define _warn warn #if MCDX_DEBUG == 1 #define TRACE(x) trace x diff -u --recursive --new-file v1.3.74/linux/include/linux/personality.h linux/include/linux/personality.h --- v1.3.74/linux/include/linux/personality.h Wed Aug 2 13:21:16 1995 +++ linux/include/linux/personality.h Fri Mar 15 15:22:59 1996 @@ -37,7 +37,7 @@ unsigned char pers_low, pers_high; unsigned long * signal_map; unsigned long * signal_invmap; - int *use_count; + long *use_count; struct exec_domain *next; }; diff -u --recursive --new-file v1.3.74/linux/include/linux/smp.h linux/include/linux/smp.h --- v1.3.74/linux/include/linux/smp.h Fri Feb 9 17:53:10 1996 +++ linux/include/linux/smp.h Sat Mar 16 13:52:11 1996 @@ -14,6 +14,7 @@ extern void smp_callin(void); /* Processor call in. Must hold processors until .. */ extern void smp_commence(void); /* Multiprocessors may now schedule */ extern int smp_num_cpus; +extern int smp_top_cpu; /* Top CPU number */ extern int smp_threads_ready; /* True once the per process idle is forked */ #ifdef __SMP_PROF__ extern volatile unsigned long smp_spins[NR_CPUS]; /* count of interrupt spins */ @@ -47,6 +48,7 @@ #define smp_num_cpus 1 #define smp_processor_id() 0 +#define smp_top_cpu 0 #define smp_message_pass(t,m,d,w) #define smp_threads_ready 1 #define kernel_lock() diff -u --recursive --new-file v1.3.74/linux/include/linux/tty.h linux/include/linux/tty.h --- v1.3.74/linux/include/linux/tty.h Sat Feb 17 16:02:54 1996 +++ linux/include/linux/tty.h Sat Mar 16 15:00:02 1996 @@ -52,7 +52,6 @@ #define ORIG_X (screen_info.orig_x) #define ORIG_Y (screen_info.orig_y) -#define ORIG_VIDEO_PAGE (screen_info.orig_video_page) #define ORIG_VIDEO_MODE (screen_info.orig_video_mode) #define ORIG_VIDEO_COLS (screen_info.orig_video_cols) #define ORIG_VIDEO_EGA_BX (screen_info.orig_video_ega_bx) diff -u --recursive --new-file v1.3.74/linux/include/net/route.h linux/include/net/route.h --- v1.3.74/linux/include/net/route.h Sat Feb 17 16:02:55 1996 +++ linux/include/net/route.h Sat Mar 16 15:00:09 1996 @@ -192,6 +192,7 @@ extern int rt_cache_get_info(char *buffer, char **start, off_t offset, int length, int dummy); extern int ip_rt_ioctl(unsigned int cmd, void *arg); extern int ip_rt_new(struct rtentry *rt); +extern int ip_rt_kill(struct rtentry *rt); extern void ip_rt_check_expire(void); extern void ip_rt_advice(struct rtable **rp, int advice); diff -u --recursive --new-file v1.3.74/linux/include/net/tcp.h linux/include/net/tcp.h --- v1.3.74/linux/include/net/tcp.h Tue Feb 20 14:37:28 1996 +++ linux/include/net/tcp.h Sat Mar 16 18:21:19 1996 @@ -179,25 +179,33 @@ * * 1. The window can never be shrunk once it is offered (RFC 793) * 2. We limit memory per socket + * 3. No reason to raise the window if the other side has + * lots of room to play with. */ static __inline__ unsigned short tcp_raise_window(struct sock *sk) { - long free_space = sock_rspace(sk); + long free_space; long window; - if (free_space > 1024) - free_space &= ~0x3FF; /* make free space a multiple of 1024 */ - if(sk->window_clamp) - free_space = min(sk->window_clamp, free_space); - /* * compute the actual window i.e. - * old_window - received_bytes_on_that_win + * old_window - received_bytes_on_that_win. + * + * Don't raise the window if we have lots left: + * that only results in unnecessary packets. */ + window = sk->window - (sk->acked_seq - sk->lastwin_seq); + if (window >= MAX_WINDOW/2) + return 0; - window = sk->window - (sk->acked_seq - sk->lastwin_seq); + free_space = sock_rspace(sk); + if (free_space > 1024) + free_space &= ~0x3FF; /* make free space a multiple of 1024 */ + + if(sk->window_clamp) + free_space = min(sk->window_clamp, free_space); if (sk->mss == 0) sk->mss = sk->mtu; diff -u --recursive --new-file v1.3.74/linux/init/main.c linux/init/main.c --- v1.3.74/linux/init/main.c Fri Mar 15 16:03:21 1996 +++ linux/init/main.c Sat Mar 16 13:52:09 1996 @@ -60,6 +60,7 @@ extern long pci_init(long, long); extern void sysctl_init(void); +extern void no_scroll(char *str, int *ints); extern void swap_setup(char *str, int *ints); extern void buff_setup(char *str, int *ints); extern void panic_setup(char *str, int *ints); @@ -222,6 +223,7 @@ { "swap=", swap_setup }, { "buff=", buff_setup }, { "panic=", panic_setup }, + { "no-scroll", no_scroll }, #ifdef CONFIG_BUGi386 { "no-hlt", no_halt }, { "no387", no_387 }, @@ -794,6 +796,7 @@ real_root_dev = ROOT_DEV; real_root_mountflags = root_mountflags; if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; + else mount_initrd =0; #endif setup(); @@ -823,7 +826,7 @@ #ifdef CONFIG_BLK_DEV_INITRD root_mountflags = real_root_mountflags; - if (ROOT_DEV != real_root_dev && ROOT_DEV == MKDEV(RAMDISK_MAJOR,0)) { + if (mount_initrd && ROOT_DEV != real_root_dev && ROOT_DEV == MKDEV(RAMDISK_MAJOR,0)) { int error; pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); diff -u --recursive --new-file v1.3.74/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.3.74/linux/kernel/ksyms.c Wed Mar 13 10:09:24 1996 +++ linux/kernel/ksyms.c Sat Mar 16 13:52:16 1996 @@ -92,6 +92,7 @@ extern char *get_options(char *str, int *ints); extern void set_device_ro(int dev,int flag); extern struct file_operations * get_blkfops(unsigned int); +extern void blkdev_release(struct inode * inode); extern void *sys_call_table; @@ -227,6 +228,8 @@ X(bmap), X(sync_dev), X(get_blkfops), + X(blkdev_open), + X(blkdev_release), #ifdef CONFIG_SERIAL /* Module creation of serial units */ X(register_serial), @@ -469,9 +472,13 @@ X(tr_type_trans), #endif -#ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_BLK_DEV_IDE_PCMCIA X(ide_register), X(ide_unregister), +#endif + +#ifdef CONFIG_BLK_DEV_MD + X(disk_name), /* for md.c */ #endif /* bimfm_aout */ diff -u --recursive --new-file v1.3.74/linux/kernel/printk.c linux/kernel/printk.c --- v1.3.74/linux/kernel/printk.c Tue Mar 5 10:11:13 1996 +++ linux/kernel/printk.c Fri Mar 15 10:23:04 1996 @@ -34,7 +34,7 @@ /* We show everything that is MORE important than this.. */ #define MINIMUM_CONSOLE_LOGLEVEL 5 /* Minimum loglevel we let people use */ -#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_NOTICE */ +#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ unsigned long log_size = 0; struct wait_queue * log_wait = NULL; diff -u --recursive --new-file v1.3.74/linux/kernel/sched.c linux/kernel/sched.c --- v1.3.74/linux/kernel/sched.c Wed Mar 13 10:09:24 1996 +++ linux/kernel/sched.c Sat Mar 16 13:52:11 1996 @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -101,6 +102,9 @@ static inline void add_to_runqueue(struct task_struct * p) { +#ifdef __SMP__ + int cpu=smp_processor_id(); +#endif #if 1 /* sanity tests */ if (p->next_run || p->prev_run) { printk("task already on run-queue\n"); @@ -115,17 +119,34 @@ init_task.prev_run = p; #ifdef __SMP__ /* this is safe only if called with cli()*/ - while(set_bit(31,&smp_process_available)) - while(test_bit(31,&smp_process_available)); + while(set_bit(31,&smp_process_available)); +#if 0 + { + while(test_bit(31,&smp_process_available)) + { + if(clear_bit(cpu,&smp_invalidate_needed)) + { + local_invalidate(); + set_bit(cpu,&cpu_callin_map[0]); + } + } + } +#endif smp_process_available++; clear_bit(31,&smp_process_available); - if ((0!=p->pid) && smp_threads_ready){ - int i, found=0; - for (i=0;ipid) { + if ((0!=p->pid) && smp_threads_ready) + { + int i; + for (i=0;i<=smp_top_cpu;i++) + { + if (cpu_number_map[i]==-1) + continue; + if (0==current_set[i]->pid) + { smp_message_pass(i, MSG_RESCHEDULE, 0L, 0); break; } + } } #endif } @@ -885,14 +906,20 @@ } #else cpu = smp_processor_id(); - for (i=0;i<(0==smp_num_cpus?1:smp_num_cpus);i++){ + for (i=0;i<=smp_top_cpu;i++) + { + if(cpu_number_map[i]==-1) + continue; #ifdef __SMP_PROF__ - if (test_bit(i,&smp_idle_map)) smp_idle_count[i]++; + if (test_bit(i,&smp_idle_map)) + smp_idle_count[i]++; #endif if (((cpu==i) && user_mode(regs)) || - ((cpu!=i) && 0==smp_proc_in_lock[i])) { + ((cpu!=i) && 0==smp_proc_in_lock[i])) + { current_set[i]->utime++; - if (current_set[i]->pid) { + if (current_set[i]->pid) + { if (current_set[i]->priority < DEF_PRIORITY) kstat.cpu_nice++; else diff -u --recursive --new-file v1.3.74/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v1.3.74/linux/kernel/sysctl.c Wed Mar 13 10:09:24 1996 +++ linux/kernel/sysctl.c Fri Mar 15 10:21:12 1996 @@ -192,7 +192,7 @@ newval, newlen, root_table, &context); if (context) kfree(context); - if (error != ENOTDIR) + if (error != -ENOTDIR) return error; tmp = tmp->DLIST_NEXT(ctl_entry); } while (tmp != &root_table_header); diff -u --recursive --new-file v1.3.74/linux/mm/swapfile.c linux/mm/swapfile.c --- v1.3.74/linux/mm/swapfile.c Fri Mar 15 16:03:21 1996 +++ linux/mm/swapfile.c Sat Mar 16 11:55:40 1996 @@ -270,7 +270,7 @@ /* * Go through process' page directory. */ - if (!mm) + if (!mm || mm == &init_mm) return 0; vma = mm->mmap; while (vma) { diff -u --recursive --new-file v1.3.74/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v1.3.74/linux/net/ax25/af_ax25.c Wed Mar 13 10:09:26 1996 +++ linux/net/ax25/af_ax25.c Sat Mar 16 13:52:11 1996 @@ -524,7 +524,123 @@ } return -EINVAL; /*NOTREACHED */ -} +} + +/* + * dl1bke 960311: set parameters for existing AX.25 connections, + * includes a KILL command to abort any connection. + * VERY useful for debugging ;-) + */ + +static int ax25_ctl_ioctl(const unsigned int cmd, const unsigned long arg) +{ + struct ax25_ctl_struct ax25_ctl; + struct device *dev; + ax25_cb *ax25; + unsigned long flags; + int err; + + if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_ctl))) != 0) + return err; + + memcpy_fromfs(&ax25_ctl, (void *) arg, sizeof(ax25_ctl)); + + if ((dev = ax25rtr_get_dev(&ax25_ctl.port_addr)) == NULL) + return -ENODEV; + + if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, dev)) == NULL) + return -ENOTCONN; + + switch (ax25_ctl.cmd) { + case AX25_KILL: +#ifdef CONFIG_NETROM + nr_link_failed(&ax25->dest_addr, ax25->device); +#endif + ax25_clear_queues(ax25); + ax25_send_control(ax25, DISC, POLLON, C_COMMAND); + + ax25->state = AX25_STATE_0; + if (ax25->sk != NULL) { + ax25->sk->state = TCP_CLOSE; + ax25->sk->err = ENETRESET; + if (!ax25->sk->dead) + ax25->sk->state_change(ax25->sk); + ax25->sk->dead = 1; + } + + ax25_dama_off(ax25); + ax25_set_timer(ax25); + break; + case AX25_WINDOW: + if (ax25->modulus == MODULUS) { + if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7) + return -EINVAL; + } else { + if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63) + return -EINVAL; + } + ax25->window = ax25_ctl.arg; + break; + case AX25_T1: + if (ax25_ctl.arg < 1) + return -EINVAL; + ax25->rtt = (ax25_ctl.arg * PR_SLOWHZ) / 2; + ax25->t1 = ax25_ctl.arg * PR_SLOWHZ; + save_flags(flags); cli(); + if (ax25->t1timer > ax25->t1) + ax25->t1timer = ax25->t1; + restore_flags(flags); + break; + case AX25_T2: + if (ax25_ctl.arg < 1) + return -EINVAL; + save_flags(flags); cli(); + ax25->t2 = ax25_ctl.arg * PR_SLOWHZ; + if (ax25->t2timer > ax25->t2) + ax25->t2timer = ax25->t2; + restore_flags(flags); + break; + case AX25_N2: + if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31) + return -EINVAL; + ax25->n2count = 0; + ax25->n2 = ax25_ctl.arg; + break; + case AX25_T3: + if (ax25_ctl.arg < 1) + return -EINVAL; + save_flags(flags); cli(); + ax25->t3 = ax25_ctl.arg * PR_SLOWHZ; + if (ax25->t3timer != 0) + ax25->t3timer = ax25->t3; + restore_flags(flags); + break; + case AX25_IDLE: + if (ax25_ctl.arg < 1) + return -EINVAL; + if (ax25->idle == 0) + return 0; + save_flags(flags); cli(); + ax25->idle = ax25_ctl.arg * PR_SLOWHZ * 60; + if (ax25->idletimer != 0) + ax25->idletimer = ax25->idle; + restore_flags(flags); + break; + case AX25_PACLEN: + if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535) + return -EINVAL; + + if (ax25_ctl.arg > 256) /* we probably want this */ + printk("ax25_ctl_ioctl(): Warning --- huge paclen %d", (int) ax25_ctl.arg); + ax25->paclen = ax25_ctl.arg; + break; + default: + return -EINVAL; + } + + return 0; +} + /* * Create an empty AX.25 control block. @@ -1501,7 +1617,9 @@ /* * Send the frame to the AX.25 auto-router */ +#ifdef notdef /* dl1bke 960310 */ ax25_rt_rx_frame(&src, dev, &dp); +#endif /* * Ours perhaps ? @@ -1532,16 +1650,19 @@ if (dev == dev_out && (ax25_dev_get_value(dev, AX25_VALUES_DIGI) & AX25_DIGI_INBAND) == 0) { kfree_skb(skb, FREE_READ); - return 0; /* Hey, Alan: look what you're doing below! You forgot this return! */ + return 0; } + ax25_rt_rx_frame(&src, dev, &dp); + build_ax25_addr(skb->data, &src, &dest, &dp, type, MODULUS); #ifdef CONFIG_FIREWALL if (call_fw_firewall(PF_AX25, skb, skb->data) != FW_ACCEPT) { kfree_skb(skb, FREE_READ); return 0; } -#endif +#endif + skb->arp = 1; ax25_queue_xmit(skb, dev_out, SOPRI_NORMAL); } else { @@ -1581,12 +1702,14 @@ switch (skb->data[1]) { #ifdef CONFIG_INET case AX25_P_IP: + ax25_rt_rx_frame(&src, dev, &dp); skb_pull(skb,2); /* drop PID/CTRL */ ax25_ip_mode_set(&src, dev, 'D'); ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ break; case AX25_P_ARP: + ax25_rt_rx_frame(&src, dev, &dp); skb_pull(skb,2); arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ break; @@ -1597,6 +1720,7 @@ if (sk->rmem_alloc >= sk->rcvbuf) { kfree_skb(skb, FREE_READ); } else { + ax25_rt_rx_frame(&src, dev, &dp); /* * Remove the control and PID. */ @@ -1640,6 +1764,7 @@ * free it immediately. This routine itself wakes the user context layers so we * do no further work */ + ax25_rt_rx_frame(&src, dev, &dp); if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) kfree_skb(skb, FREE_READ); @@ -1665,6 +1790,7 @@ /* b) received SABM(E) */ if ((sk = ax25_find_listener(&dest, dev, SOCK_SEQPACKET)) != NULL) { + ax25_rt_rx_frame(&src, dev, &dp); if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) { if (mine) ax25_return_dm(dev, &src, &dest, &dp); @@ -1688,6 +1814,8 @@ kfree_skb(skb, FREE_READ); return 0; } + + ax25_rt_rx_frame(&src, dev, &dp); if ((ax25 = ax25_create_cb()) == NULL) { ax25_return_dm(dev, &src, &dest, &dp); @@ -1698,8 +1826,10 @@ ax25_fillin_cb(ax25, dev); ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE); #else - if (mine) + if (mine) { + ax25_rt_rx_frame(&src, dev, &dp); ax25_return_dm(dev, &src, &dest, &dp); + } kfree_skb(skb, FREE_READ); return 0; @@ -2104,9 +2234,15 @@ case SIOCADDRT: case SIOCDELRT: + case SIOCAX25OPTRT: if (!suser()) return -EPERM; return ax25_rt_ioctl(cmd, (void *)arg); + + case SIOCAX25CTLCON: + if (!suser()) + return -EPERM; + return ax25_ctl_ioctl(cmd, arg); case SIOCGIFADDR: case SIOCSIFADDR: @@ -2128,6 +2264,7 @@ return(0); } + static int ax25_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { ax25_cb *ax25; @@ -2136,7 +2273,8 @@ int len = 0; off_t pos = 0; off_t begin = 0; - + int idletimer; + cli(); len += sprintf(buffer, "dest_addr src_addr dev st vs vr va t1 t2 t3 idle n2 rtt wnd paclen dama Snd-Q Rcv-Q\n"); @@ -2146,6 +2284,9 @@ devname = "???"; else devname = dev->name; + + idletimer = ax25->idletimer / (PR_SLOWHZ * 60); + idletimer += (ax25->idletimer && ax25->idletimer < ax25->idle)? 1:0; len += sprintf(buffer + len, "%-9s ", ax2asc(&ax25->dest_addr)); @@ -2159,7 +2300,7 @@ ax25->t2 / PR_SLOWHZ, ax25->t3timer / PR_SLOWHZ, ax25->t3 / PR_SLOWHZ, - (ax25->idletimer / (PR_SLOWHZ*60))+1, + idletimer, ax25->idle / (PR_SLOWHZ*60), ax25->n2count, ax25->n2, ax25->rtt / PR_SLOWHZ, @@ -2427,10 +2568,27 @@ if (bp[16] == AX25_P_IP) { mode = ax25_ip_mode_get((ax25_address *)(bp + 1), dev); - if (mode == 'V' || mode == 'v' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V')) { -/* skb_device_unlock(skb); *//* Don't unlock - it might vanish.. TCP will respond correctly to this lock holding */ - skb_pull(skb, AX25_HEADER_LEN - 1); /* Keep PID */ - ax25_send_frame(skb, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev); + if (mode == 'V' || mode == 'v' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V')) + { + /* + * This is a workaround to try and keep the device locking + * straight until skb->free=0 is abolished post 1.4. + * + * We clone the buffer and release the original thereby + * keeping it straight + * + * Note: we report 1 back so the caller will + * not feed the frame direct to the physical device + * We don't want that to happen. (It won't be upset + * as we have pulled the frame from the queue by + * freeing it). + */ + struct sk_buff *ourskb=skb_clone(skb, GFP_ATOMIC); + dev_kfree_skb(skb, FREE_READ); + if(ourskb==NULL) + return 1; + skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ + ax25_send_frame(ourskb, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev); return 1; } } diff -u --recursive --new-file v1.3.74/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v1.3.74/linux/net/ax25/ax25_in.c Wed Mar 13 10:09:26 1996 +++ linux/net/ax25/ax25_in.c Sat Mar 16 13:52:11 1996 @@ -303,7 +303,6 @@ ax25_send_control(ax25, UA, pf, C_RESPONSE); if (ax25->dama_slave) { ax25->state = AX25_STATE_0; - ax25->dama_slave = 0; ax25_dama_off(ax25); if (ax25->sk != NULL) { @@ -319,7 +318,6 @@ case UA: if (pf) { ax25->state = AX25_STATE_0; - ax25->dama_slave = 0; ax25_dama_off(ax25); if (ax25->sk != NULL) { @@ -335,7 +333,6 @@ case DM: if (pf) { ax25->state = AX25_STATE_0; - ax25->dama_slave = 0; ax25_dama_off(ax25); if (ax25->sk != NULL) { @@ -414,7 +411,6 @@ ax25_send_control(ax25, UA, pf, C_RESPONSE); ax25->t3timer = 0; ax25->state = AX25_STATE_0; - ax25->dama_slave = 0; ax25_dama_off(ax25); if (ax25->sk != NULL) { @@ -430,7 +426,6 @@ ax25_clear_queues(ax25); ax25->t3timer = 0; ax25->state = AX25_STATE_0; - ax25->dama_slave = 0; ax25_dama_off(ax25); if (ax25->sk) { ax25->sk->state = TCP_CLOSE; @@ -612,7 +607,6 @@ ax25_send_control(ax25, UA, pf, C_RESPONSE); ax25->t3timer = 0; ax25->state = AX25_STATE_0; - ax25->dama_slave = 0; ax25_dama_off(ax25); if (ax25->sk != NULL) { @@ -628,7 +622,6 @@ ax25_clear_queues(ax25); ax25->t3timer = 0; ax25->state = AX25_STATE_0; - ax25->dama_slave = 0; ax25_dama_off(ax25); if (ax25->sk != NULL) { diff -u --recursive --new-file v1.3.74/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c --- v1.3.74/linux/net/ax25/ax25_route.c Wed Mar 13 10:09:26 1996 +++ linux/net/ax25/ax25_route.c Sat Mar 16 13:52:11 1996 @@ -34,6 +34,9 @@ * Joerg(DL1BKE) changed routing for IP datagram and VC to use a default * route if available. Does not overwrite default routes * on route-table overflow anymore. + * Joerg(DL1BKE) fixed AX.25 routing of IP datagram and VC, new ioctl() + * "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag + * on routes. */ #include @@ -60,7 +63,7 @@ #include #include -#define AX25_ROUTE_MAX 40 +#define AX25_ROUTE_MAX 128 static struct ax25_route { struct ax25_route *next; @@ -70,6 +73,7 @@ struct timeval stamp; int n; char ip_mode; + char perm; } *ax25_route = NULL; static struct ax25_dev { @@ -78,13 +82,36 @@ unsigned short values[AX25_MAX_VALUES]; } *ax25_device = NULL; +static struct ax25_route * ax25_find_route(ax25_address *addr); + /* - * FIXME: heard and routing table should be two lists. The routing table - * should be updated by connects only. (WAMPES way of doing it) + * small macro to drop non-digipeated digipeaters and reverse path + */ + +static inline void ax25_route_invert(ax25_digi *in, ax25_digi *out) +{ + int k; + for (k = 0; k < in->ndigi; k++) + if (!in->repeated[k]) + break; + in->ndigi = k; + ax25_digi_invert(in, out); + +} + +/* + * dl1bke 960310: new behaviour: + * + * * try to find an existing route to 'src', if found: + * - if the route was added manually don't adjust the timestamp + * - if this route is 'permanent' just do some statistics and return + * - overwrite device and digipeater path + * * no existing route found: + * - try to alloc a new entry + * - overwrite the oldest, not manually added entry if this fails. + * + * * updated on receiption of frames directed to us _only_ * - * routing table should accept a new route to the same destination - * if the old one was added manually. Nevertheless we should still - * be able to add permanent routes. (dl1bke) */ void ax25_rt_rx_frame(ax25_address *src, struct device *dev, ax25_digi *digi) @@ -102,11 +129,30 @@ if (count == 0 || oldest->stamp.tv_sec == 0 || (ax25_rt->stamp.tv_sec != 0 && ax25_rt->stamp.tv_sec < oldest->stamp.tv_sec)) oldest = ax25_rt; - if (ax25cmp(&ax25_rt->callsign, src) == 0 && ax25_rt->dev == dev) { + if (ax25cmp(&ax25_rt->callsign, src) == 0) { if (ax25_rt->stamp.tv_sec != 0) ax25_rt->stamp = xtime; - ax25_rt->n++; - return; + + if (ax25_rt->perm == AX25_RT_PERMANENT) { + ax25_rt->n++; + return; + } + + ax25_rt->dev = dev; + if (digi == NULL) { + /* drop old digipeater list */ + if (ax25_rt->digipeat != NULL) { + kfree_s(ax25_rt->digipeat, sizeof(ax25_digi)); + ax25_rt->digipeat = NULL; + } + return; + } + + if (ax25_rt->digipeat == NULL && (ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) + return; + + ax25_route_invert(digi, ax25_rt->digipeat); + return; } count++; @@ -122,20 +168,23 @@ if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL) return; /* No space */ } - + ax25_rt->callsign = *src; ax25_rt->dev = dev; ax25_rt->digipeat = NULL; ax25_rt->stamp = xtime; ax25_rt->n = 1; ax25_rt->ip_mode = ' '; + ax25_rt->perm = AX25_RT_DYNAMIC; if (digi != NULL) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { kfree_s(ax25_rt, sizeof(struct ax25_route)); return; } - *ax25_rt->digipeat = *digi; + + ax25_route_invert(digi, ax25_rt->digipeat); + /* used to be: *ax25_rt->digipeat = *digi; */ } if (ax25_rt != oldest) { @@ -183,6 +232,7 @@ unsigned long flags; struct ax25_route *s, *t, *ax25_rt; struct ax25_routes_struct route; + struct ax25_route_opt_struct rt_option; struct device *dev; int i, err; @@ -223,6 +273,7 @@ ax25_rt->stamp.tv_sec = 0; ax25_rt->n = 0; ax25_rt->ip_mode = ' '; + ax25_rt->perm = AX25_RT_DYNAMIC; if (route.digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { kfree_s(ax25_rt, sizeof(struct ax25_route)); @@ -272,6 +323,40 @@ } } break; + case SIOCAX25OPTRT: + if ((err = verify_area(VERIFY_READ, arg, sizeof(rt_option))) != 0) + return err; + memcpy_fromfs(&rt_option, arg, sizeof(rt_option)); + if ((dev = ax25rtr_get_dev(&rt_option.port_addr)) == NULL) + return -EINVAL; + ax25_rt = ax25_route; + while (ax25_rt != NULL) { + if (ax25_rt->dev == dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) { + switch(rt_option.cmd) { + case AX25_SET_RT_PERMANENT: + ax25_rt->perm = (char) rt_option.arg; + ax25_rt->stamp.tv_sec = 0; + break; + case AX25_SET_RT_IPMODE: + switch (rt_option.arg) { + case AX25_RT_IPMODE_DEFAULT: + ax25_rt->ip_mode = ' '; + break; + case AX25_RT_IPMODE_DATAGRAM: + ax25_rt->ip_mode = 'D'; + break; + case AX25_RT_IPMODE_VC: + ax25_rt->ip_mode = 'V'; + break; + default: + return -EINVAL; + } + break; + } + } + ax25_rt = ax25_rt->next; + } + break; } return 0; @@ -288,7 +373,7 @@ cli(); - len += sprintf(buffer, "callsign dev count time mode digipeaters\n"); + len += sprintf(buffer, "callsign dev count time mode F digipeaters\n"); for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0) @@ -314,6 +399,20 @@ len += sprintf(buffer + len, " *"); break; } + + switch (ax25_rt->perm) { + case AX25_RT_DYNAMIC: + if (ax25_rt->stamp.tv_sec == 0) + len += sprintf(buffer + len, " M"); + else + len += sprintf(buffer + len, " "); + break; + case AX25_RT_PERMANENT: + len += sprintf(buffer + len, " P"); + break; + default: + len += sprintf(buffer + len, " ?"); + } if (ax25_rt->digipeat != NULL) for (i = 0; i < ax25_rt->digipeat->ndigi; i++) @@ -378,15 +477,15 @@ } /* - * Find which interface to use. + * Find AX.25 route */ -int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) + +static struct ax25_route * ax25_find_route(ax25_address *addr) { struct ax25_route *ax25_spe_rt = NULL; struct ax25_route *ax25_def_rt = NULL; struct ax25_route *ax25_rt; - ax25_address *call; - + /* * Bind to the physical interface we heard them on, or the default * route if non is found; @@ -399,12 +498,41 @@ } if (ax25_spe_rt != NULL) - ax25_rt = ax25_spe_rt; - else if (ax25_def_rt != NULL) - ax25_rt = ax25_def_rt; - else - return -EHOSTUNREACH; + return ax25_spe_rt; + + return ax25_def_rt; +} +/* + * Adjust path: If you specify a default route and want to connect + * a target on the digipeater path but w/o having a special route + * set before, the path has to be truncated from your target on. + */ + +static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat) +{ + int k; + + for (k = 0; k < digipeat->ndigi; k++) { + if (ax25cmp(addr, &digipeat->calls[k]) == 0) + break; + } + + digipeat->ndigi = k; +} + + +/* + * Find which interface to use. + */ +int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) +{ + struct ax25_route *ax25_rt; + ax25_address *call; + + if ((ax25_rt = ax25_find_route(addr)) == NULL) + return -EHOSTUNREACH; + if ((call = ax25_findbyuid(current->euid)) == NULL) { if (ax25_uid_policy && !suser()) return -EPERM; @@ -419,6 +547,7 @@ if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) return -ENOMEM; *ax25->digipeat = *ax25_rt->digipeat; + ax25_adjust_path(addr, ax25->digipeat); } if (ax25->sk != NULL) @@ -435,13 +564,7 @@ { struct ax25_route *ax25_rt; - for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL) - break; - - if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL) - break; - } + ax25_rt = ax25_find_route(addr); if (ax25_rt == NULL || ax25_rt->digipeat == NULL) return; @@ -451,30 +574,25 @@ ax25->device = ax25_rt->dev; *ax25->digipeat = *ax25_rt->digipeat; + ax25_adjust_path(addr, ax25->digipeat); } void ax25_dg_build_path(struct sk_buff *skb, ax25_address *addr, struct device *dev) { struct ax25_route *ax25_rt; + ax25_digi digipeat; ax25_address src, dest; unsigned char *bp; int len; - /* - * dl1bke 960301: use the default route if available - * - */ - - for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL) - break; - if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL) - break; - } - - - if (ax25_rt == NULL ||ax25_rt->digipeat == NULL) + + ax25_rt = ax25_find_route(addr); + if (ax25_rt == NULL || ax25_rt->digipeat == NULL) return; + + digipeat = *ax25_rt->digipeat; + + ax25_adjust_path(addr, &digipeat); len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN; @@ -485,6 +603,7 @@ memcpy(&dest, skb->data + 1, AX25_ADDR_LEN); memcpy(&src, skb->data + 8, AX25_ADDR_LEN); + bp = skb_push(skb, len); *bp++ = 0x00; /* KISS Data */ diff -u --recursive --new-file v1.3.74/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c --- v1.3.74/linux/net/ax25/ax25_subr.c Wed Mar 13 10:09:26 1996 +++ linux/net/ax25/ax25_subr.c Sat Mar 16 13:52:11 1996 @@ -513,9 +513,7 @@ void ax25_dama_on(ax25_cb *ax25) { - int count = ax25_dev_is_dama_slave(ax25->device); - - if (count == 0) { + if (ax25_dev_is_dama_slave(ax25->device) == 0) { if (ax25->sk != NULL && ax25->sk->debug) printk("ax25_dama_on: DAMA on\n"); ax25_kiss_cmd(ax25, 5, 1); @@ -524,9 +522,11 @@ void ax25_dama_off(ax25_cb *ax25) { - int count = ax25_dev_is_dama_slave(ax25->device); - - if (count == 0) { + if (ax25->dama_slave == 0) + return; + + ax25->dama_slave = 0; + if (ax25_dev_is_dama_slave(ax25->device) == 0) { if (ax25->sk != NULL && ax25->sk->debug) printk("ax25_dama_off: DAMA off\n"); ax25_kiss_cmd(ax25, 5, 0); diff -u --recursive --new-file v1.3.74/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c --- v1.3.74/linux/net/ax25/ax25_timer.c Wed Mar 13 10:09:26 1996 +++ linux/net/ax25/ax25_timer.c Sat Mar 16 13:52:11 1996 @@ -159,7 +159,8 @@ ax25->sk->state_change(ax25->sk); ax25->sk->dead = 1; } - + + ax25_reset_timer(ax25); return; } @@ -191,7 +192,6 @@ ax25->t3timer = 0; ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); - ax25->state = AX25_STATE_2; if (ax25->sk != NULL) { diff -u --recursive --new-file v1.3.74/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v1.3.74/linux/net/core/skbuff.c Wed Feb 14 14:37:20 1996 +++ linux/net/core/skbuff.c Sat Mar 16 13:52:11 1996 @@ -12,6 +12,15 @@ * Alan Cox : destructor hook for AF_UNIX etc. * Linus Torvalds : Better skb_clone. * Alan Cox : Added skb_copy. + * Alan Cox : Added all the changed routines Linus + * only put in the headers + * Ray VanTassle : Fixed --skb->lock in free + * + * TO FIX: + * The __skb_ routines ought to check interrupts are disabled + * when called, and bitch like crazy if not. Unfortunately I don't think + * we currently have a portable way to check if interrupts are off - + * Linus ??? * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,9 +29,7 @@ */ /* - * Note: There are a load of cli()/sti() pairs protecting the net_memory type - * variables. Without them for some reason the ++/-- operators do not come out - * atomic. Also with gcc 2.4.5 these counts can come out wrong anyway - use 2.5.8!! + * The functions in this file will not compile correctly with gcc 2.4.x */ #include @@ -224,6 +231,26 @@ restore_flags(flags); } +void __skb_queue_head(struct sk_buff_head *list_,struct sk_buff *newsk) +{ + struct sk_buff *list = (struct sk_buff *)list_; + + + IS_SKB(newsk); + IS_SKB_HEAD(list); + if (newsk->next || newsk->prev) + printk("Suspicious queue head: sk_buff on list!\n"); + + newsk->next = list->next; + newsk->prev = list; + + newsk->next->prev = newsk; + newsk->prev->next = newsk; + newsk->list = list_; + list_->qlen++; + +} + /* * Insert an sk_buff at the end of a list. */ @@ -252,6 +279,26 @@ restore_flags(flags); } +void __skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk) +{ + unsigned long flags; + struct sk_buff *list = (struct sk_buff *)list_; + + if (newsk->next || newsk->prev) + printk("Suspicious queue tail: sk_buff on list!\n"); + IS_SKB(newsk); + IS_SKB_HEAD(list); + + newsk->next = list; + newsk->prev = list->prev; + + newsk->next->prev = newsk; + newsk->prev->next = newsk; + + newsk->list = list_; + list_->qlen++; +} + /* * Remove an sk_buff from a list. This routine is also interrupt safe * so you can grab read and free buffers as another process adds them. @@ -288,6 +335,30 @@ return result; } +struct sk_buff *__skb_dequeue(struct sk_buff_head *list_) +{ + struct sk_buff *result; + struct sk_buff *list = (struct sk_buff *)list_; + + IS_SKB_HEAD(list); + + result = list->next; + if (result == list) { + return NULL; + } + + result->next->prev = list; + list->next = result->next; + + result->next = NULL; + result->prev = NULL; + list_->qlen--; + result->list = NULL; + + IS_SKB(result); + return result; +} + /* * Insert a packet before another one in a list. */ @@ -316,6 +387,29 @@ } /* + * Insert a packet before another one in a list. + */ + +void __skb_insert(struct sk_buff *old, struct sk_buff *newsk) +{ + IS_SKB(old); + IS_SKB(newsk); + + if(!old->next || !old->prev) + printk("insert before unlisted item!\n"); + if(newsk->next || newsk->prev) + printk("inserted item is already on a list.\n"); + + newsk->next = old; + newsk->prev = old->prev; + old->prev = newsk; + newsk->prev->next = newsk; + newsk->list = old->list; + newsk->list->qlen++; + +} + +/* * Place a packet after a given packet in a list. */ void skb_append(struct sk_buff *old, struct sk_buff *newsk) @@ -343,6 +437,25 @@ restore_flags(flags); } +void __skb_append(struct sk_buff *old, struct sk_buff *newsk) +{ + IS_SKB(old); + IS_SKB(newsk); + + if(!old->next || !old->prev) + printk("append before unlisted item!\n"); + if(newsk->next || newsk->prev) + printk("append item is already on a list.\n"); + + newsk->prev = old; + newsk->next = old->next; + newsk->next->prev = newsk; + old->next = newsk; + newsk->list = old->list; + newsk->list->qlen++; + +} + /* * Remove an sk_buff from its list. Works even without knowing the list it * is sitting on, which can be handy at times. It also means that THE LIST @@ -374,6 +487,25 @@ restore_flags(flags); } +void __skb_unlink(struct sk_buff *skb) +{ + IS_SKB(skb); + + if(skb->list) + { + skb->list->qlen--; + skb->next->prev = skb->prev; + skb->prev->next = skb->next; + skb->next = NULL; + skb->prev = NULL; + skb->list = NULL; + } +#ifdef PARANOID_BUGHUNT_MODE /* This is legal but we sometimes want to watch it */ + else + printk("skb_unlink: not a linked element\n"); +#endif +} + /* * Add data to an sk_buff */ @@ -649,7 +781,6 @@ n->next = n->prev = n->link3 = NULL; n->list = NULL; n->sk = NULL; - n->truesize = sizeof(*n); n->free = 1; n->tries = 0; n->lock = 0; @@ -745,10 +876,12 @@ save_flags(flags); cli(); - if(skb->lock==1) + if(skb->lock) + { net_locked--; - - if (!--skb->lock && (skb->free == 1 || skb->free == 3)) + skb->lock--; + } + if (!skb->lock && (skb->free == 1 || skb->free == 3)) { restore_flags(flags); kfree_skb(skb,mode); diff -u --recursive --new-file v1.3.74/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v1.3.74/linux/net/ipv4/af_inet.c Wed Mar 13 10:09:26 1996 +++ linux/net/ipv4/af_inet.c Sat Mar 16 13:52:11 1996 @@ -673,7 +673,7 @@ skb_queue_head_init(&sk->back_log); sock->data =(void *) sk; sk->dummy_th.doff = sizeof(sk->dummy_th)/4; - sk->ip_ttl=64; + sk->ip_ttl=ip_statistics.IpDefaultTTL; if(sk->type==SOCK_RAW && protocol==IPPROTO_RAW) sk->ip_hdrincl=1; else diff -u --recursive --new-file v1.3.74/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v1.3.74/linux/net/ipv4/arp.c Tue Mar 5 10:11:15 1996 +++ linux/net/ipv4/arp.c Sat Mar 16 13:52:11 1996 @@ -52,6 +52,7 @@ * Alan Cox : Missing unlock in device events. * Eckes : ARP ioctl control errors. * Alexey Kuznetsov: Arp free fix. + * Manuel Rodriguez: Gratutious ARP. */ /* RFC1122 Status: @@ -783,7 +784,7 @@ unsigned char *arp_ptr= (unsigned char *)(arp+1); struct arp_table *entry; struct arp_table *proxy_entry; - unsigned long hash; + unsigned long hash, grat=0; unsigned char ha[MAX_ADDR_LEN]; /* So we can enable ints again. */ unsigned char *sha,*tha; u32 sip,tip; @@ -928,6 +929,7 @@ * check if that someone else is one of our proxies. If it isn't, * we can toss it. */ + grat = (sip == tip) && (sha == tha); arp_fast_lock(); for (proxy_entry=arp_proxy_list; @@ -949,6 +951,12 @@ } if (proxy_entry) { + if (grat) + { + if(!(proxy_entry->flags&ATF_PERM)) + arp_destroy(proxy_entry); + goto gratuitous; + } memcpy(ha, proxy_entry->ha, dev->addr_len); arp_unlock(); arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha, sha); @@ -957,6 +965,8 @@ } else { + if (grat) + goto gratuitous; arp_unlock(); kfree_skb(skb, FREE_READ); return 0; @@ -989,6 +999,8 @@ arp_fast_lock(); +gratuitous: + hash = HASH(sip); for (entry=arp_tables[hash]; entry; entry=entry->next) @@ -1026,6 +1038,10 @@ /* * No entry found. Need to add a new entry to the arp table. */ + + if (grat) + goto end; + entry = (struct arp_table *)kmalloc(sizeof(struct arp_table),GFP_ATOMIC); if(entry == NULL) { @@ -1072,6 +1088,8 @@ /* * Replies have been sent, and entries have been added. All done. */ + +end: kfree_skb(skb, FREE_READ); arp_unlock(); return 0; diff -u --recursive --new-file v1.3.74/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v1.3.74/linux/net/ipv4/icmp.c Sat Mar 2 10:43:46 1996 +++ linux/net/ipv4/icmp.c Sat Mar 16 13:52:11 1996 @@ -358,7 +358,7 @@ break; case ICMP_PROT_UNREACH: /* printk(KERN_INFO "ICMP: %s:%d: protocol unreachable.\n", - in_ntoa(iph->daddr), ntohs(iph->protocol));*/ + in_ntoa(iph->daddr), (int)iph->protocol);*/ break; case ICMP_PORT_UNREACH: break; diff -u --recursive --new-file v1.3.74/linux/net/ipv4/packet.c linux/net/ipv4/packet.c --- v1.3.74/linux/net/ipv4/packet.c Wed Feb 28 11:50:17 1996 +++ linux/net/ipv4/packet.c Sat Mar 16 13:52:11 1996 @@ -5,6 +5,9 @@ * * PACKET - implements raw packet sockets. * + * Doesn't belong in IP but its currently too hooked into ip + * to seperate. + * * Version: @(#)packet.c 1.0.6 05/25/93 * * Authors: Ross Biro, @@ -30,6 +33,7 @@ * Richard Kooijman : Timestamp fixes. * Alan Cox : New buffers. Use sk->mac.raw. * Alan Cox : sendmsg/recvmsg support. + * Alan Cox : Protocol setting support * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -46,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -124,7 +129,8 @@ { struct sk_buff *skb; struct device *dev; - struct sockaddr *saddr=(struct sockaddr *)msg->msg_name; + struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name; + unsigned short proto=0; /* * Check the flags. @@ -139,8 +145,10 @@ if (saddr) { - if (msg->msg_namelen < sizeof(*saddr)) + if (msg->msg_namelen < sizeof(struct sockaddr)) return(-EINVAL); + if (msg->msg_namelen==sizeof(struct sockaddr_pkt)) + proto=saddr->spkt_protocol; } else return(-ENOTCONN); /* SOCK_PACKET must be sent giving an address */ @@ -149,8 +157,8 @@ * Find the device first to size check it */ - saddr->sa_data[13] = 0; - dev = dev_get(saddr->sa_data); + saddr->spkt_device[13] = 0; + dev = dev_get(saddr->spkt_device); if (dev == NULL) { return(-ENODEV); @@ -185,6 +193,7 @@ skb->free = 1; memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); skb->arp = 1; /* No ARP needs doing on this (complete) frame */ + skb->protocol = proto; /* * Now send it @@ -393,7 +402,7 @@ { int copied=0; struct sk_buff *skb; - struct sockaddr *saddr=(struct sockaddr *)msg->msg_name; + struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name; int err; if (sk->shutdown & RCV_SHUTDOWN) @@ -447,8 +456,9 @@ if (saddr) { - saddr->sa_family = skb->dev->type; - strncpy(saddr->sa_data,skb->dev->name, 15); + saddr->spkt_family = skb->dev->type; + strncpy(saddr->spkt_device,skb->dev->name, 15); + saddr->spkt_protocol = skb->protocol; } /* diff -u --recursive --new-file v1.3.74/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v1.3.74/linux/net/ipv4/route.c Sat Mar 2 10:43:46 1996 +++ linux/net/ipv4/route.c Sat Mar 16 13:52:12 1996 @@ -40,6 +40,7 @@ * * Olaf Erb : irtt wasnt being copied right. * Bjorn Ekwall : Kerneld route support. + * Alan Cox : Multicast fixed (I hope) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1556,6 +1557,11 @@ if (!(rth->rt_flags & RTF_GATEWAY)) rth->rt_gateway = rth->rt_dst; + /* + * Multicast is never gatewayed. + */ + if (MULTICAST(daddr)) + rth->rt_gateway = rth->rt_dst; if (ip_rt_lock == 1) rt_cache_add(hash, rth); @@ -1714,7 +1720,7 @@ * Remove a route, as requested by the user. */ -static int rt_kill(struct rtentry *r) +int ip_rt_kill(struct rtentry *r) { struct sockaddr_in *trg; struct sockaddr_in *msk; @@ -1764,7 +1770,7 @@ if (err) return err; memcpy_fromfs(&rt, arg, sizeof(struct rtentry)); - return (cmd == SIOCDELRT) ? rt_kill(&rt) : ip_rt_new(&rt); + return (cmd == SIOCDELRT) ? ip_rt_kill(&rt) : ip_rt_new(&rt); } return -EINVAL; diff -u --recursive --new-file v1.3.74/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v1.3.74/linux/net/ipv4/tcp.c Wed Mar 13 10:09:27 1996 +++ linux/net/ipv4/tcp.c Fri Mar 15 09:32:32 1996 @@ -1042,6 +1042,11 @@ copy = sk->mss; if (copy > seglen) copy = seglen; + if (copy <= 0) + { + printk("TCP: **bug**: copy=%d, sk->mss=%d\n", copy, sk->mss); + return -EFAULT; + } /* * We should really check the window here also. diff -u --recursive --new-file v1.3.74/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v1.3.74/linux/net/ipv4/tcp_input.c Wed Mar 13 10:09:27 1996 +++ linux/net/ipv4/tcp_input.c Sat Mar 16 19:12:31 1996 @@ -26,6 +26,8 @@ #include #include +#include + /* * Policy code extracted so its now seperate */ @@ -856,10 +858,10 @@ */ if (skb_peek(&sk->write_queue) != NULL) { - if (after (sk->window_seq+1, sk->write_queue.next->end_seq) && + if (!before(sk->window_seq, sk->write_queue.next->end_seq) && (sk->retransmits == 0 || sk->ip_xmit_timeout != TIME_WRITE || - before(sk->write_queue.next->end_seq, sk->rcv_ack_seq + 1)) + !after(sk->write_queue.next->end_seq, sk->rcv_ack_seq)) && sk->packets_out < sk->cong_window) { /* @@ -1249,25 +1251,34 @@ * Ok, we found new data, update acked_seq as * necessary (and possibly send the actual * ACK packet). - * + */ + sk->acked_seq = ack_seq; + + /* * rules for delaying an ack: * - delay time <= 0.5 HZ - * - we don't have a window update to send * - must send at least every 2 full sized packets + * - we don't have a window update to send + * + * We handle the window update in the actual read + * side, so we only have to worry about the first two. */ - sk->acked_seq = ack_seq; - if (!sk->delay_acks || - /* sk->ack_backlog >= sk->max_ack_backlog || */ - sk->bytes_rcv > sk->max_unacked || th->fin || - sk->ato > HZ/2) { + if (!sk->delay_acks || th->fin) { tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); } - else - { + else + { + int timeout = sk->ato; + if (timeout > HZ/2) + timeout = HZ/2; + if (sk->bytes_rcv > sk->max_unacked) { + timeout = 0; + mark_bh(TIMER_BH); + } sk->ack_backlog++; - if(sk->debug) + if(sk->debug) printk("Ack queued.\n"); - tcp_reset_xmit_timer(sk, TIME_WRITE, sk->ato); + tcp_reset_xmit_timer(sk, TIME_WRITE, timeout); } } } diff -u --recursive --new-file v1.3.74/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v1.3.74/linux/net/ipv4/tcp_output.c Wed Mar 13 10:09:27 1996 +++ linux/net/ipv4/tcp_output.c Fri Mar 15 09:58:40 1996 @@ -230,10 +230,10 @@ */ while((skb = skb_peek(&sk->write_queue)) != NULL && - before(skb->end_seq, sk->window_seq + 1) && + !after(skb->end_seq, sk->window_seq) && (sk->retransmits == 0 || sk->ip_xmit_timeout != TIME_WRITE || - before(skb->end_seq, sk->rcv_ack_seq + 1)) + !after(skb->end_seq, sk->rcv_ack_seq)) && sk->packets_out < sk->cong_window) { IS_SKB(skb); diff -u --recursive --new-file v1.3.74/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v1.3.74/linux/net/unix/af_unix.c Fri Mar 15 16:03:22 1996 +++ linux/net/unix/af_unix.c Sat Mar 16 13:52:12 1996 @@ -24,12 +24,12 @@ * Alan Cox : Sorted out a proper draft version of * file descriptor passing hacked up from * Mike Shaver's work. - * + * Marty Leisner : Fixes to fd passing + * Nick Nevin : recvmsg bugfix. * * Known differences from reference BSD that was tested: * * [TO FIX] - * No fd passing yet. * ECONNREFUSED is not returned from one end of a connected() socket to the * other the moment one end closes. * fstat() doesn't return st_dev=NODEV, and give the blksize as high water mark @@ -40,6 +40,7 @@ * accept() returns 0 length path for an unbound connector. BSD returns 16 * and a null first byte in the path (but not for gethost/peername - BSD bug ??) * socketpair(...SOCK_RAW..) doesnt panic the kernel. + * BSD af_unix apprently has connect forgetting to block properly. */ #include @@ -1156,7 +1157,7 @@ *addr_len=sizeof(short); } - num=min(skb->len,size-copied); + num=min(skb->len,len-done); memcpy_tofs(sp, skb->data, num); if (skb->h.filp!=NULL) diff -u --recursive --new-file v1.3.74/linux/scripts/header.tk linux/scripts/header.tk --- v1.3.74/linux/scripts/header.tk Fri Mar 15 16:03:22 1996 +++ linux/scripts/header.tk Sat Mar 16 13:52:12 1996 @@ -287,7 +287,7 @@ frame $w.x$line option_name $w $mnum $line $text $variable menubutton $w.x$line.x -textvariable $variable -menu \ - $w.x$line.x.menu -relief raised -indicatoron 1 \ + $w.x$line.x.menu -relief raised \ -width 15 -anchor w pack $w.x$line.x -anchor w -side right -fill y pack $w.x$line -anchor w -fill both -expand on @@ -301,70 +301,7 @@ #nothing to do for now. } -proc dohelp_old_version_ignore_me {w varname } { - catch {destroy $w} - toplevel $w -class Dialog - - set filefound 0 - set found 0 - set lineno 0 - if { [file readable Documentation/Configure.help] == 1} then { - set f [open Documentation/Configure.help r] - set filefound 1 - while {![eof $f]} { - gets $f line - set line1 [string trim $line] - if { $line1 == $varname } then { - set found 1 - } else { - if { $found == 0 } continue - } - if { [string length $line1 ] == 0 } break - if { [string range $line1 0 0 ] == "#" } continue - if { $lineno == 0 } then { - append message $line1 - append message ":" - } else { - append message " " - append message $line1 - } - set lineno [expr $lineno + 1] - } - close $f - } - - if { $found == 0 } then { - if { $filefound == 0 } then { - message $w.m -width 750 -aspect 300 -text \ - "No help available - unable to open file Documentation/Configure.help. This file is available from http://math-www.uni-paderborn.de/~axel/config_help.html or ftp://sunsite.unc.edu/pub/Linux/kernel/config/krnl_cnfg_hlp_1.X.XX.tgz" -relief raised - } else { - message $w.m -width 400 -aspect 300 -text \ - "No help available for $varname" -relief raised - } - label $w.bm -bitmap error - pack $w.bm $w.m -pady 10 -side top -padx 10 - wm title $w "RTFM" - } else { - message $w.m -width 400 -aspect 300 -text $message \ - -relief raised - label $w.bm -bitmap info - pack $w.bm $w.m -pady 10 -side top -padx 10 - wm title $w "Configuration help" - } - set oldFocus [focus] - frame $w.f - button $w.f.back -text "OK" -activebackground green \ - -width 10 -command "destroy $w; focus $oldFocus" - pack $w.f.back -side bottom -pady 10 -anchor s - pack $w.f -pady 10 -side top -padx 10 -anchor s - focus $w - global winx; global winy - set winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30] - wm geometry $w +$winx+$winy -} - - -proc dohelp {w varname } { +proc dohelp {w var } { catch {destroy $w} toplevel $w -class Dialog @@ -374,22 +311,21 @@ if { [file readable Documentation/Configure.help] == 1} then { set filefound 1 - set message [exec awk " - BEGIN { - start=0; - } - /^$varname\[ \]*\$/ { - start=1; - printf(\"%s:\\n\\n\",\$0); - next; - } - !/^\[ \]/ { - start=0; - } - /^\[ \]*/ && start==1 { - gsub(\"^\[ \]*\",\"\"); - printf(\"%s \",\$0); - } + set message [exec sed -n " + /^$var\[ \]*\$/,\${ + /^$var\[ \]*\$/c\\ +${var}:\\ + + /^#.*/d + /^\[ \]*\$/bL + H + } + d + :L x + s/\\n // + s/\\n / /g + p + q " Documentation/Configure.help] set found [expr [string length "$message"] > 0] } @@ -402,7 +338,7 @@ "No help available - unable to open file Documentation/Configure.help. This file should have come with your kernel." } else { message $w.f1.m -width 400 -aspect 300 -relief flat -text \ - "No help available for $varname" + "No help available for $var" } label $w.f1.bm -bitmap error wm title $w "RTFM" diff -u --recursive --new-file v1.3.74/linux/scripts/tkcond.c linux/scripts/tkcond.c --- v1.3.74/linux/scripts/tkcond.c Wed Mar 13 10:09:28 1996 +++ linux/scripts/tkcond.c Sat Mar 16 13:52:12 1996 @@ -123,7 +123,7 @@ * be one operator inbetween. */ cond2 = cond->next->next; - sprintf(tmpbuf, "%d", cond->variable.cfg->choice_value); + strcpy(tmpbuf, cond->variable.cfg->label); if( strcmp(cond2->variable.str, "y") == 0 ) { diff -u --recursive --new-file v1.3.74/linux/scripts/tkgen.c linux/scripts/tkgen.c --- v1.3.74/linux/scripts/tkgen.c Wed Mar 13 10:09:29 1996 +++ linux/scripts/tkgen.c Sat Mar 16 13:52:12 1996 @@ -14,9 +14,15 @@ * Avery Pennarun - The int and hex config.in commands work right. * - Choice buttons are more user-friendly. * - Disabling a text entry line greys it out properly. - * - dep_tristate now works like in Configure. (not pretty) + * - dep_tristate now works like in Configure. (not pretty) * - No warnings in gcc -Wall. (Fixed some "interesting" bugs.) * - Faster/prettier "Help" lookups. + * + * 1996 03 15 + * Avery Pennarun - Added new sed script from Axel Boldt to make help even + * faster. (Actually awk is downright slow on some machines.) + * - Fixed a bug I introduced into Choice dependencies. Thanks + * to Robert Krawitz for pointing this out. * * TO DO: * - clean up - there are useless ifdef's everywhere.