diff -urN 2.3.29pre1/Documentation/00-INDEX 2.3.29pre1-ikd/Documentation/00-INDEX --- 2.3.29pre1/Documentation/00-INDEX Tue Sep 14 14:34:22 1999 +++ 2.3.29pre1-ikd/Documentation/00-INDEX Mon Nov 22 16:56:22 1999 @@ -33,6 +33,8 @@ - directory with information on the CD-ROM drivers that Linux has. cpqarray.txt - info on using Compaq's SMART2 Intelligent Disk Array Controllers. +debugging.txt + - summary of the integrated kernel debugging patch devices.tex - LaTeX source listing of all the nodes in /dev/ with major minor #'s devices.txt @@ -77,6 +79,8 @@ - summary listing of command line / boot prompt args for the kernel. kmod.txt - info on the kernel module loader/unloader (kerneld replacement). +ktrace.txt + - tracing kernel procedure flow and timing. locks.txt - info on file locking implementations, flock() vs. fcntl(), etc. logo.gif diff -urN 2.3.29pre1/Documentation/Configure.help 2.3.29pre1-ikd/Documentation/Configure.help --- 2.3.29pre1/Documentation/Configure.help Sun Nov 21 03:20:43 1999 +++ 2.3.29pre1-ikd/Documentation/Configure.help Mon Nov 22 16:56:22 1999 @@ -11023,6 +11023,155 @@ differs slightly from OSS/Free, so PLEASE READ Documentation/sound/sonicvibes. +Kernel debugging support +CONFIG_KERNEL_DEBUGGING + Shows low level kernel tracing, debugging and general hacking tools. + Mere mortals say N. + +Debug kernel stack overflows +CONFIG_DEBUG_KSTACK + If you see "kernel stack corruption. Aiee" messages, and a kernel + hacker told you to 'switch on kernel stack debugging', then this + is the right option =B-) + Do 'make clean' after changing this option! + For normal systems, this option adds noticeable overhead, so say N. + +Kernel Stack Meter +CONFIG_KSTACK_METER + With this option set, the kernel will log the minimum stack left + following boot of the machine, and the function that was executing + when the machine reached that value. This is useful for determining + how much stack the kernel needs. It also allow us to detect if there + is some piece of code that could be optimized to run without eating + a lot of stack. To see the current values: + `cat /proc/sys/debug/kstack-meter' + To reinitialize the counter to default: + `echo -1 0 >/proc/sys/debug/kstack-meter' + The first integer is the minimum stack size left. The second is the + function that was running when that condition was reached. + For normal systems, this option adds noticeable overhead, so say N. + + With this option enabled the IA32 NMI watchdog will be disabled. + +Kernel stack overflow threshold +CONFIG_KSTACK_THRESHOLD + If the stack has less bytes than this left, assume you are headed for an + overflow. + +Detect software lockups +CONFIG_DEBUG_SOFTLOCKUP + If you see strange lockups and a kernel hacker told you to 'switch + on software lockup detection', then this is the right option =B-) + Do 'make clean' after changing this option! + For normal systems, this option adds noticeable overhead, so say N. + +Deadlock threshold +CONFIG_SOFTLOCKUP_THRESHOLD + The number of procedure calls a process can make without going + through schedule. Any process that does more calls than this number + is "looping". Alas it does not catch inline procedure calls. + +Enable kernel tracer +CONFIG_TRACE + For kernel hackers who want to know where the path of execution goes + and how much time the kernel spends in the various procedures. The + trace is stored in /proc/trace (say Y to "/proc filesystem support"!) + and in order to read it, you need the ktrace program, see + scripts/ktrace. For normal systems, this option adds noticeable + overhead, so say N. + + With this option enabled the IA32 NMI watchdog will be disabled. + +Size of trace buffer +CONFIG_TRACE_SIZE + The number of trace entries to store in the kernel. + +Trace timestamp +CONFIG_TRACE_TIMESTAMP + Attempts to store an accurate timestamp against each trace entry, + scripts/ktrace will calculate the interval between successive + entries. On processors where an accurate timestamp is not available, + the jiffie counter is used instead. Jiffies are almost useless + because most procedure calls run in less than one jiffie but it is + better than nothing. Recommended if you want procedure times and your + cpu supports an accurate timestamp, however it adds 64 or 32 bits to + each trace entry. + +Truncated trace timestamp +CONFIG_TRACE_TRUNCTIME + If the full timestamp field is taking up too much room (64 bits per + entry on x86) and you are willing to risk wraparound of the + timestamp, say Y here. Only the last 32 bits of the timestamp will + be stored. Unless you are *really* short on storage, say N. + +Process ID for trace +CONFIG_TRACE_PID + If you want to know which process a trace table entry is for, say Y + here. Recommended but adds sizeof(pid_t) to each trace table entry. + +Cpu ID for tracer +CONFIG_TRACE_CPU + If you want to know which cpu a trace table entry is for, say Y here. + Only effective on SMP systems. Recommended but it adds sizeof(int) + to each trace table entry. + +Memleak, Kernel memory leak detection support +CONFIG_MEMLEAK + For kernel hackers who want to track down memory leaks in the + kernel, say Y here and look at scripts/memleak. Mere mortals say N. + +GCC profiling support +CONFIG_PROFILE_GCC + This option improves the kernel profiling by using the gcc profiling feature. + With this option enabled the kernel will use gcc profiling, not once + each timer interrupt. This option enabled will add a lot of overhead to + the kernel. If you want to run this kernel for production and you want + profiling, it's recommended that you use normal profiling and that you + say N here. + +Print %eip to resolve symbols from locks +CONFIG_PRINT_EIP + This allows the kernel to print on the console the %eip address every + time a kernel function is called. This facilitates the resolution + of addresses after a complete machine lockup. A system with this + enabled should only be run in console mode, not X. The %eip addresses + are only displayed on virtual consoles (/dev/tty0...), and not + on serial consoles. This displays a column for each CPU and a one-up + counter for each CPU. If your system locks up while this feature is + enabled, for each CPU record the first column (the address) sorted + by the second column (the one-up counter). ksymoops or a manual + trace of Symbols.map may then be used to determine the lockup. + For normal systems, this option adds noticeable overhead, so say N. + Say Y here if a kernel hacker tell you to do that. + +Get Free Pages poisoner +CONFIG_GFP_POISON + Enable this option to make memory corruption at the GFP layer a bit + more visible. + +SLAB poisoner +CONFIG_SLAB_POISON + Enable this option to make memory corruption at the SLAB layer a bit + more visible. + +Semapahore deadlock detector +CONFIG_SEMAPHORE_DEADLOCK + With this option enabled, the first down() that will block for more than + 20 sec will generate an Oops that will allow you to know the code path + that deadlocked. + +Kernel Debugging support +CONFIG_KDB + This option provides a built-in kernel debugger. The built-in + kernel debugger contains commands which allow memory to be examined, + instructions to be disassembled and breakpoints to be set. For details, + see Documentation/kdb/kdb.mm and the manual pages kdb_bt, kdb_ss, etc. + Kdb can also be used via the serial port. Set up the system to + have a serial console (see Documentation/serial-console.txt). + The Control-A key sequence on the serial port will cause the + kernel debugger to be entered with input from the serial port and + output to the serial console. To enable kdb, say Y here. + Rockwell WaveArtist CONFIG_SOUND_WAVEARTIST Say Y here to include support for the Rockwell WaveArtist sound diff -urN 2.3.29pre1/Documentation/Configure.help.orig 2.3.29pre1-ikd/Documentation/Configure.help.orig --- 2.3.29pre1/Documentation/Configure.help.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/Configure.help.orig Sun Nov 21 03:20:43 1999 @@ -0,0 +1,13273 @@ +# Maintained by Axel Boldt (boldt@math.ucsb.edu) +# +# This version of the Linux kernel configuration help texts +# corresponds to the kernel versions 2.3.x. +# +# Translations of this file available on the WWW: +# +# - Japanese, maintained by the JF Project (JF@linux.or.jp), at +# http://www.linux.or.jp/JF/JFdocs/Configure.help/ +# - Russian, by kaf@linux.nevod.perm.su, at +# http://nevod.perm.su/service/linux/doc/kernel/Configure.help +# - French, by Tane Pierre (tanep@bigfoot.com), at +# http://www.kernelfr.org +# - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at +# http://visar.csustan.edu/~carlos/ +# - Italian, by Alessandro Rubini (rubini@linux.it), at +# ftp://ftp-pavia1.linux.it/pub/linux/Configure.help +# - Polish, by Cezar Cichocki (cezar@cs.net.pl), at +# http://www.cs.net.pl/~cezar/Kernel +# - German, by SuSE, at http://www.suse.de/~ke/kernel . This patch +# includes infrastructure to support different languages as well. +# +# To access a document on the WWW, you need to have a direct Internet +# connection and a browser program such as netscape or lynx. If you +# only have email access, you can still use FTP and WWW servers: send +# an email to mail-server@rtfm.mit.edu with the text +# send usenet/news.answers/internet-services/access-via-email +# in the body of the message. +# +# Information about what a kernel is, what it does, how to patch and +# compile it and much more is contained in the Kernel-HOWTO, available +# at http://metalab.unc.edu/mdw/linux.html#howto . Before you start +# compiling, make sure that you have the necessary versions of all +# programs and libraries required to compile and run this kernel; they +# are listed in the file Documentation/Changes. Make sure to read the +# toplevel kernel README file as well. +# +# Format of this file: descriptionvariablehelp text. If +# the question being documented is of type "choice", we list only the +# first occurring config variable. The help texts may contain empty +# lines, but every non-empty line must be indented two positions. +# Order of the help texts does not matter, however, no variable should +# be documented twice: if it is, only the first occurrence will be +# used by Configure. We try to keep the help texts of related variables +# close together. Lines starting with `#' are ignored. To be nice to +# menuconfig, limit your line length to 70 characters. Use emacs' +# kfill.el to edit and ispell.el to spell check this file or you lose. +# +# If you add a help text to this file, please try to be as gentle as +# possible. Don't use unexplained acronyms and generally write for the +# hypothetical ignorant but intelligent user who has just bought a PC, +# removed Windows, installed Linux and is now recompiling the kernel +# for the first time. Tell them what to do if they're unsure. Technical +# information should go in a README in the Documentation directory. +# Mention all the relevant READMEs and HOWTOs in the help text. +# Repetitions are fine since the help texts are not meant to be read +# in sequence. +# +# All this was shamelessly stolen from several different sources. Many +# thanks to all the contributors. Feel free to use these help texts in +# your own kernel configuration tools. The texts are copyrighted (c) +# 1995-1999 by Axel Boldt and many others and are governed by the GNU +# General Public License. + +Prompt for development and/or incomplete code/drivers +CONFIG_EXPERIMENTAL + Some of the various things that Linux supports (such as network + drivers, filesystems, network protocols, etc.) can be in a state + of development where the functionality, stability, or the level of + testing is not yet high enough for general use. This is usually + known as the "alpha-test" phase amongst developers. If a feature is + currently in alpha-test, then the developers usually discourage + uninformed widespread use of this feature by the general public to + avoid "Why doesn't this work?" type mail messages. However, active + testing and use of these systems is welcomed. Just be aware that it + may not meet the normal level of reliability or it may fail to work + in some special cases. Detailed bug reports from people familiar + with the kernel internals are usually welcomed by the developers + (before submitting bug reports, please read the documents README, + MAINTAINERS, REPORTING_BUGS, Documentation/BUG-HUNTING, and + Documentation/oops-tracing.txt in the kernel source). + + This option will also make obsoleted drivers available. These are + drivers that have been replaced by something else, and/or are + scheduled to be removed in a future kernel release. + + Unless you intend to help test and develop a feature or driver that + falls into this category, or you have a situation that requires + using these features, you should probably say N here, which will + cause this configure script to present you with fewer choices. If + you say Y here, you will be offered the choice of using features or + drivers that are currently considered to be in the alpha-test phase. + +Symmetric Multi Processing +CONFIG_SMP + This enables support for systems with more than one CPU. If you have + a system with only one CPU, like most personal computers, say N. If + you have a system with more than one CPU, say Y. + + If you say N here, the kernel will run on single and multiprocessor + machines, but will use only one CPU of a multiprocessor machine. If + you say Y here, the kernel will run on many, but not all, + singleprocessor machines. On a singleprocessor machine, the kernel + will run faster if you say N here. + + Note that if you say Y here and choose architecture "586" or + "Pentium" under "Processor family", the kernel will not work on 486 + architectures. Similarly, multiprocessor kernels for the "PPro" + architecture may not work on all Pentium based boards. + + People using multiprocessor machines who say Y here should also say + Y to "Enhanced Real Time Clock Support", below. The "Advanced Power + Management" code will be disabled if you say Y here. + + See also: Documentation/SMP.txt, Documentation/smp.tex, + Documentation/smp.txt, and Documentation/IO-APIC.txt. Also see the + SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ . + + If you don't know what to do here, say N. + +Kernel math emulation +CONFIG_MATH_EMULATION + Linux can emulate a math coprocessor (used for floating point + operations) if you don't have one. 486DX and Pentium processors have + a math coprocessor built in, 486SX and 386 do not, unless you added + a 487DX or 387, respectively. (The messages during boot time can + give you some hints here ["man dmesg"].) Everyone needs either a + coprocessor or this emulation. + + If you don't have a math coprocessor, you need to say Y here; if you + say Y here even though you have a coprocessor, the coprocessor will + be used nevertheless. (This behavior can be changed with the kernel + command line option "no387", which comes handy if your coprocessor + is broken. Try "man bootparam" or see the documentation of your boot + loader (lilo or loadlin) about how to pass options to the kernel at + boot time. The lilo procedure is also explained in the SCSI-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto .) This + means that it is a good idea to say Y here if you intend to use this + kernel on different machines. + + More information about the internals of the Linux math coprocessor + emulation can be found in arch/i386/math-emu/README. + + If you are not sure, say Y; apart from resulting in a 66 KB bigger + kernel, it won't hurt. + +Timer and CPU usage LEDs +CONFIG_LEDS + If you say Y here, the LEDs on your machine will be used + to provide useful information about your current system status. + + If you are compiling a kernel for a NetWinder or EBSA-285, you will + be able to select which LEDs are active using the options below. If + you are compiling a kernel for the EBSA-110 however, the red LED + will simply flash regularly to indicate that the system is still + functional. It is safe to say Y here if you have a CATS system, but + the driver will do nothing. + +Timer LED +CONFIG_LEDS_TIMER + If you say Y here, one of the system LEDs (the green one on the + NetWinder or the amber one on the EBSA285) will flash regularly to + indicate that the system is still operational. This is mainly + useful to kernel hackers who are debugging unstable kernels. + +CPU usage LED +CONFIG_LEDS_CPU + If you say Y here, the red LED will be used to give a good real + time indication of CPU usage, by lighting whenever the idle task + is not currently executing. + +Kernel FP software completion (EXPERIMENTAL) +CONFIG_MATHEMU + This option is required for IEEE compliant floating point arithmetic + on the Alpha. The only time you would ever not say Y is to say M in + order to debug the code. Say Y unless you know what you are doing. + +High Memory support +CONFIG_NOHIGHMEM + If you are compiling a kernel which will never run on a machine + with more than 1 Gigabyte total physical RAM, answer "off" + here (default choice). + + Linux can use up to 64 Gigabytes of physical memory on x86 systems. + High memory is all the physical RAM that could not be directly + mapped by the kernel - ie. 3GB if there is 4GB RAM in the system, + 7GB if there is 8GB RAM in the system. + + If 4 Gigabytes physical RAM or less is used then answer "4GB" here. + + If more than 4 Gigabytes is used then answer "64GB" here. This + selection turns Intel PAE (Physical Address Extension) mode on. + PAE implements 3-level paging on IA32 processors. PAE is fully + supported by Linux, PAE mode is implemented on all recent Intel + processors (PPro and better). NOTE: The "64GB" kernel will not + boot CPUs that not support PAE! + +Normal PC floppy disk support +CONFIG_BLK_DEV_FD + If you want to use the floppy disk drive(s) of your PC under Linux, + say Y. Information about this driver, especially important for IBM + Thinkpad users, is contained in drivers/block/README.fd. This file + also contains the location of the Floppy driver FAQ as well as + location of the fdutils package used to configure additional + parameters of the driver at run time. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called floppy.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Support for PowerMac floppy +CONFIG_MAC_FLOPPY + If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple) + floppy controller, say Y here. Most commonly found in PowerMacs. + +RAM disk support +CONFIG_BLK_DEV_RAM + Saying Y here will allow you to use a portion of your RAM memory as + a block device, so that you can make filesystems on it, read and + write to it and do all the other things that you can do with normal + block devices (such as hard drives). It is usually used to load and + store a copy of a minimal root file system off of a floppy into RAM + during the initial install of Linux. + + Note that the kernel command line option "ramdisk=XX" is now + obsolete. For details, read Documentation/ramdisk.txt. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M and read Documentation/modules.txt. The module will be called + rd.o. + + Most normal users won't need the RAM disk functionality, and can + thus say N here. + +Initial RAM disk (initrd) support +CONFIG_BLK_DEV_INITRD + The initial RAM disk is a RAM disk that is loaded by the boot loader + (loadlin or lilo) and that is mounted as root before the normal boot + procedure. It is typically used to load modules needed to mount the + "real" root file system, etc. See Documentation/initrd.txt for + details. + +Loop device support +CONFIG_BLK_DEV_LOOP + Saying Y here will allow you to use a regular file as a block + device; you can then create a file system on that block device and + mount it just as you would mount other block devices such as hard + drive partitions, CDROM drives or floppy drives. + + This is useful if you want to check an ISO 9660 file system before + burning the CD, or if you want to use floppy images without first + writing them to floppy. + + The loop device driver can also be used to "hide" a filesystem in a + disk partition, floppy, or regular file, either using encryption + (scrambling the data) or steganography (hiding the data in the low + bits of, say, a sound file). This is also safe if the file resides + on a remote file server. If you want to do this, you will first have + to acquire and install a kernel patch from + ftp://ftp.replay.com/pub/crypto/linux/all or + ftp://verden.pvv.org/pub/linux/kerneli/v2.1/ , and then you need to + say Y to this option. + + Note that alternative ways to use encrypted filesystems are provided + by the cfs package, which can be gotten from + ftp://ftp.replay.com/pub/crypto/disk/ , and the newer tcfs package, + available at http://tcfs.dia.unisa.it/ . You do not need to say Y + here if you want to use one of these. However, using cfs requires + saying Y to "NFS filesystem support" below while using tcfs requires + applying a kernel patch. + + To use the loop device, you need the losetup utility and a recent + version of the mount program, both contained in the util-linux + package. The location and current version number of util-linux is + contained in the file Documentation/Changes. + + Note that this loop device has nothing to do with the loopback + device used for network connections from the machine to itself. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called loop.o. + + Most users will answer N here. + +Network Block Device support +CONFIG_BLK_DEV_NBD + Saying Y here will allow your computer to be a client for network + block devices, i.e. it will be able to use block devices exported by + servers (mount filesystems on them etc.). Communication between + client and server works over TCP/IP networking, but to the client + program this is hidden: it looks like a regular local file access to + a block device special file such as /dev/nd0. + + Network block devices also allows you to run a block-device in + userland (making server and client physically the same computer, + communicating using the loopback network device). + + Read Documentation/nbd.txt for more information, especially about + where to find the server code, which runs in user space and does not + need special kernel support. + + Note that this has nothing to do with the network file systems NFS + or Coda; you can say N here even if you intend to use NFS or Coda. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called nbd.o. + + If unsure, say N. + +Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support +CONFIG_BLK_DEV_IDE + If you say Y here, you will use the full-featured IDE driver to + control up to eight IDE interfaces, each being able to serve a + "master" and a "slave" device, for a total of up to sixteen IDE + disk/cdrom/tape/floppy drives. People with SCSI-only systems + can say N here. + + Useful information about large (>540 MB) IDE disks, multiple + interfaces, what to do if IDE devices are not automatically + detected, sound card IDE ports, module support, and other topics, is + contained in Documentation/ide.txt. For detailed information about + hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + To fine-tune IDE drive/interface parameters for improved + performance, look for the hdparm package at + ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt and + Documentation/ide.txt. The module will be called ide.o. Do not + compile this driver as a module if your root filesystem (the one + containing the directory /) is located on an IDE device. + + If you have one or more IDE drives, say Y or M here. If your system + has no IDE drives, or if memory requirements are really tight, you + could say N here, and select the "Old hard disk driver" below + instead to save about 13 KB of memory in the kernel. + +Old hard disk (MFM/RLL/IDE) driver +CONFIG_BLK_DEV_HD_ONLY + There are two drivers for MFM/RLL/IDE hard disks. Most people use + the newer enhanced driver, but this old one is still around for two + reasons. Some older systems have strange timing problems and seem to + work only with the old driver (which itself does not work with some + newer systems). The other reason is that the old driver is smaller, + since it lacks the enhanced functionality of the new one. This makes + it a good choice for systems with very tight memory restrictions, or + for systems with only older MFM/RLL/ESDI drives. Choosing the old + driver can save 13 KB or so of kernel memory. + + If you are unsure, then just choose the Enhanced IDE/MFM/RLL driver + instead of this one. For more detailed information, read the + Disk-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + People with SCSI-only systems can say N here. + +Use old disk-only driver on primary interface +CONFIG_BLK_DEV_HD_IDE + There are two drivers for MFM/RLL/IDE disks. Most people use just + the new enhanced driver by itself. This option however installs the + old hard disk driver to control the primary IDE/disk interface in + the system, leaving the new enhanced IDE driver to take care of only + the 2nd/3rd/4th IDE interfaces. Doing this will prevent you from + having an IDE/ATAPI CDROM or tape drive connected to the primary IDE + interface. Choosing this option may be useful for older systems + which have MFM/RLL/ESDI controller+drives at the primary port + address (0x1f0), along with IDE drives at the secondary/3rd/4th port + addresses. + + Normally, just say N here; you will then use the new driver for all + 4 interfaces. + + People with SCSI-only systems don't need this and can say N here as + well. + +Include IDE/ATA-2 DISK support +CONFIG_BLK_DEV_IDEDISK + This will include enhanced support for MFM/RLL/IDE hard disks. If + you have a MFM/RLL/IDE disk, and there is no special reason to use + the old hard disk driver instead, say Y. If you have an SCSI-only + system, you can say N here. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ide-disk.o. Do not compile this driver as a module if your + root filesystem (the one containing the directory /) is located on + the IDE disk. If unsure, say Y. + +Use multi-mode by default +CONFIG_IDEDISK_MULTI_MODE + If you get this error, try to say Y here: + + hda: set_multmode: status=0x51 { DriveReady SeekComplete Error } + hda: set_multmode: error=0x04 { DriveStatusError } + + If in doubt, say N. + +Include IDE/ATAPI CDROM support +CONFIG_BLK_DEV_IDECD + If you have a CDROM drive using the ATAPI protocol, say Y. ATAPI is + a newer protocol used by IDE CDROM and TAPE drives, similar to the + SCSI protocol. Most new CDROM drives use ATAPI, including the + NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI + double(2X) or better speed drives. + + If you say Y here, the CDROM drive will be identified at boot time + along with other IDE devices, as "hdb" or "hdc", or something + similar (check the boot messages with dmesg). If this is your only + CDROM drive, you can say N to all other CDROM options, but be sure + to say Y or M to "ISO 9660 CDROM filesystem support". + + Read the CDROM-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto and the file + Documentation/cdrom/ide-cd. Note that older versions of lilo (the + Linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so + install lilo-16 or higher, available from + ftp://metalab.unc.edu/pub/Linux/system/boot/lilo . + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ide-cd.o. + +Include CD-Changer Reporting +CONFIG_IDECD_SLOTS + If you have an IDE/ATAPI multi-slot cd-changer and you want + to report which slots have a disk present, say Y. If you say Y + and there is no multi-slot cdrom present, this code is skipped. + + This code could be the basis of multi-disk access based on + multi-mounts, but this is still pie-in-the-sky. + + If unsure, say N. + +Include IDE/ATAPI TAPE support +CONFIG_BLK_DEV_IDETAPE + If you have an IDE tape drive using the ATAPI protocol, say Y. + ATAPI is a newer protocol used by IDE tape and CDROM drives, similar + to the SCSI protocol. If you have an SCSI tape drive however, you + can say N here. + + If you say Y here, the tape drive will be identified at boot time + along with other IDE devices, as "hdb" or "hdc", or something + similar, and will be mapped to a character device such as "ht0" + (check the boot messages with dmesg). Be sure to consult the + drivers/block/ide-tape.c and Documentation/ide.txt files for usage + information. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ide-tape.o. + +Include IDE/ATAPI FLOPPY support +CONFIG_BLK_DEV_IDEFLOPPY + If you have an IDE floppy drive which uses the ATAPI protocol, + answer Y. ATAPI is a newer protocol used by IDE CDROM/tape/floppy + drives, similar to the SCSI protocol. + + The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by + this driver. (ATAPI PD-CD/CDR drives are not supported by this + driver; support for PD-CD/CDR drives is available if you answer Y to + "SCSI emulation support", below). + + If you say Y here, the FLOPPY drive will be identified along with + other IDE devices, as "hdb" or "hdc", or something similar (check + the boot messages with dmesg). + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ide-floppy.o. + +SCSI emulation support +CONFIG_BLK_DEV_IDESCSI + This will provide SCSI host adapter emulation for IDE ATAPI devices, + and will allow you to use a SCSI device driver instead of a native + ATAPI driver. + + This is useful if you have an ATAPI device for which no native + driver has been written (for example, an ATAPI PD-CD or CDR drive); + you can then use this emulation together with an appropriate SCSI + device driver. In order to do this, say Y here and to "SCSI support" + and "SCSI generic support", below. + + Note that this option does NOT allow you to attach SCSI devices to a + box that doesn't have a SCSI host adapter installed. + + If both this SCSI emulation and native ATAPI support are compiled + into the kernel, the native support will be used. + + People with SCSI-only systems can say N here. If unsure, say N. + +CMD640 chipset bugfix/support +CONFIG_BLK_DEV_CMD640 + The CMD-Technologies CMD640 IDE chip is used on many common 486 and + Pentium motherboards, usually in combination with a "Neptune" or + "SiS" chipset. Unfortunately, it has a number of rather nasty + design flaws that can cause severe data corruption under many common + conditions. Say Y here to include code which tries to automatically + detect and correct the problems under Linux. This option also + enables access to the secondary IDE ports in some CMD640 based + systems. + + This driver will work automatically in PCI based systems (most new + systems have PCI slots). But if your system uses VESA local bus + (VLB) instead of PCI, you must also supply a kernel boot parameter + to enable the CMD640 bugfix/support: "ide0=cmd640_vlb". (Try "man + bootparam" or see the documentation of your boot loader about how to + pass options to the kernel. The lilo procedure is also explained in + the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto .) + + The CMD640 chip is also used on add-in cards by Acculogic, and on + the "CSA-6400E PCI to IDE controller" that some people have. For + details, read Documentation/ide.txt. + + People with SCSI-only systems should say N here. If unsure, say Y. + +CMD640 enhanced support +CONFIG_BLK_DEV_CMD640_ENHANCED + This option includes support for setting/autotuning PIO modes and + prefetch on CMD640 IDE interfaces. For details, read + Documentation/ide.txt. If you have a CMD640 IDE interface and your + BIOS does not already do this for you, then say Y here. Otherwise + say N. + +RZ1000 chipset bugfix/support +CONFIG_BLK_DEV_RZ1000 + The PC-Technologies RZ1000 IDE chip is used on many common 486 and + Pentium motherboards, usually along with the "Neptune" chipset. + Unfortunately, it has a rather nasty design flaw that can cause + severe data corruption under many conditions. Say Y here to include + code which automatically detects and corrects the problem under + Linux. This may slow disk throughput by a few percent, but at least + things will operate 100% reliably. + + People with SCSI-only systems should say N here. If unsure, say Y. + +Generic PCI IDE chipset support +CONFIG_BLK_DEV_IDEPCI + Say Y here for PCI systems which use IDE drive(s). + This option helps the IDE driver to automatically detect and + configure all PCI-based IDE interfaces in your system. + + People with SCSI-only systems should say N here; if unsure say Y. + +Generic PCI bus-master DMA support +CONFIG_BLK_DEV_IDEDMA_PCI + If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and + is capable of bus-master DMA operation (most Pentium PCI systems), + you will want to say Y here to reduce CPU overhead. You can then use + the "hdparm" utility to enable DMA for drives for which it was not + enabled automatically. By default, DMA is not enabled automatically + for these drives, but you can change that by saying Y to the + following question "Use DMA by default when available". You can get + the latest version of the hdparm utility from + ftp://metalab.unc.edu/pub/Linux/system/hardware/ . + + Read the comments at the beginning of drivers/block/idedma.c and the + file Documentation/ide.txt for more information. + + It is safe to say Y to this question. + +Good-Bad DMA Model-Firmware (EXPERIMENTAL) +IDEDMA_NEW_DRIVE_LISTINGS + If you say Y here, the model and firmware revision of your drive + will be compared against a blacklist of buggy drives that claim to + be (U)DMA capable but aren't. This is a blanket on/off test with no + speed limit options. + + Straight GNU GCC 2.7.3/2.8.X compilers are known to be safe; + whereas, many versions of EGCS have a problem and miscompile if you + say Y here. + + If in doubt, say N. + +Boot off-board chipsets first support +CONFIG_BLK_DEV_OFFBOARD + Normally, IDE controllers built into the motherboard (on-board + controllers) are assigned to ide0 and ide1 while those on add-in PCI + cards (off-board controllers) are relegated to ide2 and ide3. + Answering Y here will allow you to reverse the situation, with + off-board controllers on ide0/1 and on-board controllers on ide2/3. + This can improve the usability of some boot managers such as LILO + when booting from a drive on an off-board controller. + + If you say Y here, and you actually want to reverse the device scan + order as explained above, you also need to issue the kernel command + line option "pci=reverse". (Try "man bootparam" or see the + documentation of your boot loader (lilo or loadlin) about how to + pass options to the kernel at boot time. The lilo procedure is also + explained in the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto .) + + Note that, if you do this, the order of the hd* devices will be + rearranged which may require modification of fstab and other files. + + If in doubt, say N. + +Use DMA by default when available +CONFIG_IDEDMA_PCI_AUTO + Prior to kernel version 2.1.112, Linux used to automatically use + DMA for IDE drives and chipsets which support it. Due to concerns + about a couple of cases where buggy hardware may have caused damage, + the default is now to NOT use DMA automatically. To revert to the + previous behaviour, say Y to this question. + + If you suspect your hardware is at all flakey, say N here. + Do NOT email the IDE kernel people regarding this issue! + + It is normally safe to answer Y to this question unless your + motherboard uses a VIA VP2 chipset, in which case you should say N. + +AEC6210 chipset support +CONFIG_BLK_DEV_AEC6210 + This driver adds up to 4 more EIDE devices sharing a single + interrupt. This add-on card is a bootable PCI UDMA controller. In + order to get this card to initialize correctly in some cases, you + should say Y here, and preferably also to "Use DMA by default when + available". + + Please read the comments at the top of drivers/block/aec6210.c + +ALI M15x3 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_ALI15X3 + This driver ensures (U)DMA support for ALI 1543 and 1543C, + 1535, 1535D onboard chipsets. It also tests for Simplex mode and + enables normal dual channel support. + + If you say Y here, you also need to say Y to "Use DMA by default + when available", above. + + Please read the comments at the top of drivers/block/alim15x3.c + + If unsure, say N. + +CMD646 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_CMD646 + Say Y here if you have an IDE controller which uses this chipset. + +CY82C693 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_CY82C693 + This driver adds detection and support for the CY82C693 chipset + used on Digital's PC-Alpha 164SX boards. + + If you say Y here, you need to say Y to "Use DMA by default + when available" as well. + +HPT34X chipset support +CONFIG_BLK_DEV_HPT34X + This driver adds up to 4 more EIDE devices sharing a single + interrupt. The HPT343 chipset in its current form is a non-bootable + controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX) + PCI UDMA controllers. This driver requires dynamic tuning of the + chipset during the ide-probe at boot time. It is reported to support + DVD II drives, by the manufacturer. + +HPT34X DMA support (EXPERIMENTAL) +CONFIG_BLK_DEV_HPT34X_DMA + you need to say Y to "Use DMA by default when available" if you say + Y here. + + Please read the comments at the top of drivers/block/hpt34x.c + +HPT366 chipset support +CONFIG_BLK_DEV_HPT366 + This is an Ultra DMA chipset for ATA-66. + + This driver adds up to 4 more EIDE devices sharing a single + interrupt. The HPT366 chipset in its current form is a non-bootable. + This driver requires dynamic tuning of the chipset during the + ide-probe at boot. It is reported to support DVD II drives, by the + manufacturer. + + Please read the comments at the top of drivers/block/hpt366.c + +HPT366 Fast Interrupt support (EXPERIMENTAL) +HPT366_FAST_IRQ_PREDICTION + + If unsure, say N. + +NS87415 support (EXPERIMENTAL) +CONFIG_BLK_DEV_NS87415 + This driver adds detection and support for the NS87415 chip + (used in SPARC64, among others). + + Please read the comments at the top of drivers/block/ns87415.c. + +OPTi 82C621 enhanced support (EXPERIMENTAL) +CONFIG_BLK_DEV_OPTI621 + This is a driver for the OPTi 82C621 EIDE controller. + Please read the comments at the top of drivers/block/opti621.c. + +Intel PIIXn chipsets support +CONFIG_BLK_DEV_PIIX + This driver adds PIO mode setting and tuning for all PIIX IDE + controllers by Intel. Since the BIOS can sometimes improperly tune + PIO 0-4 mode settings, this allows dynamic tuning of the chipset + via the standard end-user tool 'hdparm'. + + Please read the comments at the top of drivers/block/piix.c + + If unsure, say N. + +PIIXn Tuning support +CONFIG_BLK_DEV_PIIX_TUNING + This driver extension adds DMA mode setting and tuning for all PIIX + IDE controllers by Intel. Since the BIOS can sometimes improperly + set up the device/adapter combination and speed limits, it has + become a necessity to back/forward speed devices as needed. + + Case 430HX/440FX PIIX3 need speed limits to reduce UDMA to DMA mode + 2 if the BIOS can not perform this task at initialization. + + If unsure, say N. + +PROMISE PDC20246/PDC20262 support +CONFIG_BLK_DEV_PDC202XX + Promise Ultra33 or PDC20246 + + This driver adds up to 4 more EIDE devices sharing a single + interrupt. This add-on card is a bootable PCI UDMA controller. Since + multiple cards can be installed and there are BIOS ROM problems that + happen if the BIOS revisions of all installed cards (three-max) do + not match, the driver attempts to do dynamic tuning of the chipset at + boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required for + more than one card. This card may require that you say Y to "Special + UDMA Feature (EXPERIMENTAL)". + + Promise Ultra66 or PDC20262 + + This driver adds up to 4 more EIDE devices sharing a single + interrupt. This add-on card is a bootable PCI UDMA ATA-66 + controller. The driver attempts to dynamic tuning of the chipset at + boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS + 1.11 or newer required. + + If you say Y here, you need to say Y to "Use DMA by default when + available" as well. + + Please read the comments at the top of drivers/block/pdc202xx.c + + If unsure, say N. + +Special UDMA Feature +PDC202XX_FORCE_BURST_BIT + For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally + for PDC20246/Ultra33 that has BIOS setup failures when using 3 or + more cards. + + Please read the comments at the top of drivers/block/pdc202xx.c + + If unsure, say N. + +Special Mode Feature (EXPERIMENTAL) +PDC202XX_FORCE_MASTER_MODE + For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for + possible Hardware RAID 0,1 for the FastTrak Series. + + Say N. + +Winbond SL82c105 support +CONFIG_BLK_DEV_SL82C105 + If you have a Winbond SL82c105 IDE controller, say Y here to enable + special configuration for this chip. This is common on various CHRP + motherboards, but could be used elsewhere. If in doubt, say Y. + +Tekram TRM290 chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_TRM290 + This driver adds support for bus master DMA transfers + using the Tekram TRM290 PCI IDE chip. Volunteers are + needed for further tweaking and development. + Please read the comments at the top of drivers/block/trm290.c. + +VIA82CXXX chipset support (EXPERIMENTAL) +CONFIG_BLK_DEV_VIA82CXXX + This allows you to to configure your chipset for a better use while + running (U)DMA: it will allow you to enable efficiently the second + channel dma usage, as it is may not be set by BIOS. It allows you to + run a kernel command line at boot time in order to set fifo config. + If no command line is provided, it will try to set fifo configuration + at its best. It will allow you to get a proc/ide/via display + (while running a "cat") provided you enabled "proc" support. + Please read the comments at the top of drivers/block/via82cxxx.c + + If you say Y here, you also need to say Y to "Use DMA by default + when available", above. + + If unsure, say N. + +Other IDE chipset support +CONFIG_IDE_CHIPSETS + Say Y here if you want to include enhanced support for various IDE + interface chipsets used on motherboards and add-on cards. You can + then pick your particular IDE chip from among the following options. + This enhanced support may be necessary for Linux to be able to + access the 3rd/4th drives in some systems. It may also enable + setting of higher speed I/O rates to improve system performance with + these chipsets. Most of these also require special kernel boot + parameters to actually turn on the support at runtime; you can find + a list of these in the file Documentation/ide.txt. + + People with SCSI-only systems can say N here. + +Generic 4 drives/port support +CONFIG_BLK_DEV_4DRIVES + Certain older chipsets, including the Tekram 690CD, use a single set + of I/O ports at 0x1f0 to control up to four drives, instead of the + customary two drives per port. Support for this can be enabled at + runtime using the "ide0=four" kernel boot parameter if you say Y + here. + +ALI M14xx support +CONFIG_BLK_DEV_ALI14XX + This driver is enabled at runtime using the "ide0=ali14xx" kernel + boot parameter. It enables support for the secondary IDE interface + of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster + I/O speeds to be set as well. See the files Documentation/ide.txt + and drivers/block/ali14xx.c for more info. + +DTC-2278 support +CONFIG_BLK_DEV_DTC2278 + This driver is enabled at runtime using the "ide0=dtc2278" kernel + boot parameter. It enables support for the secondary IDE interface + of the DTC-2278 card, and permits faster I/O speeds to be set as + well. See the Documentation/ide.txt and drivers/block/dtc2278.c + files for more info. + +Holtek HT6560B support +CONFIG_BLK_DEV_HT6560B + This driver is enabled at runtime using the "ide0=ht6560b" kernel + boot parameter. It enables support for the secondary IDE interface + of the Holtek card, and permits faster I/O speeds to be set as well. + See the Documentation/ide.txt and drivers/block/ht6560b.c files for + more info. + +PROMISE DC4030 support (EXPERIMENTAL) +CONFIG_BLK_DEV_PDC4030 + This driver provides support for the secondary IDE interface and + cache of Promise IDE chipsets, e.g. DC4030 and DC5030. 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. This driver is enabled at runtime using the + "ide0=dc4030" kernel boot parameter. See the Documentation/ide.txt + and drivers/block/pdc4030.c files for more info. + +QDI QD6580 support +CONFIG_BLK_DEV_QD6580 + This driver is enabled at runtime using the "ide0=qd6580" kernel + boot parameter. It permits faster I/O speeds to be set. See the + files Documentation/ide.txt and drivers/block/qd6580.c for more + info. + +UMC 8672 support +CONFIG_BLK_DEV_UMC8672 + This driver is enabled at runtime using the "ide0=umc8672" kernel + boot parameter. It enables support for the secondary IDE interface + of the UMC-8672, and permits faster I/O speeds to be set as well. + See the files Documentation/ide.txt and drivers/block/umc8672.c for + more info. + +PS/2 ESDI hard disk support +CONFIG_BLK_DEV_PS2 + Say Y here if you have a PS/2 machine with a MCA bus and an ESDI + hard disk. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ps2esdi.o. + +Amiga builtin Gayle IDE interface support +CONFIG_BLK_DEV_GAYLE + This is the IDE driver for the builtin IDE interface on some Amiga + models. It supports both the `A1200 style' (used in A600 and A1200) + and `A4000 style' (used in A4000 and A4000T) of the Gayle IDE + interface. Say Y if you have such an Amiga model and want to use IDE + devices (hard disks, CD-ROM drives, etc.) that are connected to the + builtin IDE interface. + +Falcon IDE interface support +CONFIG_BLK_DEV_FALCON_IDE + This is the IDE driver for the builtin IDE interface on the Atari + Falcon. Say Y if you have a Falcon and want to use IDE devices (hard + disks, CD-ROM drives, etc.) that are connected to the builtin IDE + interface. + +Amiga Buddha/Catweasel IDE interface support (EXPERIMENTAL) +CONFIG_BLK_DEV_BUDDHA + This is the IDE driver for the IDE interfaces on the Buddha and + Catweasel expansion boards. It supports up to two interfaces on the + Buddha and three on the Catweasel. + + Say Y if you have a Buddha or Catweasel expansion board and want to + use IDE devices (hard disks, CD-ROM drives, etc.) that are connected + to one of its IDE interfaces. + +Amiga IDE Doubler support (EXPERIMENTAL) +CONFIG_BLK_DEV_IDEDOUBLER + This driver provides support for the so called `IDE doublers' (made + by various manufacturers, e.g. Eyetech) that can be connected to the + builtin IDE interface of some Amiga models. Using such an IDE + doubler, you can connect up to four instead of two IDE devices on + the Amiga's builtin IDE interface. + + Note that the normal Amiga Gayle IDE driver may not work correctly + if you have an IDE doubler and don't enable this driver! + + Say Y if you have an IDE doubler. The driver is enabled at kernel + runtime using the "ide=doubler" kernel boot parameter. + +Support for PowerMac IDE devices (must also enable IDE) +CONFIG_BLK_DEV_IDE_PMAC + No help for CONFIG_BLK_DEV_IDE_PMAC + +PowerMac IDE DMA support +CONFIG_BLK_DEV_IDEDMA_PMAC + No help for CONFIG_BLK_DEV_IDEDMA_PMAC + +Use DMA by default +CONFIG_IDEDMA_PMAC_AUTO + No help for CONFIG_IDEDMA_PMAC_AUTO + +Macintosh Quadra/Powerbook IDE interface support +CONFIG_BLK_DEV_MAC_IDE + This is the IDE driver for the builtin IDE interface on some m68k + Macintosh models. It supports both the `Quadra style' (used in + Quadra/ Centris 630 and Performa 588 models) and `Powerbook style' + (used in the Powerbook 150 and 190 models) IDE interface. + + Say Y if you have such an Macintosh model and want to use IDE + devices (hard disks, CD-ROM drives, etc.) that are connected to the + builtin IDE interface. + +ICS IDE interface support +CONFIG_BLK_DEV_IDE_ICSIDE + No help for CONFIG_BLK_DEV_IDE_ICSIDE + +ICS DMA support +CONFIG_BLK_DEV_IDEDMA_ICS + No help for CONFIG_BLK_DEV_IDEDMA_ICS + +Use ICS DMA by default +CONFIG_IDEDMA_ICS_AUTO + No help for CONFIG_IDEDMA_ICS_AUTO + +RapIDE interface support +CONFIG_BLK_DEV_IDE_RAPIDE + No help for CONFIG_BLK_DEV_IDE_RAPIDE + +XT hard disk support +CONFIG_BLK_DEV_XD + Very old 8 bit hard disk controllers used in the IBM XT computer + will be supported if you say Y here. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called xd.o. + + It's pretty unlikely that you have one of these: say N. + +Mylex DAC960/DAC1100 PCI RAID Controller support +CONFIG_BLK_DEV_DAC960 + This driver adds support for the Mylex DAC960, AcceleRAID, and + eXtremeRAID PCI RAID controllers. See the file + Documentation/README.DAC960 for further information about this + driver. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called DAC960.o. + +Parallel port IDE device support +CONFIG_PARIDE + There are many external CD-ROM and disk devices that connect through + your computer's parallel port. Most of them are actually IDE devices + using a parallel port IDE adapter. This option enables the PARIDE + subsystem which contains drivers for many of these external drives. + Read linux/Documentation/paride.txt for more information. + + If you have said Y to the "Parallel-port support" configuration + option, you may share a single port between your printer and other + parallel port devices. Answer Y to build PARIDE support into your + kernel, or M if you would like to build it as a loadable module. If + your parallel port support is in a loadable module, you must build + PARIDE as a module. If you built PARIDE support into your kernel, + you may still build the individual protocol modules and high-level + drivers as loadable modules. If you build this support as a module, + it will be called paride.o. + + To use the PARIDE support, you must say Y or M here and also to at + least one high-level driver (e.g. "Parallel port IDE disks", + "Parallel port ATAPI CD-ROMs", "Parallel port ATAPI disks" etc.) and + to at least one protocol driver (e.g. "ATEN EH-100 protocol", + "MicroSolutions backpack protocol", "DataStor Commuter protocol" + etc.). + +Parallel port IDE disks +CONFIG_PARIDE_PD + This option enables the high-level driver for IDE-type disk devices + connected through a parallel port. If you chose to build PARIDE + support into your kernel, you may answer Y here to build in the + parallel port IDE driver, otherwise you should answer M to build + it as a loadable module. The module will be called pd.o. You + must also have at least one parallel port protocol driver in your + system. Among the devices supported by this driver are the SyQuest + EZ-135, EZ-230 and SparQ drives, the Avatar Shark and the backpack + hard drives from MicroSolutions. + +Parallel port ATAPI CD-ROMs +CONFIG_PARIDE_PCD + This option enables the high-level driver for ATAPI CD-ROM devices + connected through a parallel port. If you chose to build PARIDE + support into your kernel, you may answer Y here to build in the + parallel port ATAPI CD-ROM driver, otherwise you should answer M to + build it as a loadable module. The module will be called pcd.o. You + must also have at least one parallel port protocol driver in your + system. Among the devices supported by this driver are the + MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If + you have such a CD-ROM drive, you should also say Y or M to "ISO + 9660 CDROM filesystem support" below, because that's the filesystem + used on CDROMs. + +Parallel port ATAPI disks +CONFIG_PARIDE_PF + This option enables the high-level driver for ATAPI disk devices + connected through a parallel port. If you chose to build PARIDE + support into your kernel, you may answer Y here to build in the + parallel port ATAPI disk driver, otherwise you should answer M + to build it as a loadable module. The module will be called pf.o. + You must also have at least one parallel port protocol driver in + your system. Among the devices supported by this driver are the + MicroSolutions backpack PD/CD drive and the Imation Superdisk + LS-120 drive. + +Parallel port ATAPI tapes +CONFIG_PARIDE_PT + This option enables the high-level driver for ATAPI tape devices + connected through a parallel port. If you chose to build PARIDE + support into your kernel, you may answer Y here to build in the + parallel port ATAPI disk driver, otherwise you should answer M + to build it as a loadable module. The module will be called pt.o. + You must also have at least one parallel port protocol driver in + your system. Among the devices supported by this driver is the + parallel port version of the HP 5GB drive. + +Parallel port generic ATAPI devices +CONFIG_PARIDE_PG + This option enables a special high-level driver for generic ATAPI + devices connected through a parallel port. The driver allows user + programs, such as cdrecord, to send ATAPI commands directly to a + device. + + If you chose to build PARIDE support into your kernel, you may + answer Y here to build in the parallel port generic ATAPI driver, + otherwise you should answer M to build it as a loadable module. The + module will be called pg.o. + + You must also have at least one parallel port protocol driver in + your system. + + This driver implements an API loosely related to the generic SCSI + driver. See /usr/include/linux/pg.h for details. + + You can obtain the most recent version of cdrecord from + ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ . Versions 1.6.1a3 and + later fully support this driver. + +ATEN EH-100 protocol +CONFIG_PARIDE_ATEN + This option enables support for the ATEN EH-100 parallel port IDE + protocol. This protocol is used in some inexpensive low performance + parallel port kits made in Hong Kong. If you chose to build PARIDE + support into your kernel, you may answer Y here to build in the + protocol driver, otherwise you should answer M to build it as a + loadable module. The module will be called aten.o. You must also + have a high-level driver for the type of device that you want to + support. + +MicroSolutions backpack protocol +CONFIG_PARIDE_BPCK + This option enables support for the MicroSolutions backpack parallel + port IDE protocol. If you chose to build PARIDE support into your + kernel, you may answer Y here to build in the protocol driver, + otherwise you should answer M to build it as a loadable module. The + module will be called bpck.o. You must also have a high-level driver + for the type of device that you want to support. + +DataStor Commuter protocol +CONFIG_PARIDE_COMM + This option enables support for the Commuter parallel port IDE + protocol from DataStor. If you chose to build PARIDE support + into your kernel, you may answer Y here to build in the protocol + driver, otherwise you should answer M to build it as a loadable + module. The module will be called comm.o. You must also have + a high-level driver for the type of device that you want to support. + +DataStor EP-2000 protocol +CONFIG_PARIDE_DSTR + This option enables support for the EP-2000 parallel port IDE + protocol from DataStor. If you chose to build PARIDE support + into your kernel, you may answer Y here to build in the protocol + driver, otherwise you should answer M to build it as a loadable + module. The module will be called dstr.o. You must also have + a high-level driver for the type of device that you want to support. + +Shuttle EPAT/EPEZ protocol +CONFIG_PARIDE_EPAT + This option enables support for the EPAT parallel port IDE protocol. + EPAT is a parallel port IDE adapter manufactured by Shuttle + Technology and widely used in devices from major vendors such as + Hewlett-Packard, SyQuest, Imation and Avatar. If you chose to build + PARIDE support into your kernel, you may answer Y here to build in + the protocol driver, otherwise you should answer M to build it as a + loadable module. The module will be called epat.o. You must also + have a high-level driver for the type of device that you want to + support. + +Shuttle EPIA protocol +CONFIG_PARIDE_EPIA + This option enables support for the (obsolete) EPIA parallel port + IDE protocol from Shuttle Technology. This adapter can still be + found in some no-name kits. If you chose to build PARIDE support + into your kernel, you may answer Y here to build in the protocol + driver, otherwise you should answer M to build it as a loadable + module. The module will be called epia.o. You must also have a + high-level driver for the type of device that you want to support. + +FIT TD-2000 protocol +CONFIG_PARIDE_FIT2 + This option enables support for the TD-2000 parallel port IDE + protocol from Fidelity International Technology. This is a simple + (low speed) adapter that is used in some portable hard drives. If + you chose to build PARIDE support into your kernel, you may answer Y + here to build in the protocol driver, otherwise you should answer M + to build it as a loadable module. The module will be called ktti.o. + You must also have a high-level driver for the type of device that + you want to support. + +FIT TD-3000 protocol +CONFIG_PARIDE_FIT3 + This option enables support for the TD-3000 parallel port IDE + protocol from Fidelity International Technology. This protocol is + used in newer models of their portable disk, CD-ROM and PD/CD + devices. If you chose to build PARIDE support into your kernel, you + may answer Y here to build in the protocol driver, otherwise you + should answer M to build it as a loadable module. The module will be + called fit3.o. You must also have a high-level driver for the type + of device that you want to support. + +Freecom IQ ASIC-2 protocol +CONFIG_PARIDE_FRIQ + This option enables support for version 2 of the Freecom IQ parallel + port IDE adapter. This adapter is used by the Maxell Superdisk + drive. If you chose to build PARIDE support into your kernel, you + may answer Y here to build in the protocol driver, otherwise you + should answer M to build it as a loadable module. The module will be + called friq.o. You must also have a high-level driver for the type + of device that you want to support. + +FreeCom power protocol +CONFIG_PARIDE_FRPW + This option enables support for the Freecom power parallel port IDE + protocol. If you chose to build PARIDE support into your kernel, you + may answer Y here to build in the protocol driver, otherwise you + should answer M to build it as a loadable module. The module will be + called frpw.o. You must also have a high-level driver for the type + of device that you want to support. + +KingByte KBIC-951A/971A protocols +CONFIG_PARIDE_KBIC + This option enables support for the KBIC-951A and KBIC-971A parallel + port IDE protocols from KingByte Information Corp. KingByte's + adapters appear in many no-name portable disk and CD-ROM products, + especially in Europe. If you chose to build PARIDE support into your + kernel, you may answer Y here to build in the protocol driver, + otherwise you should answer M to build it as a loadable module. The + module will be called kbic.o. You must also have a high-level driver + for the type of device that you want to support. + +KT PHd protocol +CONFIG_PARIDE_KTTI + This option enables support for the "PHd" parallel port IDE protocol + from KT Technology. This is a simple (low speed) adapter that is + used in some 2.5" portable hard drives. If you chose to build PARIDE + support into your kernel, you may answer Y here to build in the + protocol driver, otherwise you should answer M to build it as a + loadable module. The module will be called ktti.o. You must also + have a high-level driver for the type of device that you want to + support. + +OnSpec 90c20 protocol +CONFIG_PARIDE_ON20 + This option enables support for the (obsolete) 90c20 parallel port + IDE protocol from OnSpec (often marketed under the ValuStore brand + name). If you chose to build PARIDE support into your kernel, you + may answer Y here to build in the protocol driver, otherwise you + should answer M to build it as a loadable module. The module will + be called on20.o. You must also have a high-level driver for the + type of device that you want to support. + +OnSpec 90c26 protocol +CONFIG_PARIDE_ON26 + This option enables support for the 90c26 parallel port IDE protocol + from OnSpec Electronics (often marketed under the ValuStore brand + name). If you chose to build PARIDE support into your kernel, you + may answer Y here to build in the protocol driver, otherwise you + should answer M to build it as a loadable module. The module will be + called on26.o. You must also have a high-level driver for the type + of device that you want to support. + +Multiple devices driver support +CONFIG_BLK_DEV_MD + This driver lets you combine several hard disk partitions into one + logical block device. This can be used to simply append one + partition to another one or to combine several redundant + hard disks to a RAID1/4/5 device so as to provide protection against + hard disk failures. This is called "Software RAID" since the + combining of the partitions is done by the kernel. "Hardware RAID" + means that the combining is done by a dedicated controller; if you + have such a controller, you do not need to say Y here. + + More information about Software RAID on Linux is contained in the + Software-RAID mini-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . There you will also + learn where to get the supporting user space utilities raidtools. + + If unsure, say N. + +Linear (append) mode +CONFIG_MD_LINEAR + If you say Y here, then your multiple devices driver will be able to + use the so-called linear mode, i.e. it will combine the hard disk + partitions by simply appending one to the other. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called linear.o. + + If unsure, say Y. + +RAID-0 (striping) mode +CONFIG_MD_STRIPED + If you say Y here, then your multiple devices driver will be able to + use the so-called raid0 mode, i.e. it will combine the hard disk + partitions into one logical device in such a fashion as to fill them + up evenly, one chunk here and one chunk there. This will increase + the throughput rate if the partitions reside on distinct disks. + + Information about Software RAID on Linux is contained in the + Software-RAID mini-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . There you will also + learn where to get the supporting user space utilities raidtools. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called raid0.o. + + If unsure, say Y. + +RAID-1 (mirroring) mode +CONFIG_MD_MIRRORING + A RAID-1 set consists of several disk drives which are exact copies + of each other. In the event of a mirror failure, the RAID driver + will continue to use the operational mirrors in the set, providing + an error free MD (multiple device) to the higher levels of the + kernel. In a set with N drives, the available space is the capacity + of a single drive, and the set protects against a failure of (N - 1) + drives. + + Information about Software RAID on Linux is contained in the + Software-RAID mini-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . There you will also + learn where to get the supporting user space utilities raidtools. + + If you want to use such a RAID-1 set, say Y. This code is also + available as a module called raid1.o ( = code which can be inserted + in and removed from the running kernel whenever you want). If you + want to compile it as a module, say M here and read + Documentation/modules.txt. + + If unsure, say Y. + +RAID-4/RAID-5 mode +CONFIG_MD_RAID5 + A RAID-5 set of N drives with a capacity of C MB per drive provides + the capacity of C * (N - 1) drives, and protects against a failure + of a single drive. For a given sector (row) number, (N - 1) drives + contain data sectors, and one drive contains the parity protection. + For a RAID-4 set, the parity blocks are present on a single drive, + while a RAID-5 set distributes the parity across the drives in one + of the available parity distribution methods. + + Information about Software RAID on Linux is contained in the + Software-RAID mini-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . There you will also + learn where to get the supporting user space utilities raidtools. + + If you want to use such a RAID-4/RAID-5 set, say Y. This code is + also available as a module called raid5.o ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. + + If unsure, say Y. + +Boot support (linear, striped) +CONFIG_MD_BOOT + To boot with an initial linear or striped md device you have to + answer Y here. For lilo and loadlin options see the file + Documentation/md.txt. + +Support for Deskstation RPC44 +CONFIG_DESKSTATION_RPC44 + This is a machine with a R4400 100 MHz CPU. To compile a Linux + kernel that runs on these, say Y here. For details about Linux + on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at + http://lena.fnet.fr/ . + +Support for Acer PICA 1 chipset +CONFIG_ACER_PICA_61 + This is a machine with a R4400 133/150 MHz CPU. To compile a Linux + kernel that runs on these, say Y here. For details about Linux on + the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at + http://lena.fnet.fr/ . + +Support for Algorithmics P4032 (EXPERIMENTAL) +CONFIG_ALGOR_P4032 + This is an evaluation board of the British company Algorithmics. The + board uses the R4300 and a R5230 CPUs. For more information about + this board see http://www.algor.co.uk . + +IDE card support +CONFIG_BLK_DEV_IDE_CARDS + On Acorn systems, say Y here if you wish to use an IDE interface + expansion card. If you do not or are unsure, say N to this. + +ICS IDE interface +CONFIG_BLK_DEV_IDE_ICS + On Acorn systems, say Y here if you wish to use the ICS IDE + interface card. This is not required for ICS partition support. + If you are unsure, say N to this. + +ADFS partition support +CONFIG_BLK_DEV_PART + This allows Linux on Acorn systems to determine its partitions in + the 'non-ADFS' partition area of the hard disk - usually located + after the ADFS partition. You are probably using this system, so + you should say Y here. + +Support for Mips Magnum 4000 +CONFIG_MIPS_MAGNUM_4000 + This is a machine with a R4000 100 MHz CPU. To compile a Linux + kernel that runs on these, say Y here. For details about Linux on + the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at + http://lena.fnet.fr/ . + +Support for Olivetti M700 +CONFIG_OLIVETTI_M700 + This is a machine with a R4000 100 MHz CPU. To compile a Linux + kernel that runs on these, say Y here. For details about Linux on + the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at + http://lena.fnet.fr/ . + +CPU type +CONFIG_CPU_R3000 + Give the type of your machine's MIPS CPU. For this question, it + suffices to give a unique prefix of the option you want to choose. + In case of doubt select the R3000 CPU. The kernel will then run on + other MIPS machines but with slightly reduced performance. + +Compile the kernel into the ECOFF object format +CONFIG_ECOFF_KERNEL + Some machines require a kernel in the ECOFF format. You will have to + say Y here for example if you want to use a Mips Magnum 3000 or a + DECstation. + +Generate little endian code +CONFIG_CPU_LITTLE_ENDIAN + Some MIPS machines can be configured for either little or big endian + byte order. These modes require different kernels. Say Y if your + machine is little endian, N if it's a big endian machine. + +Kernel support for IRIX binaries +CONFIG_BINFMT_IRIX + If you say Y here, the kernel will support running of IRIX binaries. + You will need IRIX libraries for this to work. + +Networking support +CONFIG_NET + Unless you really know what you are doing, you should say Y here. + The reason is that some programs need kernel networking support even + when running on a stand-alone machine that isn't connected to any + other computer. If you are upgrading from an older kernel, you + should consider updating your networking tools too because changes + in the kernel and the tools often go hand in hand. The tools are + contained in the package net-tools, the location and version number + of which are given in Documentation/Changes. + + For a general introduction to Linux networking, it is highly + recommended to read the NET-3-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + +Socket filtering +CONFIG_FILTER + The Linux Socket Filter is derived from the Berkeley Packet Filter. + If you say Y here, user-space programs can attach a filter to any + socket and thereby tell the kernel that it should allow or disallow + certain types of data to get through the socket. Linux Socket + Filtering works on all socket types except TCP for now. See the text + file linux/Documentation/networking/filter.txt for more information. + If unsure, say N. + +Network packet filtering +CONFIG_NETFILTER + Netfilter is a framework for filtering and mangling network packets + that pass through your Linux box. + + The most common use of packet filtering is to run your Linux box as + a firewall protecting a local network from the Internet. The type of + firewall provided by this kernel support is called a "packet + filter", which means that it can reject individual network packets + based on type, source, destination etc. The other kind of firewall, + a "proxy-based" one, is more secure but more intrusive and more + bothersome to set up; it inspects the network traffic much more + closely, modifies it and has knowledge about the higher level + protocols, which a packet filter lacks. Moreover, proxy-based + firewalls often require changes to the programs running on the local + clients. Proxy-based firewalls don't need support by the kernel, but + they are often combined with a packet filter, which only works if + you say Y here. + + You should also say Y here if you intend to use your Linux box as + the gateway to the Internet for a local network of machines without + globally valid IP addresses. This is called "masquerading": if one + of the computers on your local network wants to send something to + the outside, your box can "masquerade" as that computer, i.e. it + forwards the traffic to the intended outside destination, but + modifies the packets to make it look like they came from the + firewall box itself. It works both ways: if the outside host + replies, the Linux box will silently forward the traffic to the + correct local computer. This way, the computers on your local net + are completely invisible to the outside world, even though they can + reach the outside and can receive replies. It is even possible to + run globally visible servers from within a masqueraded local network + using a mechanism called portforwarding. Masquerading is also often + called NAT (Network Address Translation). + + Another use of Netfilter is in transparent proxying: if a machine on + the local network tries to connect to an outside host, your Linux + box can transparently forward the traffic to a local server, + typically a caching proxy server. + + Various modules exist for netfilter which replace the previous + masquerading (ipmasqadm), packet filtering (ipchains), transparent + proxying, and portforwarding mechanisms. More information is + available from http://netfilter.kernelnotes.org . + + Make sure to say N to "Fast switching" below if you intend to say Y + here, as Fast switching currently bypasses netfilter. + + Chances are that you should say Y here if you compile a kernel which + will run as a router and N for regular hosts. If unsure, say N. + +Network packet filtering debugging +CONFIG_NETFILTER_DEBUG + Say Y to make sure packets aren't leaking. + +SYN flood protection +CONFIG_SYN_COOKIES + Normal TCP/IP networking is open to an attack known as "SYN + flooding". This denial-of-service attack prevents legitimate remote + users from being able to connect to your computer during an ongoing + attack and requires very little work from the attacker, who can + operate from anywhere on the Internet. + + SYN cookies provide protection against this type of attack. If you + say Y here, the TCP/IP stack will use a cryptographic challenge + protocol known as "SYN cookies" to enable legitimate users to + continue to connect, even when your machine is under attack. There + is no need for the legitimate users to change their TCP/IP software; + SYN cookies work transparently to them. For technical information + about SYN cookies, check out + ftp://koobera.math.uic.edu/pub/docs/syncookies-archive . + + If you are SYN flooded, the source address reported by the kernel is + likely to have been forged by the attacker; it is only reported as + an aid in tracing the packets to their actual source and should not + be taken as absolute truth. + + SYN cookies may prevent correct error reporting on clients when the + server is really overloaded. If this happens frequently better turn + them off. + + If you say Y here, note that SYN cookies aren't enabled by default; + you can enable them by saying Y to "/proc filesystem support" and + "Sysctl support" below and executing the command + + echo 1 >/proc/sys/net/ipv4/tcp_syncookies + + at boot time after the proc filesystem has been mounted. + + If unsure, say Y. + +Sun floppy controller support +CONFIG_BLK_DEV_SUNFD + This is support for floppy drives on Sun SPARC workstations. Say Y + if you have a floppy drive, otherwise N. Easy. + +Alpha system type +CONFIG_ALPHA_GENERIC + This is the system type of your hardware. A "generic" kernel will + run on any supported Alpha system. However, if you configure a + kernel for your specific system, it will be faster and smaller. + + To find out what type of Alpha system you have, you may want to + check out the Linux/Alpha FAQ, accessible on the WWW from + http://www.alphalinux.org . In summary: + + Alcor/Alpha-XLT AS 600 + Alpha-XL XL-233, XL-266 + AlphaBook1 Alpha laptop + Avanti AS 200, AS 205, AS 250, AS 255, AS 300, AS 400 + Cabriolet AlphaPC64, AlphaPCI64 + DP264 DP264 + EB164 EB164 21164 evaluation board + EB64+ EB64+ 21064 evaluation board + EB66 EB66 21066 evaluation board + EB66+ EB66+ 21066 evaluation board + Jensen DECpc 150, DEC 2000 model 300, + DEC 2000 model 500 + LX164 AlphaPC164-LX + Miata Personal Workstation 433a, 433au, 500a, + 500au, 600a, or 600au + Mikasa AS 1000 + Noname AXPpci33, UDB (Multia) + Noritake AS 1000A, AS 600A, AS 800 + PC164 AlphaPC164 + Rawhide AS 1200, AS 4000, AS 4100 + Ruffian RPX164-2, AlphaPC164-UX, AlphaPC164-BX + SX164 AlphaPC164-SX + Sable AS 2000, AS 2100 + Takara Takara + + If you don't know what to do, choose "generic". + +EV5 CPU daughtercard +CONFIG_ALPHA_PRIMO + Say Y if you have an AS 1000 5/xxx or an AS 1000A 5/xxx. + +EV5 CPU(s) +CONFIG_ALPHA_GAMMA + Say Y if you have an AS 2000 5/xxx or an AS 2100 5/xxx. + +Using SRM as bootloader +CONFIG_ALPHA_SRM + There are two different types of booting firmware on Alphas: SRM, + which is command line driven, and ARC, which uses menus and arrow + keys. Details about the Linux/Alpha booting process are contained in + the Linux/Alpha FAQ, accessible on the WWW from + http://www.alphalinux.org . + + The usual way to load Linux on an Alpha machine is to use MILO + (a bootloader that lets you pass command line parameters to the + kernel just like lilo does for the x86 architecture) which can be + loaded either from ARC or can be installed directly as a permanent + firmware replacement from floppy (which requires changing a certain + jumper on the motherboard). If you want to do either of these, say N + here. If MILO doesn't work on your system (true for Jensen + motherboards), you can bypass it altogether and boot Linux directly + from an SRM console; say Y here in order to do that. Note that you + won't be able to boot from an IDE disk using SRM. + + If unsure, say N. + +Use SRM PCI setup +CONFIG_ALPHA_SRM_SETUP + This option controls whether or not the PCI configuration set up by + SRM is modified. If you say Y, the existing PCI configuration will + be left intact. + +Non-standard serial port support +CONFIG_SERIAL_NONSTANDARD + Say Y here if you have any non-standard serial boards -- boards + which aren't supported using the standard "dumb" serial driver. + This includes intelligent serial boards such as Cyclades, + Digiboards, etc. These are usually used for systems that need many + serial ports because they serve many terminals or dial-in + connections. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about non-standard serial boards. + + Most people can say N here. + +Extended dumb serial driver options +CONFIG_SERIAL_EXTENDED + If you wish to use any non-standard features of the standard "dumb" + driver, say Y here. This includes HUB6 support, shared serial + interrupts, special multiport support, support for more than the + four COM 1/2/3/4 boards, etc. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about serial driver options. If unsure, say N. + +Support more than 4 serial ports +CONFIG_SERIAL_MANY_PORTS + Say Y here if you have dumb serial boards other than the four + standard COM 1/2/3/4 ports. This may happen if you have an AST + FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available + from http://metalab.unc.edu/mdw/linux.html#howto ), or other custom + serial port hardware which acts similar to standard serial port + hardware. If you only use the standard COM 1/2/3/4 ports, you can + say N here to save some memory. You can also say Y if you have an + "intelligent" multiport card such as Cyclades, Digiboards, etc. + +Support for sharing serial interrupts +CONFIG_SERIAL_SHARE_IRQ + Some serial boards have hardware support which allows multiple dumb + serial ports on the same board to share a single IRQ. To enable + support for this in the serial driver, say Y here. + +Auto detect IRQ on standard ports (unsafe) +CONFIG_SERIAL_DETECT_IRQ + Say Y here if you want the kernel to try to guess which IRQ + to use for your serial port. + + This is considered unsafe; it is far better to configure the IRQ in + a boot script using the setserial command. + + If unsure, say N. + +Support special multiport boards +CONFIG_SERIAL_MULTIPORT + Some multiport serial ports have special ports which are used to + signal when there are any serial ports on the board which need + servicing. Say Y here to enable the serial driver to take advantage + of those special I/O ports. + +SGI Zilog85C30 serial support +CONFIG_SGI_SERIAL + If you want to use your SGI's built-in serial ports under Linux, + answer Y. + +SGI Newport Graphics support (EXPERIMENTAL) +CONFIG_SGI_NEWPORT_GFX + If you have an SGI machine and you want to compile the graphics + drivers, say Y here. This will include the code for the + /dev/graphics and /dev/gfx drivers into the kernel for supporting + virtualized access to your graphics hardware. + +Support the Bell Technologies HUB6 card +CONFIG_HUB6 + Say Y here to enable support in the dumb serial driver to support + the HUB6 card. + +PCMCIA serial device support +CONFIG_PCMCIA_SERIAL_CS + Say Y here to enable support for 16-bit PCMCIA serial devices, + including serial port cards, modems, and the modem functions of + multifunction ethernet/modem cards. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called serial_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +CardBus serial device support +CONFIG_PCMCIA_SERIAL_CB + Say Y here to enable support for CardBus serial devices, including + the modem functions of multifunction ethernet/modem devices. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called serial_cb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +PCI support +CONFIG_PCI + Find out whether you have a PCI motherboard. PCI is the name of a + bus system, i.e. the way the CPU talks to the other stuff inside + your box. Other bus systems are ISA, EISA, Microchannel (MCA) or + VESA. If you have PCI, say Y, otherwise N. + + The PCI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , contains valuable + information about which PCI hardware does work under Linux and which + doesn't. + +PCI access mode +CONFIG_PCI_GOBIOS + On PCI systems, the BIOS can be used to detect the PCI devices and + determine their configuration. However, some old PCI motherboards + have BIOS bugs and may crash if this is done. Also, some embedded + PCI-based systems don't have any BIOS at all. Linux can also try to + detect the PCI hardware directly without using the BIOS. + + With this option, you can specify how Linux should detect the PCI + devices. If you choose "BIOS", the BIOS will be used, if you choose + "Direct", the BIOS won't be used, and if you choose "Any", the + kernel will try the direct access method and falls back to the BIOS + if that doesn't work. If unsure, go with the default. + +MCA support +CONFIG_MCA + MicroChannel Architecture is found in some IBM PS/2 machines and + laptops. It is a bus system similar to PCI or ISA. See + Documentation/mca.txt (and especially the web page given there) + before attempting to build an MCA bus kernel. + +SGI Visual Workstation support +CONFIG_VISWS + The SGI Visual Workstation series is an IA32-based workstation + based on SGI systems chips with some legacy PC hardware attached. + Say Y here to create a kernel to run on the SGI 320 or 540. + A kernel compiled for the Visual Workstation will not run on other + PC boards and vice versa. + See Documentation/sgi-visws.txt for more. + +SGI Visual Workstation framebuffer support +CONFIG_FB_SGIVW + SGI Visual Workstation support for framebuffer graphics. + +I2O support +CONFIG_I2O + The Intelligent Input/Output (I2O) architecture allows hardware + drivers to be split into two parts: an operating system specific + module called the OSM and an hardware specific module called the + HDM. The OSM can talk to a whole range of HDM's, and ideally the + HDM's are not OS dependent. This allows for the same HDM driver to + be used under different operating systems if the relevant OSM is in + place. In order for this to work, you need to have an I2O interface + adapter card in your computer. This card contains a special I/O + processor (IOP), thus allowing high speeds since the CPU does not + have to deal with I/O. + + If you say Y here, you will get a choice of interface adapter + drivers and OSM's with the following questions. + + This support is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. You will get modules called i2o_core.o + and i20_config.o. + + If unsure, say N. + +I2O PCI support +CONFIG_I2O_PCI + Say Y for support of PCI bus I2O interface adapters. Currently this + is the only variety supported, so you should say Y. + + This support is also available as a module called i2o_pci.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +I2O Block OSM +CONFIG_I2O_BLOCK + Include support for the I2O Block OSM. The Block OSM presents disk + and other structured block devices to the operating system. + + This support is also available as a module called i2o_block.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +I2O LAN OSM +CONFIG_I2O_LAN + Include support for the LAN OSM. You will also need to include + support for token ring or FDDI if you wish to use token ring or FDDI + I2O cards with this driver. + + This support is also available as a module called i2o_lan.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +I2O SCSI OSM +CONFIG_I2O_SCSI + Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel + I2O controller. You can use both the SCSI and Block OSM together if + you wish. + + This support is also available as a module called i2o_scsi.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +I2O /proc support +CONFIG_I2O_PROC + If you say Y here and to "/proc filesystem support", you will be + able to read I2O related information from the virtual directory + /proc/i2o. + + This support is also available as a module called i2o_proc.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Plug and Play support +CONFIG_PNP + Plug and Play (PnP) is a standard for peripherals which allows those + peripherals to be configured by software, e.g. assign IRQ's or other + parameters. No jumpers on the cards are needed, instead the values + are provided to the cards from the BIOS, from the operating system, + or using a user-space utility. + + Say Y here if you would like Linux to configure your Plug and Play + devices. You should then also say Y to "ISA Plug and Play support", + below. Alternatively, you can configure your PnP devices using the + user space utilities contained in the isapnptools package. + + This support is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. + +ISA Plug and Play support +CONFIG_ISAPNP + Say Y here if you would like support for ISA Plug and Play devices. + + This support is also available as a module called isapnp.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + + If unsure, say Y. + +PCMCIA/CardBus support +CONFIG_PCMCIA + Include kernel support for PCMCIA and CardBus devices. Because + PCMCIA support requires additional components that are not part of + the kernel (i.e., the pcmcia-cs package), building PCMCIA into the + kernel is generally not recommended unless you have a specific + need. If unsure, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + When compiled this way, there will be modules called pcmcia_core.o + and ds.o. If you want to compile it as a module, say M here and + read Documentation/modules.txt. + + You will also need David Hinds' pcmcia-cs package (see the file + Documentation/Changes for location). For more information, see the + PCMCIA-HOWTO. + +CardBus support +CONFIG_CARDBUS + There are two types of PCMCIA devices: 16-bit PC Cards, and higher + performance 32-bit CardBus devices. Use this option to include + support for CardBus devices. If unsure, say Y. + +i82365/Yenta compatible bridge support +CONFIG_I82365 + Include support for PCMCIA and CardBus host bridges that are + register compatible with the Intel i82365 and/or the Yenta + specification: this includes virtually all modern PCMCIA bridges. + If unsure, say Y. + +Databook TCIC host bridge support +CONFIG_TCIC + Include support for the Databook TCIC family of PCMCIA host bridges. + These are only found on a handful of old systems. If unsure, say N. + +System V IPC +CONFIG_SYSVIPC + Inter Process Communication is a suite of library functions and + system calls which let processes (running programs) synchronize and + exchange information. It is generally considered to be a good thing, + and some programs won't run unless you say Y here. In particular, if + you want to run the DOS emulator dosemu under Linux (read the + DOSEMU-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto ), you'll need to say Y + here. + + You can find documentation about IPC with "info ipc" and also in + section 6.4 of the Linux Programmer's Guide, available from + http://metalab.unc.edu/mdw/linux.html#guide . + + Saying Y here enlarges your kernel by about 18 KB. Just say Y. + +BSD Process Accounting +CONFIG_BSD_PROCESS_ACCT + If you say Y here, a user level program will be able to instruct the + kernel (via a special system call) to write process accounting + information to a file: whenever a process exits, information about + that process will be appended to the file by the kernel. The + information includes things such as creation time, owning user, + command name, memory usage, controlling terminal etc. (the complete + list is in the struct acct in include/linux/acct.h). It is up to the + user level program to do useful things with this information. This + is generally a good idea, so say Y. + +Sysctl support +CONFIG_SYSCTL + The sysctl interface provides a means of dynamically changing + certain kernel parameters and variables on the fly without requiring + a recompile of the kernel or reboot of the system. The primary + interface consists of a system call, but if you say Y to "/proc + filesystem support", a tree of modifiable sysctl entries will be + generated beneath the /proc/sys directory. They are explained in the + files in Documentation/sysctl/. Note that enabling this option will + enlarge the kernel by at least 8 KB. + + As it is generally a good thing, you should say Y here unless + building a kernel for install/rescue disks or your system is very + limited in memory. + +Kernel core (/proc/kcore) format +CONFIG_KCORE_ELF + If you enabled support for /proc filesystem then the file /proc/kcore + will contain the kernel core image. This can be used in gdb: + + $ cd /usr/src/linux ; gdb vmlinux /proc/kcore + + Selecting ELF will make /proc/kcore appear in ELF core format as defined + by the Executable and Linking Format specification. Selecting A.OUT will + choose the old "a.out" format which may be necessary for some old versions + of binutils or on some architectures. + + This is especially useful if you have compiled the kernel with "-g" option + to preserve debugging information. It is mainly used for examining kernel + data structures on the live kernel so if you don't understand what this + means or are not a kernel hacker, just leave it at its default value ELF. + +Kernel support for ELF binaries +CONFIG_BINFMT_ELF + ELF (Executable and Linkable Format) is a format for libraries and + executables used across different architectures and operating + systems. Saying Y here will enable your kernel to run ELF binaries + and enlarge it by about 13 KB. ELF support under Linux has now all + but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) + because it is portable (this does *not* mean that you will be able + to run executables from different architectures or operating systems + however) and makes building run-time libraries very easy. Many new + executables are distributed solely in ELF format. You definitely + want to say Y here. + + Information about ELF is contained in the ELF HOWTO available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you find that after upgrading from Linux kernel 1.2 and saying Y + here, you still can't run any ELF binaries (they just crash), then + you'll have to install the newest ELF runtime libraries, including + ld.so (check the file Documentation/Changes for location and latest + version). + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called binfmt_elf.o. Saying M or N here is dangerous because some + crucial programs on your system might be in ELF format. + +Kernel support for A.OUT binaries +CONFIG_BINFMT_AOUT + A.out (Assembler.OUTput) is a set of formats for libraries and + executables used in the earliest versions of UNIX. Linux used the + a.out formats QMAGIC and ZMAGIC until they were replaced with the + ELF format. + + As more and more programs are converted to ELF, the use for a.out + will gradually diminish. If you disable this option it will reduce + your kernel by one page. This is not much and by itself does not + warrant removing support. However its removal is a good idea if you + wish to ensure that absolutely none of your programs will use this + older executable format. If you don't know what to answer at this + point then answer Y. If someone told you "You need a kernel with + QMAGIC support" then you'll have to say Y here. You may answer M to + compile a.out support as a module and later load the module when you + want to use a program or library in a.out format. The module will be + called binfmt_aout.o. Saying M or N here is dangerous though, + because some crucial programs on your system might still be in A.OUT + format. + +Kernel support for Linux/Intel ELF binaries +CONFIG_BINFMT_EM86 + Say Y here if you want to be able to execute Linux/Intel ELF + binaries just like native Alpha binaries on your Alpha machine. For + this to work, you need to have the emulator /usr/bin/em86 in place. + + You can get the same functionality by saying N here and saying Y to + "Kernel support for MISC binaries". + + You may answer M to compile the emulation support as a module and + later load the module when you want to use a Linux/Intel binary. The + module will be called binfmt_em86.o. If unsure, say Y. + +Kernel support for MISC binaries +CONFIG_BINFMT_MISC + If you say Y here, it will be possible to plug wrapper-driven binary + formats into the kernel. You will like this especially when you use + programs that need an interpreter to run like Java, Python or + Emacs-Lisp. It's also useful if you often run DOS executables under + the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto ). Once you have + registered such a binary class with the kernel, you can start one of + those programs simply by typing in its name at a shell prompt; Linux + will automatically feed it to the correct interpreter. + + You can do other nice things, too. Read the file + Documentation/binfmt_misc.txt to learn how to use this feature, and + Documentation/java.txt for information about how to include Java + support. + + You must say Y to "proc filesystem support" (CONFIG_PROC_FS) to + use this part of the kernel. + + You may say M here for module support and later load the module when + you have use for it; the module is called binfmt_misc.o. If you + don't know what to answer at this point, say Y. + +Solaris binary emulation (EXPERIMENTAL) +CONFIG_SOLARIS_EMUL + This is experimental code which will enable you to run (many) + Solaris binaries on your SPARC Linux machine. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called solaris.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Processor family +CONFIG_M386 + This is the processor type of your CPU. This information is used for + optimizing purposes. In order to compile a kernel that can run on + all x86 CPU types (albeit not optimally fast), you can specify + "386" here. + + If you specify one of "486" or "586" or "Pentium" or "PPro", then + the kernel will not necessarily run on earlier architectures (e.g. a + Pentium optimized kernel will run on a PPro, but not necessarily on + a i486). + + Here are the settings recommended for greatest speed: + - "386" for the AMD/Cyrix/Intel 386DX/DXL/SL/SLC/SX, Cyrix/TI + 486DLC/DLC2 and UMC 486SX-S. Only "386" kernels will run on a 386 + class machine. + - "486" for the AMD/Cyrix/IBM/Intel 486DX/DX2/DX4 or + SL/SLC/SLC2/SLC3/SX/SX2, AMD/Cyrix 5x86, NexGen Nx586 and + UMC U5D or U5S. + - "586" for generic Pentium CPUs, possibly lacking the TSC + (time stamp counter) register. + - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and + K6-3D. + - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and + Intel Pentium II/Pentium Pro. + + If you don't know what to do, choose "386". + +VGA text console +CONFIG_VGA_CONSOLE + Saying Y here will allow you to use Linux in text mode through a + display that complies with the generic VGA standard. Virtually + everyone wants that. + + The program SVGATextMode can be used to utilize SVGA video cards to + their full potential in text mode. Download it from + ftp://metalab.unc.edu/pub/Linux/utils/console . + + Say Y. + +Video mode selection support +CONFIG_VIDEO_SELECT + This enables support for text mode selection on kernel startup. If + you want to take advantage of some high-resolution text mode your + card's BIOS offers, but the traditional Linux utilities like + SVGATextMode don't, you can say Y here and set the mode using the + "vga=" option from your boot loader (lilo or loadlin) or set + "vga=ask" which brings up a video mode menu on kernel startup. (Try + "man bootparam" or see the documentation of your boot loader about + how to pass options to the kernel. The lilo procedure is also + explained in the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto .) + + Read the file Documentation/svga.txt for more information about the + Video mode selection support. If unsure, say N. + +Support for frame buffer devices (EXPERIMENTAL) +CONFIG_FB + The frame buffer device provides an abstraction for the graphics + hardware. It represents the frame buffer of some video hardware and + allows application software to access the graphics hardware through + a well-defined interface, so the software doesn't need to know + anything about the low-level (hardware register) stuff. + + Frame buffer devices work identically across the different + architectures supported by Linux and make the implementation of + application programs easier and more portable; at this point, an X + server exists which uses the frame buffer device exclusively. + On several non-X86 architectures, the frame buffer device is the + only way to use the graphics hardware. + + The device is accessed through special device nodes, usually located + in the /dev directory, i.e. /dev/fb*. + + You need an utility program called fbset to make full use of frame + buffer devices. Please read Documentation/fb/framebuffer.txt and the + Framebuffer-HOWTO at + http://www.tahallah.demon.co.uk/programming/prog.html for more + information. + + Say Y here and to the driver for your graphics board below if you + are compiling a kernel for a non-x86 architecture. + + If you are compiling for the x86 architecture, you can say Y if you + want to play with it, but it is not essential. Please note that + running graphical applications that directly touch the hardware + (e.g. an accelerated X server) and that are not frame buffer + device-aware may cause unexpected results. If unsure, say N. + +Acorn VIDC support +CONFIG_FB_ACORN + This is the frame buffer device driver for the Acorn VIDC graphics + chipset. + +Apollo frame buffer device +CONFIG_FB_APOLLO + This is the frame buffer device driver for the monochrome graphics + hardware found in some Apollo workstations. + +Amiga native chipset support +CONFIG_FB_AMIGA + This is the frame buffer device driver for the builtin graphics + chipset found in Amigas. + +Amiga OCS chipset support +CONFIG_FB_AMIGA_OCS + This enables support for the original Agnus and Denise video chips, + found in the Amiga 1000 and most A500's and A2000's. If you intend + to run Linux on any of these systems, say Y; otherwise say N. + +Amiga ECS chipset support +CONFIG_FB_AMIGA_ECS + This enables support for the Enhanced Chip Set, found in later + A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If + you intend to run Linux on any of these systems, say Y; otherwise + say N. + +Amiga AGA chipset support +CONFIG_FB_AMIGA_AGA + This enables support for the Advanced Graphics Architecture (also + known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T + and CD32. If you intend to run Linux on any of these systems, say Y; + otherwise say N. + +Amiga CyberVision support +CONFIG_FB_CYBER + This enables support for the Cybervision 64 graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64 or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the + Cybervision 64 3D card, as they use incompatible video chips. + +Amiga CyberVision3D support (EXPERIMENTAL) +CONFIG_FB_VIRGE + This enables support for the Cybervision 64/3D graphics card from + Phase5. Please note that its use is not all that intuitive (i.e. if + you have any questions, be sure to ask!). Say N unless you have a + Cybervision 64/3D or plan to get one before you next recompile the + kernel. Please note that this driver DOES NOT support the older + Cybervision 64 card, as they use incompatible video chips. + +Amiga RetinaZ3 support (EXPERIMENTAL) +CONFIG_FB_RETINAZ3 + This enables support for the Retina Z3 graphics card. Say N unless + you have a Retina Z3 or plan to get one before you next recompile + the kernel. + +Cirrus Logic generic driver (EXPERIMENTAL) +CONFIG_FB_CLGEN + This enables support for Cirrus Logic GD542x/543x based boards on + Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. + + If you have a PCI-based system, this enables support for these + chips: GD-543x, GD-544x, GD-5480. + + Please read the file Documentation/fb/clgenfb.txt. + + Say N unless you have such a graphics board or plan to get one + before you next recompile the kernel. + +Permedia2 support (EXPERIMENTAL) +CONFIG_FB_PM2 + Say Y here if this is your graphics board. + +Apollo support +CONFIG_APOLLO + Say Y here if you want to run Linux on an MC680x0-based Apollo + Domain workstation such as the DN3500. + +Apollo 3c505 support +CONFIG_APOLLO_ELPLUS + Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card. + If you don't have one made for Apollos, you can use one from a PC, + except that your Apollo won't be able to boot from it (because the + code in the ROM will be for a PC). + +Atari native chipset support +CONFIG_FB_ATARI + This is the frame buffer device driver for the builtin graphics + chipset found in Ataris. + +Open Firmware frame buffer device support +CONFIG_FB_OF + Say Y if you want support with Open Firmware for your graphics + board. + +S3 Trio frame buffer device support +CONFIG_FB_S3TRIO + If you have a S3 Trio say Y. Say N for S3 Virge. + +ATI Mach64 display support +CONFIG_FB_ATY (EXPERIMENTAL) + This driver supports graphics boards with the ATI Mach64 chips. + Say Y if you have such a graphics board. + + The driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called atyfb.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +PowerMac "control" frame buffer device support +CONFIG_FB_CONTROL + This driver supports a frame buffer for the graphics adapter in the + Power Macintosh 7300 and others. + +PowerMac "platinum" frame buffer device support +CONFIG_FB_PLATINUM + This driver supports a frame buffer for the "platinum" graphics + adapter in some Power Macintoshes. + +PowerMac "valkyrie" frame buffer device support +CONFIG_FB_VALKYRIE + This driver supports a frame buffer for the "valkyrie" graphics + adapter in some Power Macintoshes. + +Chips 65550 display support +CONFIG_FB_CT65550 + This is the frame buffer device driver for the Chips & Technologies + 65550 graphics chip in PowerBooks. + +Mac frame buffer device +CONFIG_FB_MAC + This is the frame buffer device driver for the graphics hardware in + m68k Macintoshes. + +HP300 frame buffer device +CONFIG_FB_HP300 + This is the frame buffer device driver for the Topcat graphics + hardware found in HP300 workstations. + +TGA frame buffer support +CONFIG_FB_TGA + This is the frame buffer device driver for generic TGA graphic + cards. Say Y if you have one of those. + +VESA VGA graphics console +CONFIG_FB_VESA + This is the frame buffer device driver for generic VESA 2.0 + compliant graphic cards. The older VESA 1.2 cards are not supported. + You will get a boot time penguin logo at no additional cost. Please + read Documentation/fb/vesafb.txt. If unsure, say Y. + +VGA 16-color graphics console +CONFIG_FB_VGA16 + This is the frame buffer device driver for VGA 16 color graphic + cards. Say Y if you have such a card. + + This code is also available as a module. If you want to compile it + as a module ( = code which can be inserted in and removed from the + running kernel whenever you want), say M here and read + Documentation/modules.txt. The module will be called vga16fb.o. + +Backward compatibility mode for Xpmac +CONFIG_FB_COMPAT_XPMAC + If you use the Xpmac X server (common with mklinux), you'll need to + say Y here to use X. You should consider changing to XFree86 which + includes a server that supports the frame buffer device directly + (XF68_FBDev). + +Matrox unified accelerated driver (EXPERIMENTAL) +CONFIG_FB_MATROX + Say Y here if you have Matrox Millennium, Matrox Millennium II, + Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox + Mystique G200, Matrox Millennium G200 or Matrox Marvel G200 video + card in your box. At this time, support for the G100, Mystique G200 + and Marvel G200 is untested. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). + The module will be called matroxfb.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + + You can pass several parameters to the driver at boot time or at + module load time. The parameters look like "video=matrox:XXX", where + the meaning of XXX can be found at the end of the main source file + (drivers/video/matroxfb.c). Please see the file + Documentation/fb/matroxfb.txt. + +Matrox Millennium support +CONFIG_FB_MATROX_MILLENIUM + Say Y here if you have a Matrox Millennium or Matrox Millennium II + video card. If you select "Advanced lowlevel driver options" below, + you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp + packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can + also use font widths different from 8. + +Matrox Mystique support +CONFIG_FB_MATROX_MYSTIQUE + Say Y here if you have a Matrox Mystique or Matrox Mystique 220 + video card. If you select "Advanced lowlevel driver options" below, + you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp + packed pixel and 32 bpp packed pixel. You can also use font widths + different from 8. + +Matrox G100/G200/G400 support +CONFIG_FB_MATROX_G100 + Say Y here if you have a Matrox Productiva G100, Matrox Mystique + G200, Matrox Marvel G200 or Matrox Millennium G200 video card. If + you select "Advanced lowlevel driver options", you should check 8 + bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and 32 + bpp packed pixel. You can also use font widths different from 8. + +Matrox unified driver multihead support +CONFIG_FB_MATROX_MULTIHEAD + Say Y here if you have more than one (supported) Matrox device in + your computer and you want to use all of them. If you have only one + device, you should say N because the driver compiled with Y is + larger and a bit slower, especially on ia32 (ix86). + + If you said M to "Matrox unified accelerated driver" and N here, you + will still be able to use several Matrox devices simultaneously. + This is slightly faster but uses 40 KB of kernel memory per Matrox + card. You do this by inserting several instances of the module + matroxfb.o into the kernel with insmod, supplying the parameter + "dev=N" where N is 0, 1, etc. for the different Matrox devices. + +MDA text console (dual-headed) +CONFIG_MDA_CONSOLE + Say Y here if you have an old MDA or monochrome Hercules graphics + adapter in your system acting as a second head ( = video card). You + will then be able to use two monitors with your Linux system. Do not + say Y here if your MDA card is the primary card in your system; the + normal VGA driver will handle it. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). + The module will be called mdacon.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + + If unsure, say N. + +SBUS and UPA frame buffers +CONFIG_FB_SBUS + Say Y if you want support for SBUS or UPA based frame buffer device. + +Creator/Creator3D support +CONFIG_FB_CREATOR + This is the frame buffer device driver for the Creator and Creator3D + graphics boards. + +CGsix (GX,TurboGX) support +CONFIG_FB_CGSIX + This is the frame buffer device driver for the CGsix (GX, TurboGX) + frame buffer. + +BWtwo support +CONFIG_FB_BWTWO + This is the frame buffer device driver for the BWtwo frame buffer. + +CGthree support +CONFIG_FB_CGTHREE + This is the frame buffer device driver for the CGthree frame buffer. + +TCX (SS4/SS5 only) support +CONFIG_FB_TCX + This is the frame buffer device driver for the TCX 24/8bit frame + buffer. + +Virtual Frame Buffer support (ONLY FOR TESTING!) +CONFIG_FB_VIRTUAL + This is a `virtual' frame buffer device. It operates on a chunk of + unswapable kernel memory instead of on the memory of a graphics + board. This means you cannot see any output sent to this frame + buffer device, while it does consume precious memory. The main use + of this frame buffer device is testing and debugging the frame + buffer subsystem. Do NOT enable it for normal systems! To protect + the innocent, it has to be enabled explicitly at boot time using the + kernel option `video=vfb:'. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called vfb.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. + + If unsure, say N. + +Advanced low level driver options +CONFIG_FBCON_ADVANCED + The frame buffer console uses character drawing routines that are + tailored to the specific organization of pixels in the memory of + your graphics hardware. These are called the low level frame buffer + console drivers. Note that they are used for text console output + only; they are NOT needed for graphical applications. + + If you say N here, the needed low level drivers are automatically + enabled, depending on what frame buffer devices you selected above. + This is recommended for most users. + + If you say Y here, you have more fine-grained control over which low + level drivers are enabled. You can e.g. leave out low level drivers + for color depths you do not intend to use for text consoles. + + Low level frame buffer console drivers can be modules ( = code which + can be inserted and removed from the running kernel whenever you + want). The modules will be called fbcon-*.o. If you want to compile + (some of) them as modules, read Documentation/modules.txt. + + If unsure, say N. + +Monochrome support +CONFIG_FBCON_MFB + This is the low level frame buffer console driver for monochrome + (2 colors) packed pixels. + +2 bpp packed pixels support +CONFIG_FBCON_CFB2 + This is the low level frame buffer console driver for 2 bits per + pixel (4 colors) packed pixels. + +4 bpp packed pixels support +CONFIG_FBCON_CFB4 + This is the low level frame buffer console driver for 4 bits per + pixel (16 colors) packed pixels. + +8 bpp packed pixels support +CONFIG_FBCON_CFB8 + This is the low level frame buffer console driver for 8 bits per + pixel (256 colors) packed pixels. + +16 bpp packed pixels support +CONFIG_FBCON_CFB16 + This is the low level frame buffer console driver for 15 or 16 bits + per pixel (32K or 64K colors, also known as `hicolor') packed + pixels. + +24 bpp packed pixels support +CONFIG_FBCON_CFB24 + This is the low level frame buffer console driver for 24 bits per + pixel (16M colors, also known as `truecolor') packed pixels. It is + NOT for `sparse' 32 bits per pixel mode. + +32 bpp packed pixels support +CONFIG_FBCON_CFB32 + This is the low level frame buffer console driver for 32 bits per + pixel (16M colors, also known as `truecolor') sparse packed pixels. + +Amiga bitplanes support +CONFIG_FBCON_AFB + This is the low level frame buffer console driver for 1 to 8 + bitplanes (2 to 256 colors) on Amiga. + +Amiga interleaved bitplanes support +CONFIG_FBCON_ILBM + This is the low level frame buffer console driver for 1 to 8 + interleaved bitplanes (2 to 256 colors) on Amiga. + +Atari interleaved bitplanes (2 planes) support +CONFIG_FBCON_IPLAN2P2 + This is the low level frame buffer console driver for 2 interleaved + bitplanes (4 colors) on Atari. + +Atari interleaved bitplanes (4 planes) support +CONFIG_FBCON_IPLAN2P4 + This is the low level frame buffer console driver for 4 interleaved + bitplanes (16 colors) on Atari. + +Atari interleaved bitplanes (8 planes) support +CONFIG_FBCON_IPLAN2P8 + This is the low level frame buffer console driver for 8 interleaved + bitplanes (256 colors) on Atari. + +Mac variable bpp packed pixels support +CONFIG_FBCON_MAC + This is the low level frame buffer console driver for 1/2/4/8/16/32 + bits per pixel packed pixels on Mac. It supports variable font + widths for low resolution screens. + +#VGA 16-color planar support +#CONFIG_FBCON_VGA_PLANES +### +###What is this? +### + +VGA characters/attributes support +CONFIG_FBCON_VGA + This is the low level frame buffer console driver for VGA text mode; + it is used by frame buffer device drivers that support VGA text + mode. + +Parallel-port support +CONFIG_PARPORT + If you want to use devices connected to your machine's parallel port + (the connector at the computer with 25 holes), e.g. printer, ZIP + drive, PLIP link (Parallel Line Internet Protocol is mainly used to + create a mini network by connecting the parallel ports of two local + machines) etc., then you need to say Y here; please read + Documentation/parport.txt and drivers/misc/BUGS-parport. + + For extensive information about drivers for many devices attaching + to the parallel port see http://www.torque.net/linux-pp.html on the + WWW. + + It is possible to share a single parallel port among several devices + and it is safe to compile all the corresponding drivers into the + kernel. If you want to compile parallel port support as a module ( = + code which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt. + The module will be called parport.o. If you have more than one + parallel port and want to specify which port and IRQ to be used by + this driver at module load time, take a look at + Documentation/networking/parport.txt. + + If unsure, say Y. + +PC-style hardware +CONFIG_PARPORT_PC + You should say Y here if you have a PC-style parallel port. All IBM + PC compatible computers and some Alphas have PC-style parallel + ports. + + This code is also available as a module. If you want to compile it + as a module ( = code which can be inserted in and removed from the + running kernel whenever you want), say M here and read + Documentation/modules.txt. The module will be called parport_pc.o. + + If unsure, say Y. + +Use FIFO/DMA if available +CONFIG_PARPORT_PC_FIFO + Many parallel port chipsets provide hardware that can speed up + printing. Say Y here if you want to take advantage of that. + + As well as actually having a FIFO, or DMA capability, the kernel + will need to know which IRQ the parallel port has. By default, + parallel port interrupts will not be used, and so neither will the + FIFO. See Documentation/parport.txt to find out how to specify + which IRQ/DMA to use. + +Support for PCMCIA management for PC-style ports +CONFIG_PARPORT_PC_PCMCIA + Say Y here if you need PCMCIA support for your PC-style parallel + ports. If unsure, say N. + +Support foreign hardware +CONFIG_PARPORT_OTHER + Say Y here if you want to be able to load driver modules to support + other non-standard types of parallel ports. This causes a + performance loss, so most people say N. + +Sun Ultra/AX-style hardware +CONFIG_PARPORT_AX + Say Y here if you need support for the parallel port hardware on Sun + Ultra/AX machines. This code is also available as a module (say M), + called parport_ax.o. If in doubt, saying N is the safe plan. + +IEEE1284 transfer modes +CONFIG_PARPORT_1284 + If you have a printer that supports status readback or device ID, or + want to use a device that uses enhanced parallel port transfer modes + such as EPP and ECP, say Y here to enable advanced IEEE 1284 + transfer modes. Also say Y if you want device ID information to + appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N. + +Enable loadable module support +CONFIG_MODULES + Kernel modules are small pieces of compiled code which can be + inserted in or removed from the running kernel, using the programs + insmod and rmmod. This is described in the file + Documentation/modules.txt, including the fact that you have to say + "make modules" in order to compile the modules that you chose during + kernel configuration. Modules can be device drivers, file systems, + binary executable formats, and so on. If you think that you may want + to make use of modules with this kernel in the future, then say Y + here. If unsure, say Y. + +Set version information on all symbols for modules +CONFIG_MODVERSIONS + Usually, modules have to be recompiled whenever you switch to a new + kernel. Saying Y here makes it possible, and safe, to use the + same modules even after compiling a new kernel; this requires the + program modprobe. All the software needed for module support is in + the modutils package (check the file Documentation/Changes for + location and latest version). NOTE: if you say Y here but don't + have the program genksyms (which is also contained in the above + mentioned modutils package), then the building of your kernel will + fail. If you are going to use modules that are generated from + non-kernel sources, you would benefit from this option. Otherwise + it's not that important. So, N ought to be a safe bet. + +Kernel module loader support +CONFIG_KMOD + Normally when you have selected some drivers and/or filesystems to + be created as loadable modules, you also have the responsibility to + load the corresponding modules (using the programs insmod or + modprobe) before you can use them. If you say Y here however, the + kernel will be able to load modules for itself: when a part of the + kernel needs a module, it runs modprobe with the appropriate + arguments, thereby loading the module if it is available. (This is a + replacement for kerneld.) Say Y here and read about configuring it + in Documentation/kmod.txt. + +ARP daemon support (EXPERIMENTAL) +CONFIG_ARPD + Normally, the kernel maintains an internal cache which maps IP + addresses to hardware addresses on the local network, so that + Ethernet/Token Ring/ etc. frames are sent to the proper address on + the physical networking layer. For small networks having a few + hundred directly connected hosts or less, keeping this address + resolution (ARP) cache inside the kernel works well. However, + maintaining an internal ARP cache does not work well for very large + switched networks, and will use a lot of kernel memory if TCP/IP + connections are made to many machines on the network. + + If you say Y here, the kernel's internal ARP cache will never grow + to more than 256 entries (the oldest entries are expired in a LIFO + manner) and communication will be attempted with the user space ARP + daemon arpd. Arpd then answers the address resolution request either + from its own cache or by asking the net. + + This code is experimental and also obsolete. If you want to use it, + you need to find a version of the daemon arpd on the net somewhere, + and you should also say Y to "Kernel/User network link driver", + below. If unsure, say N. + +TCP/IP networking +CONFIG_INET + These are the protocols used on the Internet and on most local + Ethernets. It is highly recommended to say Y here (this will enlarge + your kernel by about 144 KB), since some programs (e.g. the X window + system) use TCP/IP even if your machine is not connected to any + other computer. You will get the so-called loopback device which + allows you to ping yourself (great fun, that!). + + For an excellent introduction to Linux networking, please read the + NET-3-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This option is also necessary if you want to use the full power of + term (term is a program which gives you almost full Internet + connectivity if you have a regular dial up shell account on some + Internet connected Unix computer; for more information, read + http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ). + + If you say Y here and also to "/proc filesystem support" and "Sysctl + support" below, you can change various aspects of the behavior of + the TCP/IP code by writing to the (virtual) files in + /proc/sys/net/ipv4/*; the options are explained in the file + Documentation/Networking/ip-sysctl.txt. + + Short answer: say Y. + +IP: multicasting +CONFIG_IP_MULTICAST + This is code for addressing several networked computers at once, + enlarging your kernel by about 2 kB. You need multicasting if you + intend to participate in the MBONE, a high bandwidth network on top + of the Internet which carries audio and video broadcasts. More + information about the MBONE is on the WWW at + http://www-itg.lbl.gov/mbone/ . Information about the multicast + capabilities of the various network cards is contained in + Documentation/networking/multicast.txt. For most people, it's safe + to say N. + +IP: advanced router +CONFIG_IP_ADVANCED_ROUTER + If you intend to run your Linux box mostly as a router, i.e. as a + computer that forwards and redistributes network packets, say Y; you + will then be presented with several options that allow more precise + control about the routing process. + + The answer to this question won't directly affect the kernel: + answering N will just cause this configure script to skip all the + questions about advanced routing. + + Note that your box can only act as a router if you enable IP + forwarding in your kernel; you can do that by saying Y to "/proc + filesystem support" and "Sysctl support" below and executing the + line + + echo "1" > /proc/sys/net/ipv4/ip_forward + + at boot time after the /proc filesystem has been mounted. + + If you turn on IP forwarding, you will also get the rp_filter, which + automatically rejects incoming packets if the routing table entry + for their source address doesn't match the network interface they're + arriving on. This has security advantages because it prevents the + so-called IP spoofing, however it can pose problems if you use + asymmetric routing (packets from you to a host take a different path + than packets from that host to you) or if you operate a non-routing + host which has several IP addresses on different interfaces. To turn + rp_filter off use: + + echo 0 > /proc/sys/net/ipv4/conf//rp_filter + or + echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter + + If unsure, say N here. + +IP: policy routing +CONFIG_IP_MULTIPLE_TABLES + Normally, a router decides what to do with a received packet based + solely on the packet's final destination address. If you say Y here, + the Linux router will also be able to take the packet's source + address into account. Furthermore, if you also say Y to "IP: use TOS + value as routing key" below, the TOS (Type-Of-Service) field of the + packet can be used for routing decisions as well. In addition, if + you say Y here and to "IP: fast network address translation" below, + the router will also be able to modify source and destination + addresses of forwarded packets. + + If you are interested in this, please see the preliminary + documentation at http://www.compendium.com.ar/policy-routing.txt and + ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex . You + will need supporting software from ftp://ftp.inr.ac.ru/ip-routing/ + + If unsure, say N. + +IP: equal cost multipath +CONFIG_IP_ROUTE_MULTIPATH + Normally, the routing tables specify a single action to be taken in + a deterministic manner for a given packet. If you say Y here + however, it becomes possible to attach several actions to a packet + pattern, in effect specifying several alternative paths to travel + for those packets. The router considers all these paths to be of + equal "cost" and chooses one of them in a non-deterministic fashion + if a matching packet arrives. + +IP: use TOS value as routing key +CONFIG_IP_ROUTE_TOS + The header of every IP packet carries a TOS (Type of Service) value + with which the packet requests a certain treatment, e.g. low latency + (for interactive traffic), high throughput, or high reliability. If + you say Y here, you will be able to specify different routes for + packets with different TOS values. + +IP: use FWMARK value as routing key +CONFIG_IP_ROUTE_FWMARK + If you say Y here, you will be able to specify different routes for + packets with different FWMARK ("firewalling mark") values + (see ipchains(8), "-m" argument). + +IP: verbose route monitoring +CONFIG_IP_ROUTE_VERBOSE + If you say Y here, which is recommended, then the kernel will print + verbose messages regarding the routing, for example warnings about + received packets which look strange and could be evidence of an + attack or a misconfigured system somewhere. The information is + handled by the klogd daemon which is responsible for kernel messages + ("man klogd"). + +IP: large routing tables +CONFIG_IP_ROUTE_LARGE_TABLES + If you have routing zones that grow to more than about 64 entries, + you may want to say Y here to speed up the routing process. + +IP: fast network address translation +CONFIG_IP_ROUTE_NAT + If you say Y here, your router will be able to modify source and + destination addresses of packets that pass through it, in a manner + you specify. General information about Network Address Translation + can be gotten from the document + http://www.csn.tu-chemnitz.de/~mha/linux-ip-nat/diplom/nat.html + +IP: optimize as router not host +CONFIG_IP_ROUTER + Some Linux network drivers use a technique called copy and checksum + to optimize host performance. For a machine which acts as a router + most of the time and is forwarding most packets to another host this + is however a loss. If you say Y here, copy and checksum will be + switched off. In the future, it may make other changes which + optimize for router operation. + + Note that your box can only act as a router if you enable IP + forwarding in your kernel; you can do that by saying Y to "/proc + filesystem support" and "Sysctl support" below and executing the + line + + echo "1" > /proc/sys/net/ipv4/ip_forward + + at boot time after the /proc filesystem has been mounted. You can do + that even if you say N here. + + If unsure, say N here. + +IP: kernel level autoconfiguration +CONFIG_IP_PNP + This enables automatic configuration of IP addresses of devices and + of the routing table during kernel boot, based on either information + supplied at the kernel command line or by BOOTP or RARP protocols. + You need to say Y only for diskless machines requiring network + access to boot (in which case you want to say Y to "Root file system + on NFS" as well), because all other machines configure the network + in their startup scripts. + +BOOTP support +CONFIG_IP_PNP_BOOTP + If you want your Linux box to mount its whole root filesystem (the + one containing the directory /) from some other computer over the + net via NFS and you want the IP address of your computer to be + discovered automatically at boot time using the BOOTP protocol (a + special protocol designed for doing this job), say Y here. In case + the boot ROM of your network card was designed for booting Linux and + does BOOTP itself, providing all necessary information on the kernel + command line, you can say N here. If unsure, say Y. Note that if you + want to use BOOTP, a BOOTP server must be operating on your network. + Read Documentation/nfsroot.txt for details. + +RARP support +CONFIG_IP_PNP_RARP + If you want your Linux box to mount its whole root filesystem (the + one containing the directory /) from some other computer over the + net via NFS and you want the IP address of your computer to be + discovered automatically at boot time using the RARP protocol (an + older protocol which is being obsoleted by BOOTP and DHCP), say Y + here. Note that if you want to use RARP, a RARP server must be + operating on your network. Read Documentation/nfsroot.txt for + details. + +IP: tunneling +CONFIG_NET_IPIP + Tunneling means encapsulating data of one protocol type within + another protocol and sending it over a channel that understands the + encapsulating protocol. This particular tunneling driver implements + encapsulation of IP within IP, which sounds kind of pointless, but + can be useful if you want to make your (or some other) machine + appear on a different network than it physically is, or to use + mobile-IP facilities (allowing laptops to seamlessly move between + networks without changing their IP addresses; check out + http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html ). + + Saying Y to this option will produce two modules ( = code which can + be inserted in and removed from the running kernel whenever you + want). Most people won't need this and can say N. + +IP: GRE tunnels over IP +CONFIG_NET_IPGRE + Tunneling means encapsulating data of one protocol type within + another protocol and sending it over a channel that understands the + encapsulating protocol. This particular tunneling driver implements + GRE (Generic Routing Encapsulation) and at this time allows + encapsulating of IPv4 or IPv6 over existing IPv4 infrastructure. + This driver is useful if the other endpoint is a Cisco router: Cisco + likes GRE much better than the other Linux tunneling driver ("IP: + tunneling" above). In addition, GRE allows multicast redistribution + through the tunnel. + +IP: broadcast GRE over IP +CONFIG_NET_IPGRE_BROADCAST + One application of GRE/IP is to construct a broadcast WAN (Wide Area + Network), which looks like a normal Ethernet LAN (Local Area + Network), but can be distributed all over the Internet. If you want + to do that, say Y here and to "IP: multicast routing" below. + +IP: aliasing support +CONFIG_IP_ALIAS + Sometimes it is useful to give several IP addresses to a single + physical network interface (serial port or Ethernet card). The most + common case is that you want to serve different WWW or FTP documents + to the outside depending on which of your host names was used to + connect to you. This is called "multihosting" or "virtual domains" + or "virtual hosting services" and is explained in the + Virtual-Services-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + Another scenario would be that there are two logical networks living + on your local Ethernet and you want to access them both with the + same Ethernet card. This can also be done if you say Y here. + + The configuration of these alias addresses is done with a special + name syntax explained in Documentation/networking/alias.txt and in + the IP-Alias mini-HOWTO. If you want this, say Y. Most people don't + need it and say N. + +IP: multicast routing +CONFIG_IP_MROUTE + This is used if you want your machine to act as a router for IP + packets that have several destination addresses. It is needed on the + MBONE, a high bandwidth network on top of the Internet which carries + audio and video broadcasts. In order to do that, you would most + likely run the program mrouted. Information about the multicast + capabilities of the various network cards is contained in + Documentation/networking/multicast.txt. If you haven't heard about + it, you don't need it. + +IP: PIM-SM version 1 support +CONFIG_IP_PIMSM_V1 + Kernel side support for Sparse Mode PIM (Protocol Independent + Multicast) version 1. This multicast routing protocol is used widely + because Cisco supports it. You need special software to use it + (pimd-v1). Please see http://netweb.usc.edu/pim/ for more + information about PIM. + + Say Y if you want to use PIM-SM v1. Note that you can say N here if + you just want to use Dense Mode PIM. + +IP: PIM-SM version 2 support +CONFIG_IP_PIMSM_V2 + Kernel side support for Sparse Mode PIM version 2. In order to use + this, you need an experimental routing daemon supporting it (pimd or + gated-5). This routing protocol is not used widely, so say N unless + you want to play with it. + +PC/TCP compatibility mode +CONFIG_INET_PCTCP + If you have been having difficulties telnetting to your Linux + machine from a DOS system that uses (broken) PC/TCP networking + software (all versions up to OnNet 2.0) over your local Ethernet try + saying Y here. Everyone else says N. + + People having problems with NCSA telnet should see the file + linux/Documentation/networking/ncsa-telnet. + +Assume subnets are local +CONFIG_INET_SNARL + Say Y if you are on a subnetted network with all machines connected + by Ethernet segments only, as this option optimizes network access + for this special case. If there are other connections, e.g. SLIP + links, between machines of your IP network, say N. If in doubt, + answer N. The PATH mtu discovery facility will cover most cases + anyway. + +Path MTU Discovery (normally enabled) +CONFIG_PATH_MTU_DISCOVERY + MTU (maximal transfer unit) is the size of the chunks we send out + over the net. "Path MTU Discovery" means that, instead of always + sending very small chunks, we start out sending big ones and if we + then discover that some host along the way likes its chunks smaller, + we adjust to a smaller size. This is good, so most people say Y + here. + + However, some DOS software (versions of DOS NCSA telnet and Trumpet + Winsock in PPP mode) is broken and won't be able to connect to your + Linux machine correctly in all cases (especially through a terminal + server) unless you say N here. See + Documentation/networking/ncsa-telnet for the location of fixed NCSA + telnet clients. If in doubt, say Y. + +Disable NAGLE algorithm (normally enabled) +CONFIG_TCP_NAGLE_OFF + The NAGLE algorithm works by requiring an acknowledgment before + sending small IP frames (packets). This keeps tiny telnet and + rlogin packets from congesting Wide Area Networks. Most people + strongly recommend to say N here, thereby leaving NAGLE + enabled. Those programs that would benefit from disabling this + facility can do it on a per connection basis themselves. + +IP: Allow large windows (not recommended if <16 MB of memory) +CONFIG_SKB_LARGE + On high speed, long distance networks the performance limit on + networking becomes the amount of data the sending machine can buffer + until the other end confirms its reception. (At 45 Mbit/second there + are a lot of bits between New York and London ...). If you say Y + here, bigger buffers can be used which allows larger amounts of data + to be "in flight" at any given time. It also means a user process + can require a lot more memory for network buffers and thus this + option is best used only on machines with 16 MB of memory or higher. + Unless you are using long links with end to end speeds of over 2 + Mbit a second or satellite links this option will make no difference + to performance. + +Unix domain sockets +CONFIG_UNIX + If you say Y here, you will include support for Unix domain sockets; + sockets are the standard Unix mechanism for establishing and + accessing network connections. Many commonly used programs such as + the X Window system and syslog use these sockets even if your + machine is not connected to any network. Unless you are working on + an embedded system or something similar, you therefore definitely + want to say Y here. + + However, the socket support is also available as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. The module will be called + unix.o. If you try building this as a module and you have said Y to + "Kernel module loader support" above, be sure to add 'alias net-pf-1 + unix' to your /etc/modules.conf file. Note that several important + services won't work correctly if you say M here and then neglect to + load the module. + + Say Y unless you know what you are doing. + +The IPv6 protocol (EXPERIMENTAL) +CONFIG_IPV6 + This is experimental support for the next version of the Internet + Protocol: IP version 6 (also called IPng "IP next generation"). + Features of this new protocol include: expanded address space, + authentication and privacy, and seamless interoperability with the + current version of IP (IP version 4). For general information about + IPv6, see http://playground.sun.com/pub/ipng/html/ipng-main.html ; + for specific information about IPv6 under Linux read the HOWTO at + http://www.bieringer.de/linux/IPv6/ and the file net/ipv6/README in + the kernel source. + + If you want to use IPv6, please upgrade to the newest net-tools as + given in Documentation/Changes. You will still be able to do regular + IPv4 networking as well. + + This protocol support is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module will be called ipv6.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + + It is safe to say N here for now. + +IPv6: enable EUI-64 token format +CONFIG_IPV6_EUI64 + 6bone, the network of computers using the IPv6 protocol, is moving + to a new aggregatable address format and a new link local address + assignment (EUI-64). Say Y if your site has upgraded already, or + has started to upgrade. + +IPv6: disable provider based addresses +CONFIG_IPV6_NO_PB + Linux tries to operate correctly when your site has moved to EUI-64 + only partially. Unfortunately, the two address formats (old: + "provider based" and new: "aggregatable") are incompatible. Say Y if + your site finished the upgrade to EUI-64, and/or you encountered + some problems caused by the presence of two link-local addresses on + an interface. + +IPv6: routing messages via old netlink +CONFIG_IPV6_NETLINK + You can say Y here to receive routing messages from the IPv6 code + through the old netlink interface. However, a better option is to + say Y to "Kernel/User network link driver" and to "Routing + messages" instead. + +IPX networking +CONFIG_IPX + This is support for the Novell networking protocol, IPX, commonly + used for local networks of Windows machines. You need it if you want + to access Novell NetWare file or print servers using the Linux + Novell client ncpfs (available from + ftp://metalab.unc.edu/pub/Linux/system/filesystems/ ) or from within + the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto ). In order to do the + former, you'll also have to say Y to "NCP filesystem support", + below. + + IPX is similar in scope to IP, while SPX, which runs on top of IPX, + is similar to TCP. There is also experimental support for SPX in + Linux (see "SPX networking", below). + + To turn your Linux box into a fully featured NetWare file server and + IPX router, say Y here and fetch either lwared from + ftp://metalab.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe + from ftp://ftp.gwdg.de/pub/linux/misc/ncpfs . For more information, + read the IPX-HOWTO available from + http://metalab.unc.edu/mdw/linux.html#howto . + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at http://www.eats.com/linux_mac_win.html . + + The IPX driver would enlarge your kernel by about 16 KB. This driver + is also available as a module ( = code which can be inserted in and + removed from the running kernel whenever you want). The module will + be called ipx.o. If you want to compile it as a module, say M here + and read Documentation/modules.txt. Unless you want to integrate + your Linux box with a local Novell network, say N. + +IPX: Full internal IPX network +CONFIG_IPX_INTERN + Every IPX network has an address that identifies it. Sometimes it is + useful to give an IPX "network" address to your Linux box as well + (for example if your box is acting as a file server for different + IPX networks: it will then be accessible from everywhere using the + same address). The way this is done is to create a virtual internal + "network" inside your box and to assign an IPX address to this + network. Say Y here if you want to do this; read the IPX-HOWTO at + http://metalab.unc.edu/mdw/linux.html#howto for details. + + The full internal IPX network enables you to allocate sockets on + different virtual nodes of the internal network. This is done by + evaluating the field sipx_node of the socket address given to the + bind call. So applications should always initialize the node field + to 0 when binding a socket on the primary network. In this case the + socket is assigned the default node that has been given to the + kernel when the internal network was created. By enabling the full + internal IPX network the cross-forwarding of packets targeted at + 'special' sockets to sockets listening on the primary network is + disabled. This might break existing applications, especially RIP/SAP + daemons. A RIP/SAP daemon that works well with the full internal net + can be found on ftp://ftp.gwdg.de/pub/linux/misc/ncpfs . + + If you don't know what you are doing, say N. + +IPX: SPX networking (EXPERIMENTAL) +CONFIG_SPX + The Sequenced Packet eXchange protocol is a transport layer protocol + built on top of IPX. It is used in Novell NetWare systems for + client-server applications and is similar to TCP (which runs on top + of IP). + + Note that Novell NetWare file sharing does not use SPX; it uses a + protocol called NCP, for which separate Linux support is available + ("NCP filesystem support" below for the client side, and the user + space programs lwared or mars_nwe for the server side). + + Say Y here if you have use for SPX; read the IPX-HOWTO at + http://metalab.unc.edu/mdw/linux.html#howto for details. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called af_spx.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +DECnet networking (EXPERIMENTAL) +CONFIG_DECNET + The DECnet networking protocol was used in many products made by + Digital (now Compaq). It provides reliable stream and sequenced + packet communications over which run a variety of services similar + to those which run over TCP/IP. + + To find some tools to use with the kernel layer support, please + look at Patrick Caulfield's web site: + http://linux.dreamtime.org/decnet/ + + More detailed documentation is available in the + Documentation/networking/decnet.txt file. + + Be sure to say Y to "/proc filesystem support" and "Sysctl support" + below when using DECnet, since you will need sysctl support to aid + in configuration at run time. + + The DECnet code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called decnet.o. + +DECnet SIOCFIGCONF support +CONFIG_DECNET_SIOCGIFCONF + This option should only be turned on if you are really sure that + you know what you are doing. It can break other applications which + use this system call and the proper way to get the information + provided by this call is to use rtnetlink. + + If unsure, say N. + +DECnet Router Support (EXPERIMENTAL) +CONFIG_DECNET_ROUTER + Add support for turning your DECnet Endnode into a level 1 or 2 + router. This is an unfinished option for developers only. If you do + turn it on, then make sure that you also say Y to "Kernel/User + network link driver" and "Routing messages", since rtnetlink is the + only current method of configuration. + +DECnet Raw Socket Support +CONFIG_DECNET_RAW + Add support for the SOCK_RAW type under DECnet. Used by userland + routing programs to receive routing messages from the kernel and + also as a general debugging aid to see what's going on "under the + hood". + +AppleTalk DDP +CONFIG_ATALK + AppleTalk is the way Apple computers speak to each other on a + network. If your Linux box is connected to such a network and you + want to join the conversation, say Y. You will need to use the + netatalk package so that your Linux box can act as a print and file + server for Macs as well as access AppleTalk printers. Check out + http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW + for details. EtherTalk is the name used for AppleTalk over Ethernet + and the cheaper and slower LocalTalk is AppleTalk over a proprietary + Apple network using serial links. EtherTalk and LocalTalk are fully + supported by Linux. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at http://www.eats.com/linux_mac_win.html The + NET-3-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , contains valuable + information as well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called appletalk.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. I hear that + the GNU boycott of Apple is over, so even politically correct people + are allowed to say Y here. + +AppleTalk-IP driver support +CONFIG_IPDDP + This allows IP networking for users who only have AppleTalk + networking available. This feature is experimental. With this + driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux + box is stuck on an AppleTalk only network) or decapsulate (e.g. if + you want your Linux box to act as an Internet gateway for a zoo of + AppleTalk connected Macs). Please see the file + Documentation/networking/ipddp.txt for more information. + + If you say Y here, the AppleTalk-IP support will be compiled into + the kernel. In this case, you can either use encapsulation or + decapsulation, but not both. With the following two questions, you + decide which one you want. + + If you say M here, the AppleTalk-IP support will be compiled as a + module ( = code which can be inserted in and removed from the + running kernel whenever you want, read Documentation/modules.txt). + The module is called ipddp.o. In this case, you will be able to use + both encapsulation and decapsulation simultaneously, by loading two + copies of the module and specifying different values for the module + option ipddp_mode. + +IP to AppleTalk-IP Encapsulation support +CONFIG_IPDDP_ENCAP + If you say Y here, the AppleTalk-IP code will be able to encapsulate + IP packets inside AppleTalk frames; this is useful if your Linux box + is stuck on an AppleTalk network (which hopefully contains a + decapsulator somewhere). Please see + Documentation/networking/ipddp.txt for more information. If you said + Y to "AppleTalk-IP driver support" above and you say Y here, then + you cannot say Y to "AppleTalk-IP to IP Decapsulation support", + below. + +AppleTalk-IP to IP Decapsulation support +CONFIG_IPDDP_DECAP + If you say Y here, the AppleTalk-IP code will be able to decapsulate + AppleTalk-IP frames to IP packets; this is useful if you want your + Linux box to act as an Internet gateway for an AppleTalk network. + Please see Documentation/networking/ipddp.txt for more information. + If you said Y to "AppleTalk-IP driver support" above and you say Y + here, then you cannot say Y to "IP to AppleTalk-IP Encapsulation + support", above. + +Apple/Farallon LocalTalk PC card support +CONFIG_LTPC + This allows you to use the AppleTalk PC card to connect to LocalTalk + networks. The card is also known as the Farallon PhoneNet PC card. + If you are in doubt, this card is the one with the 65C02 chip on it. + You also need version 1.3.3 or later of the netatalk package. + This driver is experimental, which means that it may not work. + See the file Documentation/networking/ltpc.txt. + +COPS LocalTalk PC card support +CONFIG_COPS + This allows you to use COPS AppleTalk cards to connect to LocalTalk + networks. You also need version 1.3.3 or later of the netatalk + package. This driver is experimental, which means that it may not + work. This driver will only work if you choose "AppleTalk DDP" + networking support, above. + Please read the file Documentation/networking/cops.txt. + +Dayna firmware support +CONFIG_COPS_DAYNA + Support COPS compatible cards with Dayna style firmware (Dayna + DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC + III, Farallon PhoneNET PC II). + +Tangent firmware support +CONFIG_COPS_TANGENT + Support COPS compatible cards with Tangent style firmware (Tangent + ATB_II, Novell NL-1000, Daystar Digital LT-200. + +Amateur Radio support +CONFIG_HAMRADIO + If you want to connect your Linux box to an amateur radio, answer Y + here. You want to read http://www.tapr.org/tapr/html/pkthome.html + and the HAM-HOWTO and the AX25-HOWTO, both available from + http://metalab.unc.edu/mdw/linux.html#howto . + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about amateur radio. + +Amateur Radio AX.25 Level 2 +CONFIG_AX25 + This is the protocol used for computer communication over amateur + radio. It is either used by itself for point-to-point links, or to + carry other protocols such as tcp/ip. To use it, you need a device + that connects your Linux box to your amateur radio. You can either + use a low speed TNC (a Terminal Node Controller acts as a kind of + modem connecting your computer's serial port to your radio's + microphone input and speaker output) supporting the KISS protocol or + one of the various SCC cards that are supported by the generic Z8530 + or the DMA SCC driver. Another option are the Baycom modem serial + and parallel port hacks or the sound card modem (supported by their + own drivers). If you say Y here, you also have to say Y to one of + those drivers. + + Information about where to get supporting software for Linux amateur + radio as well as information about how to configure an AX.25 port is + contained in the AX25-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . You might also want to + check out the file Documentation/networking/ax25.txt in the kernel + source. More information about digital amateur radio in general is + on the WWW at http://www.tapr.org/tapr/html/pkthome.html . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ax25.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +AX.25 DAMA Slave support +CONFIG_AX25_DAMA_SLAVE + DAMA is a mechanism to prevent collisions when doing AX.25 + networking. A DAMA server (called "master") accepts incoming traffic + from clients (called "slaves") and redistributes it to other slaves. + If you say Y here, your Linux box will act as a DAMA slave; this is + transparent in that you don't have to do any special DAMA + configuration. (Linux cannot yet act as a DAMA server.) If unsure, + say N. + +AX.25 DAMA Master support +CONFIG_AX25_DAMA_MASTER + DAMA is a mechanism to prevent collisions when doing AX.25 + networking. A DAMA server (called "master") accepts incoming traffic + from clients (called "slaves") and redistributes it to other + slaves. If you say Y here, your Linux box will act as a DAMA server. + If unsure, say N. + +Amateur Radio NET/ROM +CONFIG_NETROM + NET/ROM is a network layer protocol on top of AX.25 useful for + routing. + + A comprehensive listing of all the software for Linux amateur radio + users as well as information about how to configure an AX.25 port is + contained in the AX25-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . You also might want to + check out the file Documentation/networking/ax25.txt. More + information about digital amateur radio in general is on the WWW at + http://www.tapr.org/tapr/html/pkthome.html . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called netrom.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Amateur Radio X.25 PLP (Rose) +CONFIG_ROSE + The Packet Layer Protocol (PLP) is a way to route packets over X.25 + connections in general and amateur radio AX.25 connections in + particular, essentially an alternative to NET/ROM. + + A comprehensive listing of all the software for Linux amateur radio + users as well as information about how to configure an AX.25 port is + contained in the AX25-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . You also might want to + check out the file Documentation/networking/ax25.txt. More + information about digital amateur radio in general is on the WWW at + http://www.tapr.org/tapr/html/pkthome.html . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called rose.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Serial port KISS driver for AX.25 +CONFIG_MKISS + KISS is a protocol used for the exchange of data between a computer + and a Terminal Node Controller (a small embedded system commonly + used for networking over AX.25 amateur radio connections; it + connects the computer's serial port with the radio's microphone + input and speaker output). + + Although KISS is less advanced than the 6pack protocol, it has + the advantage that it is already supported by most modern TNCs + without the need for a firmware upgrade. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called mkiss.o. + +Serial port 6PACK driver for AX.25 +CONFIG_6PACK + 6pack is a transmission protocol for the data exchange between your + PC and your TNC (the Terminal Node Controller acts as a kind of + modem connecting your computer's serial port to your radio's + microphone input and speaker output). This protocol can be used as + an alternative to KISS for networking over AX.25 amateur radio + connections, but it has some extended functionality. + + Note that this driver is still experimental and might cause + problems. For details about the features and the usage of the + driver, read Documentation/networking/6pack.txt. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called 6pack.o. + +BPQ Ethernet driver +CONFIG_BPQETHER + AX.25 is the protocol used for computer communication over amateur + radio. If you say Y here, you will be able to send and receive AX.25 + traffic over Ethernet (also called "BPQ AX.25"), which could be + useful if some other computer on your local network has a direct + amateur radio connection. + +High-speed (DMA) SCC driver for AX.25 +CONFIG_DMASCC + This is a driver for high-speed SCC boards, i.e. those supporting + DMA on one port. You usually use those boards to connect your + computer to an amateur radio modem (such as the WA4DSY 56kbps + modem), in order to send and receive AX.25 packet radio network + traffic. + + Currently, this driver supports Ottawa PI/PI2 + (http://hydra.carleton.ca/info/pi2.html ) and Gracilis PackeTwin + (http://www.paccomm.com/gracilis.html ) boards. They are detected + automatically. If you have one of these cards, say Y here and read + the AX25-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver can operate multiple boards simultaneously. If you + compile it as a module (by saying M instead of Y), it will be called + dmascc.o. If you don't pass any parameter to the driver, all + possible I/O addresses are probed. This could irritate other devices + that are currently not in use. You may specify the list of addresses + to be probed by "dmascc=addr1,addr2,..." (when compiled into the + kernel image) or "io=addr1,addr2,..." (when loaded as a module). The + network interfaces will be called dmascc0 and dmascc1 for the board + detected first, dmascc2 and dmascc3 for the second one, and so on. + + Before you configure each interface with ifconfig, you MUST set + certain parameters, such as channel access timing, clock mode, and + DMA channel. This is accomplished with a small utility program, + dmascc_cfg, available at + http://www.nt.tuwien.ac.at/~kkudielk/Linux/ . + +Z8530 SCC driver for AX.25 +CONFIG_SCC + These cards are used to connect your Linux box to an amateur radio + in order to communicate with other computers. If you want to use + this, read Documentation/networking/z8530drv.txt and the AX25-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . Also + make sure to say Y to "Amateur Radio AX.25 Level 2" support. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called scc.o. + +additional delay for PA0HZP OptoSCC compatible boards +CONFIG_SCC_DELAY + Say Y here if you experience problems with the SCC driver not + working properly; please read Documentation/networking/z8530drv.txt + for details. If unsure, say N. + +#support for TRX that feedback the tx signal to rx +#CONFIG_SCC_TRXECHO +### +### Don't know what's going on here. +### +# + +YAM driver for AX.25 +CONFIG_YAM + The YAM is a modem for packet radio which connects to the serial + port and includes some of the functions of a Terminal Node + Controller. If you have one of those, say Y here. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. + +BAYCOM picpar and par96 driver for AX.25 +CONFIG_BAYCOM_PAR + This is a driver for Baycom style simple amateur radio modems that + connect to a parallel interface. The driver supports the picpar and + par96 designs. To configure the driver, use the sethdlc utility + available in the standard ax25 utilities package. For information on + the modems, see http://www.baycom.de and the file + Documentation/networking/baycom.txt. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called baycom_par.o. + +BAYCOM EPP driver for AX.25 +CONFIG_BAYCOM_EPP + This is a driver for Baycom style simple amateur radio modems that + connect to a parallel interface. The driver supports the EPP + designs. To configure the driver, use the sethdlc utility available + in the standard ax25 utilities package. For information on the + modems, see http://www.baycom.de and the file + Documentation/networking/baycom.txt. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called baycom_par.o. + +BAYCOM ser12 full duplex driver for AX.25 +CONFIG_BAYCOM_SER_FDX + This is one of two drivers for Baycom style simple amateur radio + modems that connect to a serial interface. The driver supports the + ser12 design in full duplex mode. In addition, it allows the + baudrate to be set between 300 and 4800 baud (however not all modems + support all baudrates). This is the preferred driver. The next + driver, "BAYCOM ser12 half duplex driver for AX.25" is the old + driver and still provided in case this driver does not work with + your serial interface chip. To configure the driver, use the sethdlc + utility available in the standard ax25 utilities package. For + information on the modems, see http://www.baycom.de and + Documentation/networking/baycom.txt. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called baycom_ser_fdx.o. + +BAYCOM ser12 half duplex driver for AX.25 +CONFIG_BAYCOM_SER_HDX + This is one of two drivers for Baycom style simple amateur radio + modems that connect to a serial interface. The driver supports the + ser12 design in full duplex mode. This is the old driver. It is + still provided in case your serial interface chip does not work with + the full duplex driver. This driver is depreciated. To configure the + driver, use the sethdlc utility available in the standard ax25 + utilities package. For information on the modems, see + http://www.baycom.de and Documentation/networking/baycom.txt. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called baycom_ser_hdx.o. + +Sound card modem driver for AX.25 +CONFIG_SOUNDMODEM + This experimental driver allows a standard Sound Blaster or + WindowsSoundSystem compatible sound card to be used as a packet + radio modem (NOT as a telephone modem!), to send digital traffic + over amateur radio. + + To configure the driver, use the sethdlc, smdiag and smmixer + utilities available in the standard ax25 utilities package. For + information on how to key the transmitter, see + http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html and + Documentation/networking/soundmodem.txt. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called soundmodem.o. + +Sound card modem support for Sound Blaster and compatible cards +CONFIG_SOUNDMODEM_SBC + This option enables the soundmodem driver to use Sound Blaster and + compatible cards. If you have a dual mode card (i.e. a WSS cards + with a Sound Blaster emulation) you should say N here and Y to + "Sound card modem support for WSS and Crystal cards", below, because + this usually results in better performance. This option also + supports SB16/32/64 in full duplex mode. + +Sound card modem support for WSS and Crystal cards +CONFIG_SOUNDMODEM_WSS + This option enables the soundmodem driver to use WindowsSoundSystem + compatible cards. These cards feature a codec chip from either + Analog Devices (such as AD1848, AD1845, AD1812) or Crystal + Semiconductors (such as CS4248, CS423x). This option also supports + the WSS full duplex operation which currently works with Crystal + CS423x chips. If you don't need full duplex operation, do not enable + it to save performance. + +Sound card modem support for 1200 baud AFSK modulation +CONFIG_SOUNDMODEM_AFSK1200 + This option enables the soundmodem driver 1200 baud AFSK modem, + compatible to popular modems using TCM3105 or AM7911. The + demodulator requires about 12% of the CPU power of a Pentium 75 CPU + per channel. + +Sound card modem support for 2400 baud AFSK modulation (7.3728MHz crystal) +CONFIG_SOUNDMODEM_AFSK2400_7 + This option enables the soundmodem driver 2400 baud AFSK modem, + compatible to TCM3105 modems (over-)clocked with a 7.3728MHz + crystal. Note that the availability of this driver does _not_ imply + that I recommend building such links. It is only here since users + especially in eastern Europe have asked me to do so. In fact this + modulation scheme has many disadvantages, mainly its incompatibility + with many transceiver designs and the fact that the TCM3105 (if + used) is operated widely outside its specifications. + +Sound card modem support for 2400 baud AFSK modulation (8MHz crystal) +CONFIG_SOUNDMODEM_AFSK2400_8 + This option enables the soundmodem driver 2400 baud AFSK modem, + compatible to TCM3105 modems (over-)clocked with an 8MHz crystal. + Note that the availability of this driver does _not_ imply that I + recommend building such links. It is only here since users + especially in eastern Europe have asked me to do so. In fact this + modulation scheme has many disadvantages, mainly its incompatibility + with many transceiver designs and the fact that the TCM3105 (if + used) is operated widely outside its specifications. + +Sound card modem support for 2666 baud AFSK modulation +CONFIG_SOUNDMODEM_AFSK2666 + This option enables the soundmodem driver 2666 baud AFSK modem. + This modem is experimental, and not compatible to anything + else I know of. + +Sound card modem support for 4800 baud 8PSK modulation +CONFIG_SOUNDMODEM_PSK4800 + This option enables the soundmodem driver 4800 baud 8PSK modem. + This modem is experimental, and not compatible to anything + else I know of. + +Sound card modem support for 4800 baud HAPN-1 modulation +CONFIG_SOUNDMODEM_HAPN4800 + This option enables the soundmodem driver 4800 baud HAPN-1 + compatible modem. This modulation seems to be widely used 'down + under' and in the Netherlands. Here, nobody uses it, so I could not + test if it works. It is compatible to itself, however :-) + +Sound card modem support for 9600 baud FSK G3RUH modulation +CONFIG_SOUNDMODEM_FSK9600 + This option enables the soundmodem driver 9600 baud FSK modem, + compatible to the G3RUH standard. The demodulator requires about 4% + of the CPU power of a Pentium 75 CPU per channel. You can say Y to + both 1200 baud AFSK and 9600 baud FSK if you want (but obviously you + can only use one protocol at a time, depending on what the other end + can understand). + +CCITT X.25 Packet Layer (EXPERIMENTAL) +CONFIG_X25 + X.25 is a set of standardized network protocols, similar in scope to + frame relay; the one physical line from your box to the X.25 network + entry point can carry several logical point-to-point connections + (called "virtual circuits") to other computers connected to the X.25 + network. Governments, banks, and other organizations tend to use it + to connect to each other or to form Wide Area Networks (WANs). Many + countries have public X.25 networks. X.25 consists of two + protocols: the higher level Packet Layer Protocol (PLP) (say Y here + if you want that) and the lower level data link layer protocol LAPB + (say Y to "LAPB Data Link Driver" below if you want that). + + You can read more about X.25 at http://www.sangoma.com/x25.htm and + http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm . + Information about X.25 for Linux is contained in the files + Documentation/networking/x25.txt and + Documentation/networking/x25-iface.txt. + + One connects to an X.25 network either with a dedicated network card + using the X.21 protocol (not yet supported by Linux) or one can do + X.25 over a standard telephone line using an ordinary modem (say Y + to "X.25 async driver" below) or over Ethernet using an ordinary + Ethernet card and either the 802.2 LLC protocol (say Y to "802.2 + LLC" below) or LAPB over Ethernet (say Y to "LAPB Data Link Driver" + and "LAPB over Ethernet driver" below). + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called x25.o. If unsure, say N. + +LAPB Data Link Driver (EXPERIMENTAL) +CONFIG_LAPB + Link Access Procedure, Balanced (LAPB) is the data link layer (i.e. + the lower) part of the X.25 protocol. It offers a reliable + connection service to exchange data frames with one other host, and + it is used to transport higher level protocols (mostly X.25 Packet + Layer, the higher part of X.25, but others are possible as well). + Usually, LAPB is used with specialized X.21 network cards, but Linux + currently supports LAPB only over Ethernet connections. If you want + to use LAPB connections over Ethernet, say Y here and to "LAPB over + Ethernet driver" below. Read + Documentation/networking/lapb-module.txt for technical details. + + If you want to compile this driver as a module though ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read Documentation/modules.txt. The module + will be called lapb.o. If unsure, say N. + +802.2 LLC (EXPERIMENTAL) +CONFIG_LLC + This is a Logical Link Layer protocol used for X.25 connections over + Ethernet, using ordinary Ethernet cards. + +Bridging (EXPERIMENTAL) +CONFIG_BRIDGE + If you say Y here, then your Linux box will be able to act as an + Ethernet bridge, which means that the different Ethernet segments it + is connected to will appear as one Ethernet to the participants. + Several such bridges can work together to create even larger + networks of Ethernets using the IEEE802.1 spanning tree algorithm. + As this is a standard, Linux bridges will interwork properly with + other third party bridge products. + + In order to use this, you'll need the bridge configuration tools + available from ftp://shadow.cabi.net/pub/Linux . Please read the + Bridge mini-HOWTO for more information. Note that if your box acts + as a bridge, it probably contains several Ethernet devices, but the + kernel is not able to recognize more than one at boot time without + help; for details read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + The Bridging code is still in test. If unsure, say N. + +Packet socket +CONFIG_PACKET + The Packet protocol is used by applications which communicate + directly with network devices without an intermediate network + protocol implemented in the kernel, e.g. tcpdump. If you want them + to work, choose Y. + + This driver is also available as a module called af_packet.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt; if you use modprobe or + kmod, you may also want to add "alias net-pf-17 af_packet" to + /etc/modules.conf. + + If unsure, say Y. + +Packet socket: mmapped IO +CONFIG_PACKET_MMAP + If you say Y here, the Packet protocol driver will use an IO + mechanism that results in faster communication. + + If unsure, say N. + +Kernel/User network link driver +CONFIG_NETLINK + This driver allows for two-way communication between the kernel and + user processes; the user processes communicate with the kernel by + reading from and writing to character special files in the /dev + directory having major mode 36. + + So far, the kernel uses this feature to publish some network related + information if you say Y to "Routing messages", below. You also need + to say Y here if you want to use arpd, a daemon that helps keep the + internal ARP cache (a mapping between IP addresses and hardware + addresses on the local network) small. The ethertap device, which + lets user space programs read and write raw Ethernet frames, also + needs the network link driver. + + This driver is also available as a module called netlink_dev.o ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + + If unsure, say Y. + +Routing messages +CONFIG_RTNETLINK + If you say Y here and create a character special file /dev/route + with major number 36 and minor number 0 using mknod ("man mknod"), + you (or some user space utility) can read some network related + routing information from that file. Everything you write to that + file will be discarded. + +Netlink device emulation +CONFIG_NETLINK_DEV + This is a backward compatibility option, choose Y for now. + This option will be removed soon. + +Asynchronous Transfer Mode (ATM) +CONFIG_ATM + ATM is a high-speed networking technology for Local Area Networks + and Wide Area Networks. It uses a fixed packet size and is + connection oriented, allowing for the negotiation of minimum + bandwidth requirements. + + In order to participate in an ATM network, your Linux box needs an + ATM networking card. If you have that, say Y here and to the driver + of your ATM card below. + + Note that you need a set of user-space programs to actually make use + of ATM. See the file Documentation/atm.txt for further details. + +Classical IP over ATM +CONFIG_ATM_CLIP + Classical IP over ATM for PVCs and SVCs, supporting InARP and + ATMARP. Typically you will either use LAN Emulation (LANE) or + Classical IP to communicate with other IP hosts on your ATM network. + +Do NOT send ICMP if no neighbour +CONFIG_ATM_CLIP_NO_ICMP + Normally, an "ICMP host unreachable" message is sent if a neighbour + cannot be reached because there is no VC to it in the kernel's + ATMARP table. This may cause problems when ATMARP table entries are + briefly removed during revalidation. If you say Y here, packets to + such neighbours are silently discarded instead. + +LAN Emulation (LANE) support +CONFIG_ATM_LANE + LAN Emulation emulates services of existing LANs across an ATM + network. Besides operating as a normal ATM end station client, Linux + LANE client can also act as an proxy client bridging packets between + ELAN and Ethernet segments. You need LANE if you want to try MPOA. + +Multi-Protocol Over ATM (MPOA) support +CONFIG_ATM_MPOA + Multi-Protocol Over ATM allows ATM edge devices such as routers, + bridges and ATM attached hosts establish direct ATM VCs across + subnetwork boundaries. These shortcut connections bypass routers + enhancing overall network performance. + +ATM over TCP +CONFIG_ATM_TCP + ATM over TCP driver. Useful mainly for development and for + experiments. If unsure, say N. + +Efficient Networks ENI155P +CONFIG_ATM_ENI + Driver for the Efficient Networks ENI155p series and SMC ATM + Power155 155 Mbps ATM adapters. Both, the versions with 512kB and + 2MB on-board RAM (Efficient calls them "C" and "S", respectively), + and the FPGA and the ASIC Tonga versions of the board are supported. + The driver works with MMF (-MF or ...F) and UTP-5 (-U5 or ...D) + adapters. + +Enable extended debugging +CONFIG_ATM_ENI_DEBUG + Extended debugging records various events and displays that list + when an inconsistency is detected. This mechanism is faster than + generally using printks, but still has some impact on performance. + Note that extended debugging may create certain race conditions + itself. Enable this ONLY if you suspect problems with the driver. + +Fine-tune burst settings +CONFIG_ATM_ENI_TUNE_BURST + In order to obtain good throughput, the ENI NIC can transfer + multiple words of data per PCI bus access cycle. Such a multi-word + transfer is called a burst. + + The default settings for the burst sizes are suitable for most PCI + chipsets. However, in some cases, large bursts may overrun buffers + in the PCI chipset and cause data corruption. In such cases, large + bursts must be disabled and only (slower) small bursts can be used. + The burst sizes can be set independently in the send (TX) and + receive (RX) direction. + + Note that enabling many different burst sizes in the same direction + may increase the cost of setting up a transfer such that the + resulting throughput is lower than when using only the largest + available burst size. + + Also, sometimes larger bursts lead to lower throughput, e.g. on an + Intel 440FX board, a drop from 135 Mbps to 103 Mbps was observed + when going from 8W to 16W bursts. + +Enable 16W TX bursts (discouraged) +CONFIG_ATM_ENI_BURST_TX_16W + Burst sixteen words at once in the send direction. This may work + with recent PCI chipsets, but is known to fail with older chipsets. + +Enable 8W TX bursts (recommended) +CONFIG_ATM_ENI_BURST_TX_8W + Burst eight words at once in the send direction. This is the default + setting. + +Enable 4W TX bursts (optional) +CONFIG_ATM_ENI_BURST_TX_4W + Burst four words at once in the send direction. You may want to try + this if you have disabled 8W bursts. Enabling 4W if 8W is also set + may or may not improve throughput. + +Enable 2W TX bursts (optional) +CONFIG_ATM_ENI_BURST_TX_2W + Burst two words at once in the send direction. You may want to try + this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W + are also set may or may not improve throughput. + +Enable 16W RX bursts (discouraged) +CONFIG_ATM_ENI_BURST_RX_16W + Burst sixteen words at once in the receive direction. This may work + with recent PCI chipsets, but is known to fail with older chipsets. + +Enable 8W RX bursts (discouraged) +CONFIG_ATM_ENI_BURST_RX_8W + Burst eight words at once in the receive direction. This may work + with recent PCI chipsets, but is known to fail with older chipsets, + such as the Intel Neptune series. + +Enable 4W RX bursts (recommended) +CONFIG_ATM_ENI_BURST_RX_4W + Burst four words at once in the receive direction. This is the + default setting. Enabling 4W if 8W is also set may or may not + improve throughput. + +Enable 2W RX bursts (optional) +CONFIG_ATM_ENI_BURST_RX_2W + Burst two words at once in the receive direction. You may want to + try this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or + 8W are also set may or may not improve throughput. + +ZeitNet ZN1221/ZN1225 +CONFIG_ATM_ZATM + Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM + adapters. + +Enable extended debugging +CONFIG_ATM_ZATM_DEBUG + Extended debugging records various events and displays that list + when an inconsistency is detected. This mechanism is faster than + generally using printks, but still has some impact on performance. + Note that extended debugging may create certain race conditions + itself. Enable this ONLY if you suspect problems with the driver. + +Enable usec resolution timestamps +CONFIG_ATM_ZATM_EXACT_TS + The uPD98401 SAR chip supports a high-resolution timer (approx. 30 + MHz) that is used for very accurate reception timestamps. Because + that timer overflows after 140 seconds, and also to avoid timer + drift, time measurements need to be periodically synchronized with + the normal system time. Enabling this feature will add some general + overhead for timer synchronization and also per-packet overhead for + time conversion. + +IDT 77201 (NICStAR) +CONFIG_ATM_NICSTAR + The NICStAR chipset family is used in a large number of ATM NICs for + 25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE + series. + +Madge Ambassador (Collage PCI 155 Server) +CONFIG_ATM_AMBASSADOR + This is a driver for ATMizer based ATM card produced by Madge + Networks Ltd. Say Y (or M to compile as a module named ambassador.o) + here if you have one of these cards. + +Enable debugging messages +CONFIG_ATM_AMBASSADOR_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument (kernel command line argument as well?), changed + dynamically using an ioctl (not yet) or changed by sending the + string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file + drivers/atm/ambassador.h for the meanings of the bits in the mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + +Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client) +CONFIG_ATM_HORIZON + This is a driver for the Horizon chipset ATM adapter cards once + produced by Madge Networks Ltd. Say Y (or M to compile as a module + named horizon.o) here if you have one of these cards. + +Enable debugging messages +CONFIG_ATM_HORIZON_DEBUG + Somewhat useful debugging messages are available. The choice of + messages is controlled by a bitmap. This may be specified as a + module argument (kernel command line argument as well?), changed + dynamically using an ioctl (not yet) or changed by sending the + string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file + drivers/atm/horizon.h for the meanings of the bits in the mask. + + When active, these messages can have a significant impact on the + speed of the driver, and the size of your syslog files! When + inactive, they will have only a modest impact on performance. + +SCSI support? +CONFIG_SCSI + If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or + any other SCSI device under Linux, say Y and make sure that you know + the name of your SCSI host adapter (the card inside your computer + that "speaks" the SCSI protocol, also called SCSI controller), + because you will be asked for it. + + You also need to say Y here if you want support for the parallel + port version of the 100 MB IOMEGA ZIP drive. + + Please read the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . The + SCSI-Programming-HOWTO contains information about how to add or + remove an SCSI device from a running Linux machine without + rebooting. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called scsi_mod.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt and + Documentation/scsi.txt. However, do not compile this as a module if + your root filesystem (the one containing the directory /) is located + on a SCSI device. + +SCSI disk support +CONFIG_BLK_DEV_SD + If you want to use a SCSI hard disk or the SCSI or parallel port + version of the IOMEGA ZIP drive under Linux, say Y and read the + SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . This is NOT for SCSI + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sd_mod.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt and + Documentation/scsi.txt. Do not compile this driver as a module if + your root filesystem (the one containing the directory /) is located + on a SCSI disk. In this case, do not compile the driver for your + SCSI host adapter (below) as a module either. + +SCSI tape support +CONFIG_CHR_DEV_ST + If you want to use a SCSI tape drive under Linux, say Y and read the + SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , and + drivers/scsi/README.st in the kernel source. This is NOT for SCSI + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called st.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt and + Documentation/scsi.txt . + +SCSI CDROM support +CONFIG_BLK_DEV_SR + If you want to use a SCSI CDROM under Linux, say Y and read the + SCSI-HOWTO and the CDROM-HOWTO at + http://metalab.unc.edu/mdw/linux.html#howto . Also make sure to say Y + or M to "ISO 9660 CDROM filesystem support" later. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sr_mod.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt and + Documentation/scsi.txt . + +Enable vendor-specific extensions (for SCSI CDROM) +CONFIG_BLK_DEV_SR_VENDOR + This enables the usage of vendor specific SCSI commands. This is + required to support multisession CDs with old NEC/TOSHIBA cdrom + drives (and HP Writers). If you have such a drive and get the first + session only, try saying Y here; everybody else says N. + +SCSI generic support +CONFIG_CHR_DEV_SG + If you want to use SCSI scanners, synthesizers or CD-writers or just + about anything having "SCSI" in its name other than hard disks, + CDROMs or tapes, say Y here. These won't be supported by the kernel + directly, so you need some additional software which knows how to + talk to these devices using the SCSI protocol. For CD-writers, you + would need the program cdwrite, available from + ftp://metalab.unc.edu/pub/Linux/utils/disk-management ; for other + devices, it's possible that you'll have to write the driver software + yourself, so have a look at the SCSI-HOWTO and at the + SCSI-Programming-HOWTO, both available from + http://metalab.unc.edu/mdw/linux.html#howto . Please read the file + Documentation/scsi-generic.txt for more information. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt and + Documentation/scsi.txt. The module will be called sg.o. If unsure, + say N. + +Probe all LUNs on each SCSI device +CONFIG_SCSI_MULTI_LUN + If you have a SCSI device that supports more than one LUN (Logical + Unit Number), e.g. a CD jukebox, and only one LUN is detected, you + can say Y here to force the SCSI driver to probe for multiple LUNs. + A SCSI device with multiple LUNs acts logically like multiple SCSI + devices. The vast majority of SCSI devices have only one LUN, and + so most people can say N here and should in fact do so, because it + is safer. + +Verbose SCSI error reporting (kernel size +=12K) +CONFIG_SCSI_CONSTANTS + The error messages regarding your SCSI hardware will be easier to + understand if you say Y here; it will enlarge your kernel by about + 12 KB. If in doubt, say Y. + +SCSI logging facility +CONFIG_SCSI_LOGGING + This turns on a logging facility that can be used to debug a number + of SCSI related problems. + + If you say Y here, no logging output will appear by default, but you + can enable logging by saying Y to "/proc filesystem support" and + "Sysctl support" below and executing the command + + echo "scsi log token [level]" > /proc/scsi/scsi + + at boot time after the /proc filesystem has been mounted. + + There are a number of things that can be used for 'token' (you can + find them in the source: drivers/scsi/scsi.c), and this allows you + to select the types of information you want, and the level allows + you to select the level of verbosity. + + If you say N here, it may be harder to track down some types of SCSI + problems. If you say Y here your kernel will be somewhat larger, but + there should be no noticeable performance impact as long as you have + logging turned off. + +AdvanSys SCSI support +CONFIG_SCSI_ADVANSYS + This is a driver for all SCSI host adapters manufactured by + AdvanSys. It is documented in the kernel source in + drivers/scsi/advansys.c. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called advansys.o. + +Adaptec AHA152X/2825 support +CONFIG_SCSI_AHA152X + This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825 + SCSI host adapters. It also works for the AVA-1505, but the IRQ etc. + must be manually specified in this case. + + It is explained in section 3.3 of the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . You might also want to + read the comments at the top of drivers/scsi/aha152x.c. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aha152x.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Adaptec AHA1542 support +CONFIG_SCSI_AHA1542 + This is support for a SCSI host adapter. It is explained in section + 3.4 of the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Note that Trantor was + purchased by Adaptec, and some former Trantor products are being + sold under the Adaptec name. If it doesn't work out of the box, you + may have to change some settings in drivers/scsi/aha1542.h. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called aha1542.o. + +Adaptec AHA1740 support +CONFIG_SCSI_AHA1740 + This is support for a SCSI host adapter. It is explained in section + 3.5 of the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + of the box, you may have to change some settings in + drivers/scsi/aha1740.h. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aha1740.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Adaptec AIC7xxx chipset SCSI controller support +CONFIG_SCSI_AIC7XXX + This is support for the various aic7xxx based Adaptec SCSI + controllers. These include the 274x EISA cards; 284x VLB cards; + 2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and + motherboard based SCSI controllers from Adaptec. It does not support + the AAA-13x RAID controllers from Adaptec, nor will it likely ever + support them. It does not support the 2920 cards from Adaptec that + use the Future Domain SCSI controller chip. For those cards, you + need the "Future Domain 16xx SCSI support" driver. + + In general, if the controller is based on an Adaptec SCSI controller + chip from the aic777x series or the aic78xx series, this driver + should work. The only exception is the 7810 which is specifically + not supported (that's the RAID controller chip on the AAA-13x + cards). + + Note that the AHA2920 SCSI host adapter is *not* supported by this + driver; choose "Future Domain 16xx SCSI support" instead if you have + one of those. + + Information on the configuration options for this controller can be + found by checking the help file for each of the available + configuration options. You should read drivers/scsi/README.aic7xxx + at a minimum before contacting the maintainer with any questions. + The SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , can also be of great + help. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called aic7xxx.o. + +Enable or Disable Tagged Command Queueing by default +CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT + This option causes the aic7xxx driver to attempt to use Tagged + Command Queueing (TCQ) on all devices that claim to support it. + + TCQ is a feature of SCSI-2 which improves performance: the host + adapter can send several SCSI commands to a device's queue even if + previous commands haven't finished yet. Because the device is + intelligent, it can optimize its operations (like head positioning) + based on its own request queue. Not all devices implement this + correctly. + + If you say Y here, you can still turn off TCQ on troublesome devices + with the use of the tag_info boot parameter. See the file + drivers/scsi/README.aic7xxx for more information on that and other + aic7xxx setup commands. If this option is turned off, you may still + enable TCQ on known good devices by use of the tag_info boot + parameter. + + If you are unsure about your devices then it is safest to say N + here. + + However, TCQ can increase performance on some hard drives by as much + as 50% or more, so it is recommended that if you say N here, you + should at least read the README.aic7xxx file so you will know how to + enable this option manually should your drives prove to be safe in + regards to TCQ. + + Conversely, certain drives are known to lock up or cause bus resets + when TCQ is enabled on them. If you have a Western Digital + Enterprise SCSI drive for instance, then don't even bother to enable + TCQ on it as the drive will become unreliable, and it will actually + reduce performance. + +Default number of TCQ commands per device +CONFIG_AIC7XXX_CMDS_PER_DEVICE + Specify the number of commands you would like to allocate per SCSI + device when Tagged Command Queueing (TCQ) is enabled on that device. + + Reasonable figures are in the range of 8 to 24 commands per device, + but depending on hardware could be increased or decreased from that + figure. If the number is too high for any particular device, the + driver will automatically compensate usually after only 10 minutes + of uptime. It will not hinder performance if some of your devices + eventually have their command depth reduced, but is a waste of + memory if all of your devices end up reducing this number down to a + more reasonable figure. + + NOTE: Certain very broken drives are known to lock up when given + more commands than they like to deal with. Quantum Fireball drives + are the most common in this category. For the Quantum Fireball + drives it is suggested to use no more than 8 commands per device. + + Default: 8 + +Collect statistics to report in /proc +CONFIG_AIC7XXX_PROC_STATS + This option tells the driver to keep track of how many commands have + been sent to each particular device and report that information to + the user via the /proc/scsi/aic7xxx/n file, where n is the number of + the aic7xxx controller you want the information on. This adds a + small amount of overhead to each and every SCSI command the aic7xxx + driver handles, so if you aren't really interested in this + information, it is best to leave it disabled. This will only work if + you also say Y to "/proc filesystem support", below. + + If unsure, say N. + +Delay in seconds after SCSI bus reset +CONFIG_AIC7XXX_RESET_DELAY + This sets how long the driver will wait after resetting the SCSI bus + before attempting to communicate with the devices on the SCSI bus + again. This delay will be used during the reset phase at bootup time + as well as after any reset that might occur during normal operation. + Reasonable numbers range anywhere from 5 to 15 seconds depending on + your devices. DAT tape drives are notorious for needing more time + after a bus reset to be ready for the next command, but most hard + drives and CD-ROM devices are ready in only a few seconds. This + option has a maximum upper limit of 20 seconds to avoid bad + interactions between the aic7xxx driver and the rest of the linux + kernel. The default value has been reduced to 5 seconds. If this + doesn't work with your hardware, try increasing this value. + +IBM ServeRAID Support +CONFIG_SCSI_IPS + This is support for the IBM ServeRAID hardware RAID controllers. + Consult the SCSI-HOWTO, available via anonymous FTP from + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, and the file + README.ips in drivers/scsi for more information. If this driver + does not work correctly without modification please contact the + author by email at ipslinux@us.ibm.com. + +IBM ServeRAID Support +CONFIG_SCSI_IPS + This is support for the IBM ServeRAID hardware RAID controllers. + Consult the SCSI-HOWTO, available via anonymous FTP from + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, and the file + README.ips in drivers/scsi for more information. If this driver + does not work correctly without modification please contact the + author by email at ipslinux@us.ibm.com. + +BusLogic SCSI support +CONFIG_SCSI_BUSLOGIC + This is support for BusLogic MultiMaster and FlashPoint SCSI Host + Adapters. Consult the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , and the files + README.BusLogic and README.FlashPoint in drivers/scsi for more + information. If this driver does not work correctly without + modification, please contact the author, Leonard N. Zubkoff, by + email to lnz@dandelion.com. + + You can also build this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + but only a single instance may be loaded. If you want to compile it + as a module, say M here and read Documentation/modules.txt. The + module will be called BusLogic.o. + +Omit BusLogic SCSI FlashPoint support +CONFIG_SCSI_OMIT_FLASHPOINT + This option allows you to omit the FlashPoint support from the + BusLogic SCSI driver. The FlashPoint SCCB Manager code is + substantial, so users of MultiMaster Host Adapters may wish to omit + it. + +DTC3180/3280 SCSI support +CONFIG_SCSI_DTC3280 + This is support for DTC 3180/3280 SCSI Host Adapters. Please read + the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , and the file + drivers/scsi/README.dtc3x80. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dtc.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support +CONFIG_SCSI_EATA_DMA + This is support for the EATA-DMA protocol compliant SCSI Host + Adapters like the SmartCache III/IV, SmartRAID controller families + and the DPT PM2011B and PM2012B controllers. + + Note that this driver is obsolete; if you have one of the above SCSI + Host Adapters, you should normally say N here and Y to "EATA + ISA/EISA/PCI support", below. Please read the SCSI-HOWTO, available + from http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eata_dma.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +EATA-PIO (old DPT PM2001, PM2012A) support +CONFIG_SCSI_EATA_PIO + This driver supports all EATA-PIO protocol compliant SCSI Host + Adapters like the DPT PM2001 and the PM2012A. EATA-DMA compliant + host adapters could also use this driver but are discouraged from + doing so, since this driver only supports hard disks and lacks + numerous features. You might want to have a look at the SCSI-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called eata_pio.o. + +UltraStor 14F/34F support +CONFIG_SCSI_U14_34F + This is support for the UltraStor 14F and 34F SCSI-2 host adapters. + The source at drivers/scsi/u14-34f.c contains some information about + this hardware. If the driver doesn't work out of the box, you may + have to change some settings in drivers/scsi/u14-34f.c. Read the + SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Note that there is also + another driver for the same hardware: "UltraStor SCSI support", + below. You should say Y to both only if you want 24F support as + well. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called u14-34f.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +enable elevator sorting +CONFIG_SCSI_U14_34F_LINKED_COMMANDS + This option enables elevator sorting for all probed SCSI disks and + CDROMs. It definitely reduces the average seek distance when doing + random seeks, but this does not necessarily result in a noticeable + performance improvement: your mileage may vary... + + The safe answer is N. + +maximum number of queued commands +CONFIG_SCSI_U14_34F_MAX_TAGS + This specifies how many SCSI commands can be maximally queued for + each probed SCSI device. You should reduce the default value of 8 + only if you have disks with buggy or limited tagged command support. + Minimum is 2 and maximum is 14. This value is also the window size + used by the elevator sorting option above. The effective value used + by the driver for each probed SCSI device is reported at boot time. + +Future Domain 16xx SCSI/AHA-2920A support +CONFIG_SCSI_FUTURE_DOMAIN + This is support for Future Domain's 16-bit SCSI host adapters + (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and + other adapters based on the Future Domain chipsets (Quantum + ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board). + It is explained in section 3.7 of the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip + and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI + controller support"). This Future Domain driver works with the older + Adaptec AHA-2920A boards with a Future Domain chip on them. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fdomain.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Future Domain MCS-600/700 SCSI support +CONFIG_SCSI_FD_MCS + This is support for Future Domain MCS 600/700 MCA SCSI adapters. + Some PS/2 computers are equipped with IBM Fast SCSI Adapter/A which + is identical to the MCS 700 and hence also supported by this driver. + This driver also supports the Reply SB16/SCSI card (the SCSI part). + It supports multiple adapters in the same system. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fd_mcs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Generic NCR5380/53c400 SCSI support +CONFIG_SCSI_GENERIC_NCR5380 + This is the generic NCR family of SCSI controllers, not to be + confused with the NCR 53c7 or 8xx controllers. It is explained in + section 3.8 of the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + of the box, you may have to change some settings in + drivers/scsi/g_NCR5380.h. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called g_NCR5380.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +Enable NCR53c400 extensions +CONFIG_SCSI_GENERIC_NCR53C400 + This enables certain optimizations for the NCR53c400 SCSI cards. You + might as well try it out. Note that this driver will only probe for + the Trantor T130B in its default configuration; you might have to + pass a command line option to the kernel at boot time if it doesn't + detect your card. See the file drivers/scsi/README.g_NCR5380 for + details. + +NCR5380/53c400 mapping method (use Port for T130B) +CONFIG_SCSI_G_NCR5380_PORT + The NCR5380 and NCR53c400 SCSI controllers come in two varieties: + port or memory mapped. You should know what you have. The most + common card, Trantor T130B, uses port mapped mode. + +NCR53c7,8xx SCSI support +CONFIG_SCSI_NCR53C7xx + This is a driver for the 53c7 and 8xx NCR family of SCSI + controllers, not to be confused with the NCR 5380 controllers. It is + explained in section 3.8 of the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + of the box, you may have to change some settings in + drivers/scsi/53c7,8xx.h. Please read drivers/scsi/README.ncr53c7xx + for the available boot time command line options. + + Note: there is another driver for the 53c8xx family of controllers + ("NCR53C8XX SCSI support" below). If you want to use them both, you + need to say M to both and build them as modules, but only one may be + active at a time. If you have a 53c8xx board, it's better to use the + other driver. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 53c7,8xx.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +always negotiate synchronous transfers +CONFIG_SCSI_NCR53C7xx_sync + In general, this is good; however, it is a bit dangerous since there + are some broken SCSI devices out there. Take your chances. Safe bet + is N. + +allow FAST-SCSI [10MHz] +CONFIG_SCSI_NCR53C7xx_FAST + This will enable 10MHz FAST-SCSI transfers with your host + adapter. Some systems have problems with that speed, so it's safest + to say N here. + +allow DISCONNECT +CONFIG_SCSI_NCR53C7xx_DISCONNECT + This enables the disconnect/reconnect feature of the NCR SCSI + controller. When you say Y here, a slow SCSI device will not lock + the SCSI bus while processing a request, allowing simultaneous use + of e.g. a SCSI hard disk and SCSI tape or CD-ROM drive, and + providing much better performance when using slow and fast SCSI + devices at the same time. Some devices, however, do not operate + properly with this option enabled, and will cause your SCSI system + to hang, which might cause a system crash. The safe answer + therefore is to say N. + +NCR53C8XX SCSI support +CONFIG_SCSI_NCR53C8XX + This is the BSD ncr driver adapted to Linux for the NCR53C8XX family + of PCI-SCSI controllers. This driver supports parity checking, + tagged command queuing and fast synchronous data transfers up to 80 + MB/s with wide FAST-40 LVD devices and controllers. + + Recent versions of the 53C8XX chips are better supported by the + option "SYM53C8XX SCSI support", below. + + Note: there is yet another driver for the 53c8xx family of + controllers ("NCR53c7,8xx SCSI support" above). If you want to use + them both, you need to say M to both and build them as modules, but + only one may be active at a time. If you have a 53c8xx board, you + probably do not want to use the "NCR53c7,8xx SCSI support". + + Please read drivers/scsi/README.ncr53c8xx for more information. + +SYM53C8XX SCSI support +CONFIG_SCSI_SYM53C8XX + This driver supports all the features of recent 53C8XX chips (used + in PCI SCSI controllers), notably the hardware phase mismatch + feature of the SYM53C896. + + Older versions of the 53C8XX chips are not supported by this + driver. If your system uses either a 810 rev. < 16, a 815, or a 825 + rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX + driver ("NCR53C8XX SCSI support" above) or configure both the + NCR53C8XX and this SYM53C8XX drivers either as module or linked to + the kernel image. + + When both drivers are linked into the kernel, the SYM53C8XX driver + is called first at initialization and you can use the 'excl=ioaddr' + driver boot option to exclude attachment of adapters by the + SYM53C8XX driver. For example, entering + 'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents + adapters at io address 0xb400 and 0xc000 from being attached by the + SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them. + The 'excl' option is also supported by the NCR53C8XX driver. + + Please read drivers/scsi/README.ncr53c8xx for more information. + +synchronous data transfers frequency +CONFIG_SCSI_NCR53C8XX_SYNC + The SCSI Parallel Interface-2 Standard defines 4 classes of transfer + rates: FAST-5, FAST-10, FAST-20 and FAST-40. The numbers are + respectively the maximum data transfer rates in mega-transfers per + second for each class. For example, a FAST-20 Wide 16 device is able + to transfer data at 20 million 16 bit packets per second for a total + rate of 40 MB/s. + + You may specify 0 if you want to only use asynchronous data + transfers. This is the safest and slowest option. Otherwise, specify + a value between 5 and 40, depending on the capability of your SCSI + controller. The higher the number, the faster the data transfer. + Note that 40 should normally be ok since the driver decreases the + value automatically according to the controller's capabilities. + + Your answer to this question is ignored for controllers with NVRAM, + since the driver will get this information from the user set-up. It + also can be overridden using a boot setup option, as follows + (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate + for FAST-20 synchronous data transfer (20 mega-transfers per + second). + + The normal answer therefore is not to go with the default but to + select the maximum value 40 allowing the driver to use the maximum + value supported by each controller. If this causes problems with + your SCSI devices, you should come back and decrease the value. + + There is no safe option other than using good cabling, right + terminations and SCSI conformant devices. + +use normal IO +CONFIG_SCSI_NCR53C8XX_IOMAPPED + If you say Y here, the driver will use normal IO, as opposed to + memory mapped IO. Memory mapped IO has less latency than normal IO + and works for most Intel-based hardware. Under Linux/Alpha only + normal IO is currently supported by the driver and so, this option + has no effect on those systems. + + The normal answer therefore is N; try Y only if you encounter SCSI + related problems. + +not allow targets to disconnect +CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT + This option is only provided for safety if you suspect some SCSI + device of yours to not support properly the target-disconnect + feature. In that case, you would say Y here. In general however, to + not allow targets to disconnect is not reasonable if there is more + than 1 device on a SCSI bus. The normal answer therefore is N. + +default tagged command queue depth +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS + "Tagged command queuing" is a feature of SCSI-2 which improves + performance: the host adapter can send several SCSI commands to a + device's queue even if previous commands haven't finished yet. + Because the device is intelligent, it can optimize its operations + (like head positioning) based on its own request queue. Some SCSI + devices don't implement this properly; if you want to disable this + feature, enter 0 or 1 here (it doesn't matter which). + + The default value is 8 and should be supported by most hard disks. + This value can be overridden from the boot command line using the + 'tags' option as follows (example): + 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to + 4, set queue depth to 16 for target 2 and target 3 on controller 0 + and set queue depth to 10 for target 0 / lun 2 on controller 1. + + The normal answer therefore is to go with the default 8 and to use + a boot command line option for devices that need to use a different + command queue depth. + + There is no safe option other than using good SCSI devices. + +maximum number of queued commands +CONFIG_SCSI_NCR53C8XX_MAX_TAGS + This option allows you to specify the maximum number of commands + that can be queued to any device, when tagged command queuing is + possible. The default value is 32. Minimum is 2, maximum is 64. + Modern hard disks are able to support 64 tags and even more, but + do not seem to be faster when more than 32 tags are being used. + + So, the normal answer here is to go with the default value 32 unless + you are using very large hard disks with large cache (>= 1 MB) that + are able to take advantage of more than 32 tagged commands. + + There is no safe option and the default answer is recommended. + +assume boards are SYMBIOS compatible (EXPERIMENTAL) +CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT + This option allows you to enable some features depending on GPIO + wiring. These General Purpose Input/Output pins can be used for + vendor specific features or implementation of the standard SYMBIOS + features. Genuine SYMBIOS controllers use GPIO0 in output for + controller LED and GPIO3 bit as a flag indicating + singled-ended/differential interface. The Tekram DC-390U/F boards + uses a different GPIO wiring. + + Your answer to this question is ignored if all your controllers have + NVRAM, since the driver is able to detect the board type from the + NVRAM format. + + If all the controllers in your system are genuine SYMBIOS boards or + use BIOS and drivers from SYMBIOS, you would want to say Y here, + otherwise N. N is the safe answer. + +enable profiling statistics gathering +CONFIG_SCSI_NCR53C8XX_PROFILE + This option allows you to enable profiling information gathering. + These statistics are not very accurate due to the low frequency + of the kernel clock (100 Hz on i386) and have performance impact + on systems that use very fast devices. + + The normal answer therefore is N. + +include support for the NCR PQS/PDS SCSI card +CONFIG_SCSI_NCR53C8XX_PQS_PDS + Say Y here if you have a special SCSI adapter produced by NCR + corporation called a PCI Quad SCSI or PCI Dual SCSI. You do not need + this if you do not have one of these adapters. However, since this + device is detected as a specific PCI device, this option is quite + safe. + + The common answer here is N, but answering Y is safe. + +IBMMCA SCSI support +CONFIG_SCSI_IBMMCA + This is support for the IBM SCSI adapter found in many of the PS/2 + series computers. These machines have an MCA bus, so you need to + answer Y to "MCA support" as well and read Documentation/mca.txt. + + If the adapter isn't found during boot (a common problem for models + 56, 57, 76, and 77) you'll need to use the 'ibmmcascsi=' kernel + option, where is the id of the SCSI subsystem (usually 7, but + if that doesn't work check your reference diskette). Owners of model + 95 with a LED-matrix-display can in addition activate some activity + info like under OS/2, but more informative, by setting + 'ibmmcascsi=display' as an additional kernel parameter. Try "man + bootparam" or see the documentation of your boot loader about how to + pass options to the kernel. The lilo procedure is also explained in + the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ibmmca.o. + +Standard SCSI-order +CONFIG_IBMMCA_SCSI_ORDER_STANDARD + In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks + are assigned to the drive letters, starting with the lowest SCSI-id + (physical number -- pun) to be drive C:, as seen from DOS and + similar operating systems. When looking into papers describing the + ANSI-SCSI-standard, this assignment of drives appears to be wrong. + The SCSI-standard follows a hardware-hierarchy which says that id 7 + has the highest priority and id 0 the lowest. Therefore, the host + adapters are still today everywhere placed as SCSI-id 7 by default. + In the SCSI-standard, the drive letters express the priority of the + disk. C: should be the hard disk, or a partition on it, with the + highest priority. This must therefore be the disk with the highest + SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the + original definition of the SCSI-standard as also industrial- and + process-control-machines, like VME-CPUs running under realtime-OSs + (e.g. LynxOS, OS9) do. + + If you like to run Linux on your MCA-machine with the same + assignment of hard disks as seen from e.g. DOS or OS/2 on your + machine, which is in addition conformant to the SCSI-standard, you + must say Y here. This is also necessary for MCA-Linux users who want + to keep downward compatibility to older releases of the + IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than + June 1997). + + If you like to have the lowest SCSI-id assigned as drive C:, as + modern SCSI-BIOSes do, which does not conform to the standard, but + is widespread and common in the PC-world of today, you must say N + here. If unsure, say Y. + +Reset SCSI-devices at boot time +CONFIG_IBMMCA_SCSI_DEV_RESET + By default, SCSI-devices are reset when the machine is powered on. + However, some devices exist, like special-control-devices, + SCSI-CNC-machines, SCSI-printer or scanners of older type, that do + not reset when switched on. If you say Y here, each device connected + to your SCSI-bus will be issued a reset-command after it has been + probed, while the kernel is booting. This may cause problems with + more modern devices, like hard disks, which do not appreciate these + reset commands, and can cause your system to hang. So say Y only if + you know that one of your older devices needs it; N is the safe + answer. + +NCR 53C9x MCA support +CONFIG_SCSI_MCA_53C9X + Some Microchannel machines, notably the NCR 35xx line, use a SCSI + controller based on the NCR 53C94. This driver will allow use of + the controller on the 3550, and very possibly others. + + If you want to compile this as a module (= code which can be + inserted and removed from the running kernel whenever you want), say + M here and read Documentation/modules.txt. The module will be called + mca_53c9x.o. + +Always IN2000 SCSI support +CONFIG_SCSI_IN2000 + This is support for an ISA bus SCSI host adapter. You'll find more + information in drivers/scsi/in2000.readme. If it doesn't work out of + the box, you may have to change the jumpers for IRQ or address + selection. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called in2000.o. + +Initio 91XXU(W) SCSI support +CONFIG_SCSI_INITIO + This is support for the Initio 91XXU(W) SCSI host adapter. Please + read the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called initio.o + +PAS16 SCSI support +CONFIG_SCSI_PAS16 + This is support for a SCSI host adapter. It is explained in section + 3.10 of the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + of the box, you may have to change some settings in + drivers/scsi/pas16.h. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pas16.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Initio INI-A100U2W SCSI support +CONFIG_SCSI_INIA100 + This is support for the Initio INI-A100U2W SCSI host adapter. Please + read the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called a100u2w.o + +PCI2000 support +CONFIG_SCSI_PCI2000 + This is support for the PCI2000I EIDE interface card which acts as a + SCSI host adapter. Please read the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module called pci2000.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +PCI2220i support +CONFIG_SCSI_PCI2220I + This is support for the PCI2220i EIDE interface card which acts as a + SCSI host adapter. Please read the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module called pci2220i.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +PSI240i support +CONFIG_SCSI_PSI240I + This is support for the PSI240i EIDE interface card which acts as a + SCSI host adapter. Please read the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module called psi240i.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Qlogic FAS SCSI support +CONFIG_SCSI_QLOGIC_FAS + This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic + FastSCSI! cards as well as any other card based on the FASXX chip + (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards). + + This driver does NOT support the PCI versions of these cards. The + PCI versions are supported by the Qlogic ISP driver ("Qlogic ISP + SCSI support"), below. + + Information about this driver is contained in + drivers/scsi/README.qlogicfas. You should also read the SCSI-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called qlogicfas.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +Qlogic ISP SCSI support (EXPERIMENTAL) +CONFIG_SCSI_QLOGIC_ISP + This driver works for all QLogic PCI SCSI host adapters (IQ-PCI, + IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card. (This latter + card is supported by the "AM53/79C974 PCI SCSI" driver). + + If you say Y here, make sure to choose "BIOS" at the question "PCI + access mode". + + Please read the file drivers/scsi/README.qlogicisp. You should also + read the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called qlogicisp.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +Qlogic ISP FC SCSI support +CONFIG_SCSI_QLOGIC_FC + This is a driver for the QLogic ISP2100 SCSI-FCP host adapter. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called qlogicfc.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +Seagate ST-02 and Future Domain TMC-8xx SCSI support +CONFIG_SCSI_SEAGATE + These are 8-bit SCSI controllers; the ST-01 is also supported by + this driver. It is explained in section 3.9 of the SCSI-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . If it + doesn't work out of the box, you may have to change some settings in + drivers/scsi/seagate.h. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called seagate.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Trantor T128/T128F/T228 SCSI support +CONFIG_SCSI_T128 + This is support for a SCSI host adapter. It is explained in section + 3.11 of the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + of the box, you may have to change some settings in + drivers/scsi/t128.h. Note that Trantor was purchased by Adaptec, and + some former Trantor products are being sold under the Adaptec name. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called t128.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +UltraStor SCSI support +CONFIG_SCSI_ULTRASTOR + This is support for the UltraStor 14F, 24F and 34F SCSI-2 host + adapter family. This driver is explained in section 3.12 of the + SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . If it doesn't work out + of the box, you may have to change some settings in + drivers/scsi/ultrastor.h. + + Note that there is also another driver for the same hardware: + "UltraStor 14F/34F support", above. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ultrastor.o. + +7000FASST SCSI support +CONFIG_SCSI_7000FASST + This driver supports the Western Digital 7000 SCSI host adapter + family. Some information is in the source: drivers/scsi/wd7000.c. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module will be called wd7000.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + +ACARD SCSI support +CONFIG_SCSI_ACARD + This driver supports the ACARD 870U/W SCSI host adapter. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called atp870u.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support +CONFIG_SCSI_EATA + This driver supports all EATA/DMA-compliant SCSI host adapters. DPT + ISA and all EISA i/o addresses are probed looking for the "EATA" + signature. If you chose "BIOS" at the question "PCI access mode", + the addresses of all the PCI SCSI controllers reported by the PCI + subsystem are probed as well. + + You want to read the start of drivers/scsi/eata.c and the + SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + Note that there is also another driver for the same hardware + available: "EATA-DMA support". You should say Y to only one of them. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called eata.o. + +enable tagged command queuing +CONFIG_SCSI_EATA_TAGGED_QUEUE + This is a feature of SCSI-2 which improves performance: the host + adapter can send several SCSI commands to a device's queue even if + previous commands haven't finished yet. Most EATA adapters negotiate + this feature automatically with the device, even if your answer is + N. The safe answer is N. + +enable elevator sorting +CONFIG_SCSI_EATA_LINKED_COMMANDS + This option enables elevator sorting for all probed SCSI disks and + CDROMs. It definitely reduces the average seek distance when doing + random seeks, but this does not necessarily result in a noticeable + performance improvement: your mileage may vary... + The safe answer is N. + +maximum number of queued commands +CONFIG_SCSI_EATA_MAX_TAGS + This specifies how many SCSI commands can be maximally queued for + each probed SCSI device. You should reduce the default value of 16 + only if you have disks with buggy or limited tagged command support. + Minimum is 2 and maximum is 62. This value is also the window size + used by the elevator sorting option above. The effective value used + by the driver for each probed SCSI device is reported at boot time. + +NCR53c406a SCSI support +CONFIG_SCSI_NCR53C406A + This is support for the NCR53c406a SCSI host adapter. For user + configurable parameters, check out drivers/scsi/NCR53c406.c in the + kernel source. Also read the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called NCR53c406.o. + +Symbios Logic sym53c416 support +CONFIG_SCSI_SYM53C416 + This is support for the sym53c416 SCSI host adapter, the SCSI + adapter that comes with some HP scanners. This driver requires that + the sym53c416 is configured first using some sort of pnp + configuration program (e.g. isapnp) or by a PnP aware BIOS. If you + are using isapnp then you need to compile this driver as a module + and then load it using insmod after isapnp has run. The parameters + of the configured card(s) should be passed to the driver. The format + is: + + insmod sym53c416 sym53c416=, [sym53c416_1=,] + + There is support for up to four adapters. If you want to compile + this driver as a module ( = code which can be inserted in and + removed from the running kernel whenever you want), say M here and + read Documentation/modules.txt. The module will be called + sym53c416.o. + +Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support +CONFIG_SCSI_DC390T + This driver supports PCI SCSI host adapters based on the Am53C974A + chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard + PCscsi/PCnet (Am53/79C974) solutions. + + Documentation can be found in linux/drivers/scsi/README.tmscsim. + + Note that this driver does NOT support Tekram DC390W/U/F, which are + based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those. + Also note that there is another generic Am53C974 driver, + "AM53/79C974 PCI SCSI support" below. You can pick either one. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called tmscsim.o. + +Omit support for other Am53/79C974 based SCSI adapters +CONFIG_SCSI_DC390T_NOGENSUPP + If you say N here, the DC390(T) SCSI driver relies on the DC390 + EEPROM to get initial values for its settings, such as speed, + termination, etc. If it can't find this EEPROM, it will use defaults + or the user supplied boot/module parameters. For details on driver + configuration see linux/drivers/scsi/README.tmscsim. + + If you say Y here and if no EEPROM is found, the driver gives up and + thus only supports Tekram DC390(T) adapters. This can be useful if + you have a DC390(T) and another Am53C974 based adapter, which, for + some reason, you want to drive with the other AM53C974 driver. + + If unsure, say N. + +AM53/79C974 PCI SCSI support +CONFIG_SCSI_AM53C974 + This is support for the AM53/79C974 SCSI host adapters. Please read + drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto , is for + you. + + Note that there is another driver for AM53C974 based adapters: + "Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above. You + can pick either one. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called AM53C974.o. + +AMI MegaRAID support +CONFIG_SCSI_MEGARAID + This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490 + and 467 SCSI host adapters. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called megaraid.o. + +GDT SCSI Disk Array Controller support +CONFIG_SCSI_GDTH + This is a driver for all SCSI Disk Array Controllers (EISA/ISA/PCI) + manufactured by ICP vortex. It is documented in the kernel source in + drivers/scsi/gdth.c and drivers/scsi/gdth.h. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. + +IOMEGA parallel port (ppa - older drives) +CONFIG_SCSI_PPA + This driver supports older versions of IOMEGA's parallel port ZIP + drive (a 100 MB removable media device). + + Note that you can say N here if you have the SCSI version of the ZIP + drive: it will be supported automatically if you said Y to the + generic "SCSI disk support", above. + + If you have the ZIP Plus drive or a more recent parallel port ZIP + drive (if the supplied cable with the drive is labeled "AutoDetect") + then you should say N here and Y to "IOMEGA parallel port (imm - + newer drives)", below. + + For more information about this driver and how to use it you should + read the file drivers/scsi/README.ppa. You should also read the + SCSI-HOWTO, which is available from + http://metalab.unc.edu/mdw/linux.html#howto . If you use this driver, + you will still be able to use the parallel port for other tasks, + such as a printer; it is safe to compile both drivers into the + kernel. + + This driver is also available as a module which can be inserted in + and removed from the running kernel whenever you want. To compile + this driver as a module, say M here and read + Documentation/modules.txt. The module will be called ppa.o. + +IOMEGA parallel port (imm - newer drives) +CONFIG_SCSI_IMM + This driver supports newer versions of IOMEGA's parallel port ZIP + drive (a 100 MB removable media device). + + Note that you can say N here if you have the SCSI version of the ZIP + drive: it will be supported automatically if you said Y to the + generic "SCSI disk support", above. + + If you have the ZIP Plus drive or a more recent parallel port ZIP + drive (if the supplied cable with the drive is labeled "AutoDetect") + then you should say Y here; if you have an older ZIP drive, say N + here and Y to "IOMEGA Parallel Port (ppa - older drives)", above. + + For more information about this driver and how to use it you should + read the file drivers/scsi/README.ppa. You should also read the + SCSI-HOWTO, which is available from + http://metalab.unc.edu/mdw/linux.html#howto . If you use this driver, + you will still be able to use the parallel port for other tasks, + such as a printer; it is safe to compile both drivers into the + kernel. + + This driver is also available as a module which can be inserted in + and removed from the running kernel whenever you want. To compile + this driver as a module, say M here and read + Documentation/modules.txt. The module will be called imm.o. + +Force the Iomega ZIP drivers to use EPP-16 +CONFIG_SCSI_IZIP_EPP16 + EPP (Enhanced Parallel Port) is a standard for parallel ports which + allows them to act as expansion buses that can handle up to 64 + peripheral devices. + + Some parallel port chipsets are slower than their motherboard, and + so we have to control the state of the chipset's FIFO queue every + now and then to avoid data loss. This will be done if you say Y + here. + + Generally, saying Y is the safe option and slows things down a bit. + +Assume slow parallel port control register +CONFIG_SCSI_IZIP_SLOW_CTR + Some parallel ports are known to have excessive delays between + changing the parallel port control register and good data being + available on the parallel port data/status register. This option + forces a small delay (1.0 usec to be exact) after changing the + control register to let things settle out. Enabling this option may + result in a big drop in performance but some very old parallel ports + (found in 386 vintage machines) will not work properly. + + Generally, saying N is fine. + +SCSI Debug host simulator. (EXPERIMENTAL) +CONFIG_SCSI_DEBUG + This is a host adapter simulator that can be programmed to simulate + a large number of conditions that could occur on a real bus. The + advantage is that many hard to reproduce problems can be tested in a + controlled environment where there is reduced risk of losing + important data. This is primarily of use to people trying to debug + the middle and upper layers of the SCSI subsystem. If unsure, say N. + +Fibre Channel support +CONFIG_FC4 + This is an experimental support for storage arrays connected to + the system using Fibre Optic and the "X3.269-199X Fibre Channel + Protocol for SCSI" specification. You'll also need the generic SCSI + support, as well as the drivers for the storage array itself and + for the interface adapter such as SOC. This subsystem could even + serve for IP networking, with some code extensions. + + If unsure, say N. + +Sun SOC +CONFIG_FC4_SOC + Serial Optical Channel is an interface card with one or two Fibre + Optic ports, each of which can be connected to a disk array. Only + the SBus incarnation of the adapter is supported at the moment. + +SparcSTORAGE Array 100 and 200 series +CONFIG_SCSI_PLUTO + If you never bought a disk array made by Sun, go with N. + +AcornSCSI support +CONFIG_SCSI_ACORNSCSI_3 + This enables support for the Acorn SCSI card (aka30). If you have an + Acorn system with one of these, say Y. If unsure, say N. + +Acorn SCSI tagged queue support +CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + Say Y here to enable tagged queuing support on the Acorn SCSI card. + + This is a feature of SCSI-2 which improves performance: the host + adapter can send several SCSI commands to a device's queue even if + previous commands haven't finished yet. Some SCSI devices don't + implement this properly, so the safe answer is N. + +Acorn SCSI Synchronous transfers support +CONFIG_SCSI_ACORNSCSI_SYNC + Say Y here to enable synchronous transfer negotiation with all + targets on the Acorn SCSI card. + + In general, this improves performance; however some SCSI devices + don't implement it properly, so the safe answer is N. + +Oak SCSI support +CONFIG_SCSI_OAK1 + This enables support for the Oak SCSI card. If you have an Acorn + system with one of these, say Y. If unsure, say N. + +Cumana SCSI I support +CONFIG_SCSI_CUMANA_1 + This enables support for the Cumana SCSI I card. If you have an + Acorn system with one of these, say Y. If unsure, say N. + +Cumana SCSI II support (EXPERIMENTAL) +CONFIG_SCSI_CUMANA_2 + This enables support for the Cumana SCSI II card. If you have an + Acorn system with one of these, say Y. If unsure, say N. + +EcoSCSI support +CONFIG_SCSI_ECOSCSI + This enables support for the EcoSCSI card -- a small card that sits + in the Econet socket. If you have an Acorn system with one of these, + say Y. If unsure, say N. + +EESOX SCSI support (EXPERIMENTAL) +CONFIG_SCSI_EESOXSCSI + This enables support for the EESOX SCSI card. If you have an Acorn + system with one of these, say Y, otherwise say N. + +Powertec SCSI support (EXPERIMENTAL) +CONFIG_SCSI_POWERTECSCSI + This enables support for the Powertec SCSI card on Acorn systems. If + you have one of these, say Y. If unsure, say N. + +Network device support? +CONFIG_NETDEVICES + You can say N here if you don't intend to connect your Linux box to + any other computer at all or if all your connections will be over a + telephone line with a modem either via UUCP (UUCP is a protocol to + forward mail and news between unix hosts over telephone lines; read + the UUCP-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto ) or dialing up a shell + account or a BBS, even using term (term is a program which gives you + almost full Internet connectivity if you have a regular dial up + shell account on some Internet connected Unix computer. Read + http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ). + + You'll have to say Y if your computer contains a network card that + you want to use under Linux (make sure you know its name because you + will be asked for it and read the Ethernet-HOWTO (especially if you + plan to use more than one network card under Linux)) or if you want + to use SLIP (Serial Line Internet Protocol is the protocol used to + send Internet traffic over telephone lines or null modem cables) or + CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better + and newer replacement for SLIP) or PLIP (Parallel Line Internet + Protocol is mainly used to create a mini network by connecting the + parallel ports of two local machines) or AX.25/KISS (protocol for + sending Internet traffic over amateur radio links). + + Make sure to read the NET-3-HOWTO. Eventually, you will have to read + Olaf Kirch's excellent and free book "Network Administrator's + Guide", to be found in ftp://metalab.unc.edu/pub/Linux/docs/LDP . If + unsure, say Y. + +Dummy net driver support +CONFIG_DUMMY + This is essentially a bit-bucket device (i.e. traffic you send to + this device is consigned into oblivion) with a configurable IP + address. It is most commonly used in order to make your currently + inactive SLIP address seem like a real address for local programs. + If you use SLIP or PPP, you might want to say Y here. Since this + thing often comes in handy, the default is Y. It won't enlarge your + kernel either. What a deal. Read about it in the Network + Administrator's Guide, available from + http://metalab.unc.edu/mdw/linux.html#guide . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called dummy.o. If you want to use more than one dummy device at a + time, you need to compile this driver as a module. Instead of + 'dummy', the devices will then be called 'dummy0', 'dummy1' etc. + +SLIP (serial line) support +CONFIG_SLIP + Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to + connect to your Internet service provider or to connect to some + other local Unix box or if you want to configure your Linux box as a + Slip/CSlip server for other people to dial in. SLIP (Serial Line + Internet Protocol) is a protocol used to send Internet traffic over + serial connections such as telephone lines or null modem cables; + nowadays, the protocol PPP is more commonly used for this same + purpose. + + Normally, your access provider has to support SLIP in order for you + to be able to use it, but there is now a SLIP emulator called SLiRP + around (available via FTP (user: anonymous) from + ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which + allows you to use SLIP over a regular dial up shell connection. If + you plan to use SLiRP, make sure to say Y to CSLIP, below. The + NET-3-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , explains how to + configure SLIP. Note that you don't need this option if you just + want to run term (term is a program which gives you almost full + Internet connectivity if you have a regular dial up shell account on + some Internet connected Unix computer. Read + http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ). SLIP + support will enlarge your kernel by about 4 KB. If unsure, say N. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + slip.o. + +CSLIP compressed headers +CONFIG_SLIP_COMPRESSED + This protocol is faster than SLIP because it uses compression on the + TCP/IP headers (not on the data itself), but it has to be supported + on both ends. Ask your access provider if you are not sure and + answer Y, just in case. You will still be able to use plain SLIP. If + you plan to use SLiRP, the SLIP emulator (available from + ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which allows + you to use SLIP over a regular dial up shell connection, you + definitely want to say Y here. The NET-3-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , explains how to + configure CSLIP. This won't enlarge your kernel. + +Keepalive and linefill +CONFIG_SLIP_SMART + Adds additional capabilities to the SLIP driver to support the + RELCOM line fill and keepalive monitoring. Ideal on poor quality + analogue lines. + +Six bit SLIP encapsulation +CONFIG_SLIP_MODE_SLIP6 + Just occasionally you may need to run IP over hostile serial + networks that don't pass all control characters or are only seven + bit. Saying Y here adds an extra mode you can use with SLIP: + "slip6". In this mode, SLIP will only send normal ASCII symbols over + the serial device. Naturally, this has to be supported at the other + end of the link as well. It's good enough, for example, to run IP + over the async ports of a Camtec JNT Pad. If unsure, say N. + +PPP (point-to-point protocol) support +CONFIG_PPP + PPP (Point to Point Protocol) is a newer and better SLIP. It serves + the same purpose: sending Internet traffic over telephone (and other + serial) lines. Ask your access provider if they support it, because + otherwise you can't use it; most internet access providers these + days support PPP rather than SLIP. + + To use PPP, you need an additional program called pppd as described + in Documentation/networking/ppp.txt and in the PPP-HOWTO, available + at http://metalab.unc.edu/mdw/linux.html#howto . If you upgrade + from an older kernel, you might need to upgrade pppd as well. The + PPP option enlarges your kernel by about 16 KB. + + There are actually two versions of PPP: the traditional PPP for + asynchronous lines, such as regular analog phone lines, and + synchronous PPP which can be used over digital ISDN lines for + example. If you want to use PPP over phone lines or other + asynchronous serial lines, you need to say Y (or M) here and also to + the next option, "PPP support for async serial ports". For PPP over + synchronous lines, you should say Y (or M) here and to "Support + synchronous PPP", below. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you said Y to "Version information on all symbols" above, then + you cannot compile the PPP driver into the kernel; you can then only + compile it as a module. The module will be called ppp_generic.o. If + you want to compile it as a module, say M here and read + Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +PPP support for async serial ports +CONFIG_PPP_ASYNC + Say Y (or M) here if you want to be able to use PPP over standard + asynchronous serial ports, such as COM1 or COM2 on a PC. If you use + a modem (not a synchronous or ISDN modem) to contact your ISP, you + need this option. + + This code is also available as a module (code which can be inserted + into and removed from the running kernel). If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +CONFIG_PPP_SYNC_TTY + Say Y (or M) here if you want to be able to use PPP over synchronous + (HDLC) tty devices, such as the SyncLink adapter. These devices + are often used for high-speed leased lines like T1/E1. + + This code is also available as a module (code which can be inserted + into and removed from the running kernel). If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +PPP Deflate compression +CONFIG_PPP_DEFLATE + Support for the Deflate compression method for PPP, which uses the + Deflate algorithm (the same algorithm that gzip uses) to compress + each PPP packet before it is sent over the wire. The machine at the + other end of the PPP link (usually your ISP) has to support the + Deflate compression method as well for this to be useful. Even if + they don't support it, it is safe to say Y here. + + This code is also available as a module (code which can be inserted + into and removed from the running kernel). If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +PPP BSD-Compress compression +CONFIG_PPP_BSDCOMP + Support for the BSD-Compress compression method for PPP, which uses + the LZW compression method to compress each PPP packet before it is + sent over the wire. The machine at the other end of the PPP link + (usually your ISP) has to support the BSD-Compress compression + method as well for this to be useful. Even if they don't support it, + it is safe to say Y here. + + The PPP Deflate compression method ("PPP Deflate compression", + above) is preferable to BSD-Compress, because it compresses better + and is patent-free. + + Note that the BSD compression code will always be compiled as a + module; it is called bsd_comp.o and will show up in the directory + modules once you have said "make modules". If unsure, say N. + +Wireless LAN (non-hamradio) +CONFIG_NET_RADIO + Support for wireless LANs and everything having to do with radio, + but not with amateur radio. Note that the answer to this question + won't directly affect the kernel: saying N will just cause this + configure script to skip all the questions about radio + interfaces. + + Some user-level drivers for scarab devices which don't require + special kernel support are available from + ftp://shadow.cabi.net/pub/Linux . + +STRIP (Metricom Starmode radio IP) +CONFIG_STRIP + Say Y if you have a Metricom radio and intend to use Starmode Radio + IP. STRIP is a radio protocol developed for the MosquitoNet project + (on the WWW at http://mosquitonet.stanford.edu/ ) to send Internet + traffic using Metricom radios. Metricom radios are small, battery + powered, 100kbit/sec packet radio transceivers, about the size and + weight of a cellular telephone. (You may also have heard them called + "Metricom modems" but we avoid the term "modem" because it misleads + many people into thinking that you can plug a Metricom modem into a + phone line and use it as a modem.) + + You can use STRIP on any Linux machine with a serial port, although + it is obviously most useful for people with laptop computers. If you + think you might get a Metricom radio in the future, there is no harm + in saying Y to STRIP now, except that it makes the kernel a bit + bigger. + + You can also compile this as a module ( = code which can be inserted + in and removed from the running kernel whenever you want), say M + here and read Documentation/modules.txt. The module will be called + strip.o. + +AT&T WaveLAN & DEC RoamAbout DS support +CONFIG_WAVELAN + The Lucent WaveLAN (formerly NCR and AT&T; or DEC RoamAbout DS) is + a Radio LAN (wireless Ethernet-like Local Area Network) using the + radio frequencies 900 MHz and 2.4 GHz. + + This driver support the ISA version of the WaveLAN card. A separate + driver for the PCMCIA (PC-card) hardware is available in David + Hinds' pcmcia-cs package (see the file Documentation/Changes for + location). + + If you want to use an ISA WaveLAN card under Linux, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Some more specific + information is contained in Documentation/networking/wavelan.txt and + in the source code drivers/net/wavelan.p.h. + + You will also need the wireless tools package available from + ftp://hyper.stanford.edu/pub/pcmcia/contrib/ . Please read the man + pages contained therein. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wavelan.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Aironet Arlan 655 & IC2200 DS support +CONFIG_ARLAN + Aironet makes Arlan, a class of wireless LAN adapters. These use the + www.Telxon.com chip, which is also used on several similar cards. + This driver is tested on the 655 and IC2200 series cards. Look at + http://www.ylenurme.ee/~elmer/655/ for latest information. + + The driver is built as two modules, arlan and arlan-proc. The latter + is the /proc interface and is not needed most of time. + + On some computers the card ends up in non-valid state after some time. + Use a ping-reset script to clear it. + +LAPB over Ethernet driver +CONFIG_LAPBETHER + This is a driver for a pseudo device (typically called /dev/lapb0) + which allows you to open an LAPB point-to-point connection to some + other computer on your Ethernet network. In order to do this, you + need to say Y or M to the driver for your Ethernet card as well as + to "LAPB Data Link Driver". + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called lapbether.o. If unsure, say N. + +X.25 async driver +CONFIG_X25_ASY + This is a driver for sending and receiving X.25 frames over regular + asynchronous serial lines such as telephone lines equipped with + ordinary modems. Experts should note that this driver doesn't + currently comply with the asynchronous HDLS framing protocols in + CCITT recommendation X.25. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called x25_asy.o. If unsure, say N. + +PCMCIA network device support +CONFIG_NET_PCMCIA + Say Y if you would like to include support for any PCMCIA network + adapters. If unsure, say N. + +3Com 3c589 PCMCIA support +CONFIG_PCMCIA_3C589 + Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA + (PC-card) Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c589_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +3Com 3c574 PCMCIA support +CONFIG_PCMCIA_3C574 + Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA + (PC-card) Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c574_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +Fujitsu FMV-J18x PCMCIA support +CONFIG_PCMCIA_FMVJ18X + Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible + PCMCIA (PC-card) Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fmvj18x_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +NE2000 compatible PCMCIA support +CONFIG_PCMCIA_PCNET + Say Y here if you intend to attach an NE2000 compatible PCMCIA + (PC-card) Ethernet or Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pcnet_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +New Media PCMCIA support +CONFIG_PCMCIA_NMCLAN + Say Y here if you intend to attach a New Media Ethernet or LiveWire + PCMCIA (PC-card) Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called nmclan_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +SMC 91Cxx PCMCIA support +CONFIG_PCMCIA_SMC91C92 + Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA + (PC-card) Ethernet or Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc91c92_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +Xircom 16-bit PCMCIA support +CONFIG_PCMCIA_XIRC2PS + Say Y here if you intend to attach a Xircom 16-bit PCMCIA + (PC-card) Ethernet or Fast Ethernet card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called xirc2ps_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +3Com 3c575 CardBus support +CONFIG_PCMCIA_3C575 + This driver supports the 3Com 3c575 series of CardBus Fast Ethernet + adapters. + + This driver can only be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c575_cb.o. If you want to do that, say M + here and read Documentation/modules.txt. If unsure, say N. + +DEC Tulip CardBus support +CONFIG_PCMCIA_TULIP + This driver supports CardBus Fast Ethernet adapters based on DEC + Tulip and compatible chipsets. + + This driver can only be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tulip_cb.o. If you want to do that, say M + here and read Documentation/modules.txt. If unsure, say N. + +SMC EPIC CardBus support +CONFIG_PCMCIA_EPIC100 + This driver supports CardBus Fast Ethernet adapters based on the SMC + EPIC chipset. + + This driver can only be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called epic100_cb.o. If you want to do that, say + M here and read Documentation/modules.txt. If unsure, say N. + +Aviator/Raytheon 2.4MHz wireless support +CONFIG_PCMCIA_RAYCS + Say Y here if you intend to attach an Aviator/Raytheon PCMCIA + (PC-card) wireless Ethernet networking card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ray_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +Xircom Netwave AirSurfer wireless support +CONFIG_PCMCIA_NETWAVE + Say Y here if you intend to attach a Xircom Netwave AirSurfer PCMCIA + (PC-card) wireless Ethernet networking card to your computer. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called netwave_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +AT&T/Lucent Wavelan wireless support +CONFIG_PCMCIA_WAVELAN + Say Y here if you intend to attach an AT&T/Lucent Wavelan PCMCIA + (PC-card) wireless Ethernet networking card to your computer. This + driver is for the non-IEEE-802.11 Wavelan cards. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wavelan_cs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +PLIP (parallel port) support +CONFIG_PLIP + PLIP (Parallel Line Internet Protocol) is used to create a + reasonably fast mini network consisting of two (or, rarely, more) + local machines. A PLIP link from a Linux box is a popular means to + install a Linux distribution on a machine which doesn't have a CDROM + drive (a minimal system has to be transferred with floppies first). + The kernels on both machines need to have this PLIP option enabled + for this to work. + + The PLIP driver has two modes, mode 0 and mode 1. The parallel ports + (the connectors at the computers with 25 holes) are connected with + "null printer" or "Turbo Laplink" cables which can transmit 4 bits + at a time (mode 0) or with special PLIP cables, to be used on + bidirectional parallel ports only, which can transmit 8 bits at a + time (mode 1); you can find the wiring of these cables in + Documentation/networking/PLIP.txt. The cables can be up to 15m long. + Mode 0 works also if one of the machines runs DOS/Windows and has + some PLIP software installed, e.g. the Crynwr PLIP packet driver + (http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html ) and + winsock or NCSA's telnet. + + If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well + as the NET-3-HOWTO, both available from + http://metalab.unc.edu/mdw/linux.html#howto . Note that the PLIP + protocol has been changed and this PLIP driver won't work together + with the PLIP support in Linux versions 1.0.x. This option enlarges + your kernel by about 8 KB. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + plip.o. If unsure, say Y or M, in case you buy a laptop later. + +EQL (serial line load balancing) support +CONFIG_EQUALIZER + If you have two serial connections to some other computer (this + usually requires two modems and two telephone lines) and you use + SLIP (the protocol for sending Internet traffic over telephone + lines) or PPP (a better SLIP) on them, you can make them behave like + one double speed connection using this driver. Naturally, this has + to be supported at the other end as well, either with a similar EQL + Linux driver or with a Livingston Portmaster 2e. + + Say Y if you want this and read Documentation/networking/eql.txt. + You may also want to read section 6.2 of the NET-3-HOWTO, available + from http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eql.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +Ethertap network tap (EXPERIMENTAL) +CONFIG_ETHERTAP + If you say Y here (and have said Y to "Kernel/User network link + driver", above) and create a character special file /dev/tap0 with + major number 36 and minor number 16 using mknod ("man mknod"), you + will be able to have a user space program read and write raw + Ethernet frames from/to that special file. tap0 can be configured + with ifconfig and route like any other Ethernet device but it is not + connected to any physical LAN; everything written by the user to + /dev/tap0 is treated by the kernel as if it had come in from a LAN + to the device tap0; everything the kernel wants to send out over the + device tap0 can instead be read by the user from /dev/tap0: the user + mode program replaces the LAN that would be attached to an ordinary + Ethernet device. Please read the file + Documentation/networking/ethertap.txt for more information. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ethertap.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If you don't know what to use this for, you don't need it. + +Sealevel Systems 4021 support +CONFIG_SEALEVEL_4021 + This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. + + This driver can only be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to do that, say M here. The module will be called + sealevel.o. + +Frame Relay (DLCI) support +CONFIG_DLCI + This is support for the frame relay protocol; frame relay is a fast + low-cost way to connect to a remote Internet access provider or to + form a private wide area network. The one physical line from your + box to the local "switch" (i.e. the entry point to the frame relay + network, usually at the phone company) can carry several logical + point-to-point connections to other computers connected to the frame + relay network. For a general explanation of the protocol, check out + http://www.frforum.com/ on the WWW. To use frame relay, you need + supporting hardware (called FRAD) and certain programs from the + net-tools package as explained in + Documentation/networking/framerelay.txt. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dlci.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Max open DLCI +CONFIG_DLCI_COUNT + This is the maximal number of logical point-to-point frame relay + connections (the identifiers of which are called DCLIs) that + the driver can handle. The default is probably fine. + +Max DLCI per device +CONFIG_DLCI_MAX + You can specify here how many logical point-to-point frame relay + connections (the identifiers of which are called DCLIs) should be + handled by each of your hardware frame relay access devices. Go with + the default. + +Sangoma S502A FRAD support +CONFIG_SDLA + Say Y here if you need a driver for the Sangoma S502A, S502E, and + S508 Frame Relay Access Devices. These are multi-protocol cards, but + only frame relay is supported by the driver at this time. Please + read Documentation/framerelay.txt. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sdla.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Acorn Econet/AUN protocols (EXPERIMENTAL) +CONFIG_ECONET + Econet is a fairly old and slow networking protocol mainly used by + Acorn computers to access file and print servers. It uses native + Econet network cards. AUN is an implementation of the higher level + parts of Econet that runs over ordinary Ethernet connections, on + top of the UDP packet protocol, which in turn runs on top of the + Internet protocol IP. + + If you say Y here, you can choose with the next two options whether + to send Econet/AUN traffic over a UDP Ethernet connection or over + a native Econet network card. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called econet.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +AUN over UDP +CONFIG_ECONET_AUNUDP + Say Y here if you want to send Econet/AUN traffic over a UDP + connection (UDP is a packet based protocol that runs on top of the + Internet protocol IP) using an ordinary Ethernet network card. + +Native Econet +CONFIG_ECONET_NATIVE + Say Y here if you have a native Econet network card installed in + your computer. + +WAN Router +CONFIG_WAN_ROUTER + Wide Area Networks (WANs), such as X.25, frame relay and leased + lines, are used to interconnect Local Area Networks (LANs) over vast + distances with data transfer rates significantly higher than those + achievable with commonly used asynchronous modem connections. + Usually, a quite expensive external device called a `WAN router' is + needed to connect to a WAN. + + As an alternative, WAN routing can be built into the Linux kernel. + With relatively inexpensive WAN interface cards available on the + market, a perfectly usable router can be built for less than half + the price of an external router. If you have one of those cards and + wish to use your Linux box as a WAN router, say Y here and also to + the WAN driver for your card, below. You will then need the + wan-tools package which is available from ftp://ftp.sangoma.com . + Read Documentation/networking/wan-router.txt for more information. + + The WAN routing support is also available as a module called + wanrouter.o ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If unsure, say N. + +Fast switching (read help!) +CONFIG_NET_FASTROUTE + Saying Y here enables direct NIC-to-NIC (NIC = Network Interface + Card) data transfers on the local network, which is fast. + + IMPORTANT NOTE: This option is NOT COMPATIBLE with "Network packet + filtering" (CONFIG_NETFILTER). Say N here if you say Y there. + + However, it will work with all options in the "IP: advanced router" + section (except for "IP: use TOS value as routing key" and + "IP: use FWMARK value as routing key"). + + At the moment, few devices support fast switching (tulip is one of + them, a modified 8390 driver can be found at + ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz ). + + If unsure, say N. + +Forwarding between high speed interfaces +CONFIG_NET_HW_FLOWCONTROL + This option enables NIC (Network Interface Card) hardware throttling + during periods of extremal congestion. At the moment only a couple + of device drivers support it (really only one -- tulip, a modified + 8390 driver can be found at + ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz ). + + Really, this option is applicable to any machine attached to a fast + enough network, and even a 10 Mb NIC is able to kill a not very slow + box, such as a 120MHz Pentium. + + However, do not say Y here if you did not experience any serious + problems. + +QoS and/or fair queueing +CONFIG_NET_SCHED + When the kernel has several packets to send out over a network + device, it has to decide which ones to send first, which ones to + delay, and which ones to drop. This is the job of the packet + scheduler, and several different algorithms for how to do this + "fairly" have been proposed. + + If you say N here, you will get the standard packet scheduler, which + is a FIFO (first come, first served). If you say Y here, you will be + able to choose from among several alternative algorithms which can + then be attached to different network devices. This is useful for + example if some of your network devices are real time devices that + need a certain minimum data flow rate, or if you need to limit the + maximum data flow rate for traffic which matches specified criteria. + This code is considered to be experimental. + + To administer these schedulers, you'll need the user-level utilities + from the package iproute2+tc at ftp://ftp.inr.ac.ru/ip-routing/ . + That package also contains some documentation; for more, check out + http://snafu.freedom.org/linux2.2/iproute-notes.html . + + If you say Y here and to "/proc filesystem" below, you will be able + to read status information about packet schedulers from the file + /proc/net/psched. + + The available schedulers are listed in the following questions; you + can say Y to as many as you like. If unsure, say N now. + +CBQ packet scheduler +CONFIG_NET_SCH_CBQ + Say Y here if you want to use the Class-Based Queueing (CBQ) packet + scheduling algorithm for some of your network devices. This + algorithm classifies the waiting packets into a tree-like hierarchy + of classes; the leaves of this tree are in turn scheduled by + separate algorithms (called "disciplines" in this context). + + See the top of net/sched/sch_cbq.c for references about the CBQ + algorithm. + + CBQ is a commonly used scheduler, so if you're unsure, you should + say Y here. Then say Y to all the queueing algorithms below that you + want to use as CBQ disciplines. Then say Y to "Packet classifier + API" and say Y to all the classifiers you want to use; a classifier + is a routine that allows you to sort your outgoing traffic into + classes based on a certain criterion. + + This code is also available as a module called sch_cbq.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +CSZ packet scheduler +CONFIG_NET_SCH_CSZ + Say Y here if you want to use the Clark-Shenker-Zhang (CSZ) packet + scheduling algorithm for some of your network devices. At the + moment, this is the only algorithm that can guarantee service for + real-time applications (see the top of net/sched/sch_csz.c for + details and references about the algorithm). + + Note: this scheduler is currently broken. + + This code is also available as a module called sch_csz.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +#ATM pseudo-scheduler +#CONFIG_NET_SCH_ATM +# +# ??? +# + +The simplest PRIO pseudo scheduler +CONFIG_NET_SCH_PRIO + Say Y here if you want to use an n-band priority queue packet + "scheduler" for some of your network devices or as a leaf discipline + for the CBQ scheduling algorithm. If unsure, say Y. + + This code is also available as a module called sch_prio.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +RED queue +CONFIG_NET_SCH_RED + Say Y here if you want to use the Random Early Detection (RED) + packet scheduling algorithm for some of your network devices (see + the top of net/sched/sch_red.c for details and references about the + algorithm). + + This code is also available as a module called sch_red.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +SFQ queue +CONFIG_NET_SCH_SFQ + Say Y here if you want to use the Stochastic Fairness Queueing (SFQ) + packet scheduling algorithm for some of your network devices or as a + leaf discipline for the CBQ scheduling algorithm (see the top of + net/sched/sch_sfq.c for details and references about the SFQ + algorithm). + + This code is also available as a module called sch_sfq.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +TEQL queue +CONFIG_NET_SCH_TEQL + Say Y here if you want to use the True Link Equalizer (TLE) packet + scheduling algorithm for some of your network devices or as a leaf + discipline for the CBQ scheduling algorithm. This queueing + discipline allows the combination of several physical devices into + one virtual device. (see the top of net/sched/sch_teql.c for + details). + + This code is also available as a module called sch_teql.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +TBF queue +CONFIG_NET_SCH_TBF + Say Y here if you want to use the Simple Token Bucket Filter (TBF) + packet scheduling algorithm for some of your network devices or as a + leaf discipline for the CBQ scheduling algorithm (see the top of + net/sched/sch_tbf.c for a description of the TBF algorithm). + + This code is also available as a module called sch_tbf.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +QoS support +CONFIG_NET_QOS + Say Y here if you want to include Quality Of Service scheduling + features, which means that you will be able to request certain + rate-of-flow limits for your network devices. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about QoS support. + +Rate estimator +CONFIG_NET_ESTIMATOR + In order for Quality of Service scheduling to work, the current + rate-of-flow for a network device has to be estimated; if you say Y + here, the kernel will do just that. + +Packet classifier API +CONFIG_NET_CLS + The CBQ scheduling algorithm requires that network packets which are + scheduled to be sent out over a network device be classified + according to some criterion. If you say Y here, you will get a + choice of several different packet classifiers with the following + questions. + +Routing tables based classifier +CONFIG_NET_CLS_ROUTE + If you say Y here, you will be able to classify outgoing packets + according to the route table entry they matched. If unsure, say Y. + + This code is also available as a module called cls_route.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Firewall based classifier +CONFIG_NET_CLS_FW + If you say Y here, you will be able to classify outgoing packets + according to firewall criteria you specified. + + This code is also available as a module called cls_fw.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +U32 classifier +CONFIG_NET_CLS_U32 + If you say Y here, you will be able to classify outgoing packets + according to their destination address. If unsure, say Y. + + This code is also available as a module called cls_u32.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt + +Special RSVP classifier +CONFIG_NET_CLS_RSVP + The Resource Reservation Protocol (RSVP) permits end systems to + request a minimum and maximum data flow rate for a connection; this + is important for real time data such as streaming sound or video. + + Say Y here if you want to be able to classify outgoing packets based + on their RSVP requests. + + This code is also available as a module called cls_rsvp.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt + +Special RSVP classifier for IPv6 +CONFIG_NET_CLS_RSVP6 + The Resource Reservation Protocol (RSVP) permits end systems to + request a minimum and maximum data flow rate for a connection; this + is important for real time data such as streaming sound or video. + + Say Y here if you want to be able to classify outgoing packets based + on their RSVP requests and you are using the new Internet Protocol + IPv6 as opposed to the older and more common IPv4. + + This code is also available as a module called cls_rsvp6.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt + +# +# Ingres traffic policing +# CONFIG_NET_CLS_POLICE +### +### Some expert please fill these in +### + +Network code profiler +CONFIG_NET_PROFILE + If you say Y here and to "/proc filesystem support" below, some + obscure and undocumented information about the network code's + performance will be written to /proc/net/profile. If you don't know + what it is about, you don't need it: say N. + +Comtrol Hostess SV-11 support +CONFIG_HOSTESS_SV11 + This is a network card for low speed synchronous serial links, at + up to 256Kbps. It supports both PPP and Cisco HDLC. + + At this point, the driver can only be compiled as a module. + +COSA/SRP sync serial boards support +CONFIG_COSA + This is a driver for COSA and SRP synchronous serial boards. These + boards allow to connect synchronous serial devices (for example + base-band modems, or any other device with the X.21, V.24, V.35 or + V.36 interface) to your Linux box. The cards can work as the + character device, synchronous PPP network device, or the Cisco HDLC + network device. + + To actually use the COSA or SRP board, you will need user-space + utilities for downloading the firmware to the cards and to set them + up. Look at the http://www.fi.muni.cz/~kas/cosa/ for more + information about the cards (including the pointer to the user-space + utilities). You can also read the comment at the top of the + drivers/net/cosa.c for details about the cards and the driver + itself. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cosa.o. For general information about + modules read Documentation/modules.txt. + +# Fibre Channel driver support +# CONFIG_NET_FC + +# Interphase 5526 Tachyon chipset based adaptor support +# CONFIG_IPHASE5526 + +Red Creek Hardware VPN (EXPERIMENTAL) +CONFIG_RCPCI + This is a driver for hardware which provides a Virtual Private + Network (VPN). Say Y if you have it. + + This code is also available as a module called rcpci.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +SBNI Leased Line Adapters +CONFIG_SBNI + This is a driver for ISA SBNI12-xx cards that is a low cost + alternative to leased line modems. Say Y if you want to insert + driver into kernel or say M to compile driver as a module. + + You can find more information and last versions of drivers and + utilities at http://www.granch.ru. If you have any question you + can mail to sbni@granch.ru. + + Say N if unsure. + +WAN Drivers +CONFIG_WAN_DRIVERS + Say Y to this option if your Linux box contains a WAN card and you + are planning to use the box as a WAN ( = Wide Area Network) router + ( = device used to interconnect local area networks over wide area + communication links, such as leased lines or public data networks, + e.g. X.25 or frame relay) and you will be offered a list of drivers + for WAN cards currently available. For more information, read + Documentation/networking/wan-router.txt. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about WAN card drivers. If unsure, say N. + +Sangoma WANPIPE(tm) multiprotocol cards +CONFIG_VENDOR_SANGOMA + WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com ) is a + family of intelligent multiprotocol WAN adapters with data transfer + rates up to T1 (1.544 Mbps). They are also known as Synchronous Data + Link Adapters (SDLA) and designated S502E(A), S503 or S508. These + cards support the X.25, Frame Relay, and PPP protocols. If you have + one or more of these cards, say Y to this option; you may then also + want to read the file Documentation/networking/wanpipe.txt. The next + questions will ask you about the protocols you want the driver to + support. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wanpipe.o. For general information about + modules read Documentation/modules.txt. + +Maximum number of cards +CONFIG_WANPIPE_CARDS + Enter number of WANPIPE adapters installed in your machine. The + driver can support up to 8 cards. You may enter more than you + actually have if you plan to add more cards in the future without + re-compiling the driver, but remember that in this case you'll waste + some kernel memory (about 1K per card). + +WANPIPE X.25 support +CONFIG_WANPIPE_X25 + Say Y to this option if you are planning to connect a WANPIPE card + to an X.25 network. You should then also have said Y to "CCITT X.25 + Packet Layer" and "LAPB Data Link Driver", above. If you say N, the + X.25 support will not be included in the driver (saves about 16 KB + of kernel memory). + +WANPIPE Frame Relay support +CONFIG_WANPIPE_FR + Say Y to this option if you are planning to connect a WANPIPE card + to a frame relay network. You should then also have said Y to "Frame + Relay (DLCI) support", above. If you say N, the frame relay + support will not be included in the driver (saves about 16 KB of + kernel memory). + +WANPIPE PPP support +CONFIG_WANPIPE_PPP + Say Y to this option if you are planning to connect a WANPIPE card + to a leased line using Point-to-Point protocol (PPP). You should + then also have said Y to "PPP (point-to-point) support", above. If + you say N, the PPP support will not be included in the driver (saves + about 16 KB of kernel memory). + +Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL) +CONFIG_CYCLADES_SYNC + Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and + http://www.cyclades.com.br ) is an intelligent multiprotocol WAN + adapter with data transfer rates up to 512 Kbps. These cards support + the X.25 and SNA related protocols. If you have one or more of these + cards, say Y to this option. The next questions will ask you about + the protocols you want the driver to support (for now only X.25 is + supported). + + While no documentation is available at this time please grab the + wanconfig tarball in http://www.conectiva.com.br/~acme/cycsyn-devel + (with minor changes to make it compile with the current wanrouter + include files; efforts are being made to use the original package + available at ftp://ftp.sangoma.com ). + + Feel free to contact me or the cycsyn-devel mailing list at + acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for + additional details, I hope to have documentation available as soon + as possible. + + The driver will be compiled as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cyclomx.o. For general information about + modules read Documentation/modules.txt. + +Cyclom 2X X.25 support +CONFIG_CYCLOMX_X25 + Say Y to this option if you are planning to connect a Cyclom 2X card + to an X.25 network. + + If you say N, the X.25 support will not be included in the driver + (saves about 11 KB of kernel memory). + +Ethernet (10 or 100Mbit) +CONFIG_NET_ETHERNET + Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common + type of Local Area Network (LAN) in universities and companies. + + Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over + coaxial cable, linking computers in a chain), 10BASE-T or twisted + pair (10 Mbps over twisted pair cable, linking computers to central + hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs), + 100BASE-TX (100 Mbps over two twisted pair cables, using hubs), + 100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair + cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links) + [the 100BASE varieties are also known as Fast Ethernet], and Gigabit + Ethernet (1 Gbps over optical fiber or short copper links). + + If your Linux machine will be connected to an Ethernet and you have + an Ethernet network interface card (NIC) installed in your computer, + say Y here and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . You will then also have + to say Y to the driver for your particular NIC. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about Ethernet network cards. If unsure, say N. + +Sun LANCE Ethernet support +CONFIG_SUN_LANCE + This is support for lance Ethernet cards on Sun workstations such as + the SPARCstation IPC (any SPARC with a network interface 'le0' under + SunOS basically). + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called lance.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Sun Intel Ethernet support +CONFIG_SUN_INTEL + This is support for the Intel Ethernet cards on some Sun + workstations (all those with a network interface 'ie0' under SunOS). + +Western Digital/SMC cards +CONFIG_NET_VENDOR_SMC + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about Western Digital cards. If you say Y, you will be + asked for your specific card in the following questions. + +WD80*3 support +CONFIG_WD80x3 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called wd.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +SMC Ultra MCA support +CONFIG_ULTRAMCA + If you have a network (Ethernet) card of this type and are running + an MCA based system (PS/2), say Y and read the Ethernet-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc-mca.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +SMC Ultra support +CONFIG_ULTRA + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + Important: There have been many reports that, with some motherboards + mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, + such as some BusLogic models) causes corruption problems with many + operating systems. The Linux smc-ultra driver has a work-around for + this but keep it in mind if you have such a SCSI card and have + problems. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc-ultra.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +SMC Ultra32 EISA support +CONFIG_ULTRA32 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called smc-ultra32.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt as well + as Documentation/networking/net-modules.txt. + +SMC 9194 Support +CONFIG_SMC9194 + This is support for the SMC9xxx based Ethernet cards. Choose this + option if you have a DELL laptop with the docking station, or + another SMC9192/9194 based chipset. Say Y if you want it compiled + into the kernel, and read the file + Documentation/networking/smc9.txt and the Ethernet-HOWTO, available + from http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module will be called smc9194.o. If you want to compile + it as a module, say M here and read Documentation/modules.txt as + well as Documentation/networking/net-modules.txt. + +PCI NE2000 support +CONFIG_NE2K_PCI + This driver is for NE2000 compatible PCI cards. It will not work + with ISA NE2000 cards (they have their own driver, "NE2000/NE1000 + support" below). If you have a PCI NE2000 network (Ethernet) card, + say Y and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ne2k-pci.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +PCI DM9102 support +CONFIG_DM9102 + This driver is for DM9102 compatible PCI cards from Davicom + (http://www.davicom.com.tw) + If you have a PCI DM9102 network (Ethernet) card, say Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dmfe.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Racal-Interlan (Micom) NI cards +CONFIG_NET_VENDOR_RACAL + If you have a network (Ethernet) card belonging to this class, such + as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about NI cards. If you say Y, you will be asked for + your specific card in the following questions. + +NI5010 support (EXPERIMENTAL) +CONFIG_NI5010 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Note that this is still + experimental code. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ni5010.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +NI5210 support +CONFIG_NI52 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ni52.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +NI6510 support +CONFIG_NI65 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ni65.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +RealTek 8129/8139 (not 8019/8029!) support +CONFIG_RTL8139 + This is a driver for the Fast Ethernet PCI network cards based on + the RTL8129 and RTL8139 chips. If you have one of those, say Y and + read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called rtl8139.o. + +SiS 900 PCI Fast Ethernet Adapter support +CONFIG_SIS900 + This is a driver for the Fast Ethernet PCI network cards based on + the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in + SiS 630 and SiS 540 chipsets. If you have one of those, say Y and + read the Ethernet-HOWTO, available via FTP (user: anonymous) in + ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Please read + Documentation/networking/sis900.txt and comments at the beginning + of drivers/net/sis900.c for more information. + + This driver also supports AMD 79C901 HomePNA such that you can use + your phone line as network cable. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called sis900.o. + +Packet Engines Yellowfin Gigabit-NIC support +CONFIG_YELLOWFIN + Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet + adapter. This adapter is used by the Beowulf Linux cluster project. + See http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html for + more information about this driver in particular and Beowulf in + general. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called yellowfin.o. + +General Instruments Surfboard 1000 +CONFIG_NET_SB1000 + This is a driver for the General Instrument (also known as + NextLevel) SURFboard 1000 internal + cable modem. This is an ISA card which is used by a number of cable + TV companies to provide cable modem access. It's a one-way + downstream-only cable modem, meaning that your upstream net link is + provided by your regular phone modem. + + At present this driver only compiles as a module, so say M here if + you have this card. The module will be called sb1000.o. Then read + Documentation/networking/README.sb1000 for information on how to use + this module, as it needs special ppp scripts for establishing a + connection. Further documentation and the necessary scripts can be + found at: + + http://www.jacksonville.net/~fventuri/ + http://home.adelphia.net/~siglercm/sb1000.html + http://linuxpower.cx/~cable/ + + If you don't have this card, of course say N. + +Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support +CONFIG_ACENIC + Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear + GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet + adapter. The driver allows for using the Jumbo Frame option (9000 + bytes/frame) however it requires that your switches can handle this + as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig + line. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called acenic.o. + +Omit support for older Tigon I based AceNICs +CONFIG_ACENIC_OMIT_TIGON_I + Say Y here if you only have Tigon II based AceNICs and want to leave + out support for the older Tigon I based cards which are no longer + being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B + version)). This will reduce the size of the driver object by + app. 100KB. If you are not sure whether your card is a Tigon I or a + Tigon II, say N here. + + The safe and default value for this is N. + +AMD LANCE and PCnet (AT1500 and NE2100) support +CONFIG_LANCE + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Some LinkSys cards are + of this type. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called lance.o. + +3COM cards +CONFIG_NET_VENDOR_3COM + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about 3COM cards. If you say Y, you will be asked for + your specific card in the following questions. + +3c501 support +CONFIG_EL1 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Also, consider buying a + new card, since the 3c501 is slow, broken, and obsolete: you will + have problems. Some people suggest to ping ("man ping") a nearby + machine every minute ("man cron") when using this card. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c501.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +3c503 support +CONFIG_EL2 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c503.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +3c505 support +CONFIG_ELPLUS + Information about this network (Ethernet) card can be found in + Documentation/networking/3c505.txt. If you have a card of this type, + say Y and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + 3c505.o. + +3c507 support (EXPERIMENTAL) +CONFIG_EL16 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c507.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +3c523 support +CONFIG_ELMC + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c523.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +3c527 support +CONFIG_ELMC_II + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called 3c527.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +3c509/3c579 support +CONFIG_EL3 + If you have a network (Ethernet) card belonging to the 3Com + EtherLinkIII series, say Y and read the Ethernet-HOWTO, available + from http://metalab.unc.edu/mdw/linux.html#howto . + + If your card is not working you may need to use the DOS + setup disk to disable Plug & Play mode, and to select the default + media type. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + 3c509.o. + +3c590 series (592/595/597) "Vortex" support +CONFIG_VORTEX + If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) + or "Boomerang" series (EtherLink XL 3c900 or 3c905) network + (Ethernet) card, say Y and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . More specific + information is in Documentation/networking/vortex.txt and in the + comments at the beginning of drivers/net/3c59x.c. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Other ISA cards +CONFIG_NET_ISA + If your network (Ethernet) card hasn't been mentioned yet and its + bus system (that's the way the cards talks to the other components + of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y. + Make sure you know the name of your card. Read the Ethernet-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + If unsure, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause this configure script to skip all + the remaining ISA network card questions. If you say Y, you will be + asked for your specific card in the following questions. + +Generic ARCnet support +CONFIG_ARCNET + If you have a network card of this type, say Y and check out the + (arguably) beautiful poetry in Documentation/networking/arcnet.txt. + + You need both this driver, and the driver for the particular ARCnet + chipset of your card. If you don't know, then it's probably a + COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset + support" below. + + You might also want to have a look at the Ethernet-HOWTO, available + from http://metalab.unc.edu/mdw/linux.html#howto (even though ARCnet + is not really Ethernet). + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called arcnet.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Enable arc0e (ARCnet "ether-encap" packet format) +CONFIG_ARCNET_ETH + This allows you to use "Ethernet encapsulation" with your ARCnet + card via the virtual arc0e device. You only need arc0e if you want + to talk to nonstandard ARCnet software, specifically, + DOS/Windows-style "NDIS" drivers. You do not need to say Y here to + communicate with industry-standard RFC1201 implementations, like the + arcether.com packet driver or most DOS/Windows ODI drivers. RFC1201 + is included automatically as the arc0 device. Please read the + ARCnet documentation in Documentation/networking/arcnet.txt for more + information about using arc0e and arc0s. + +Enable arc0s (ARCnet RFC1051 packet format) +CONFIG_ARCNET_1051 + This allows you to use RFC1051 with your ARCnet card via the virtual + arc0s device. You only need arc0s if you want to talk to ARCnet + software complying with the "old" standard, specifically, the DOS + arcnet.com packet driver, Amigas running AmiTCP, and some variants + of NetBSD. You do not need to say Y here to communicate with + industry-standard RFC1201 implementations, like the arcether.com + packet driver or most DOS/Windows ODI drivers. RFC1201 is included + automatically as the arc0 device. Please read the ARCnet + documentation in Documentation/networking/arcnet.txt for more + information about using arc0e and arc0s. + +ARCnet COM90xx (normal) chipset driver +CONFIG_ARCNET_COM90xx + This is the chipset driver for the standard COM90xx cards. If you + have always used the old ARCnet driver without knowing what type of + card you had, this is probably the one for you. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called com90xx.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +ARCnet COM90xx (IO mapped) chipset driver +CONFIG_ARCNET_COM90xxIO + This is the chipset driver for the COM90xx cards, using them in + IO-mapped mode instead of memory-mapped mode. This is slower than + the normal driver. Only use it if your card doesn't support shared + memory. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called com90io.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +ARCnet COM90xx (RIM I) chipset driver +CONFIG_ARCNET_RIM_I + This is yet another chipset driver for the COM90xx cards, but this + time only using memory-mapped mode, and no IO ports at all. This + driver is completely untested, so if you have one of these cards, + please mail David.Woodhouse@mvhi.com, especially if it works! + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module will be called arc-rimi.o. If you want to compile + it as a module, say M here and read Documentation/modules.txt as + well as Documentation/networking/net-modules.txt. + +ARCnet COM20020 chipset driver +CONFIG_ARCNET_COM20020 + This is the driver for the new COM20020 chipset. It supports such + things as promiscuous mode, so packet sniffing is possible, and + extra diagnostic information. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called com20020.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Cabletron E21xx support +CONFIG_E2100 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called e2100.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +CS89x0 support +CONFIG_CS89x0 + Support for CS89x0 chipset based Ethernet cards. If you have a + network (Ethernet) card of this type, say Y and read the + Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto as well as + Documentation/networking/cs89x0.txt. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + cs89x.o. + +DEPCA support +CONFIG_DEPCA + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto as well as + drivers/net/depca.c. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + depca.o. + +EtherWorks 3 support +CONFIG_EWRK3 + This driver supports the DE203, DE204 and DE205 network (Ethernet) + cards. If this is for you, say Y and read + Documentation/networking/ewrk3.txt in the kernel source as well as + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + ewrk3.o. + +SEEQ8005 support +CONFIG_SEEQ8005 + This is a driver for the SEEQ 8005 network (Ethernet) card. If this + is for you, read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + ewrk3.o. + +AT1700/1720 support +CONFIG_AT1700 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + at1700.o. + +FMV-181/182/183/184 support +CONFIG_FMV18X + If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card, + say Y and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you use an FMV-183 or FMV-184 and it is not working, you may need + to disable Plug & Play mode of the card. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called fmv18x.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +EtherExpress PRO support +CONFIG_EEXPRESS_PRO + If you have a network (Ethernet) card of this type, say Y. Note + however that the EtherExpress PRO/100 Ethernet card has its own + separate driver. Please read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eepro.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +EtherExpress support +CONFIG_EEXPRESS + If you have an EtherExpress16 network (Ethernet) card, say Y and + read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Note that the Intel + EtherExpress16 card used to be regarded as a very poor choice + because the driver was very unreliable. We now have a new driver + that should do better. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + eexpress.o. + +HP PCLAN+ (27247B and 27252A) support +CONFIG_HPLAN_PLUS + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called hp-plus.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +HP PCLAN (27245 and other 27xxx series) support +CONFIG_HPLAN + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called hp.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +HP 10/100VG PCLAN (ISA, EISA, PCI) support +CONFIG_HP100 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + hp100.o. + +NE2000/NE1000 support +CONFIG_NE2000 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Many Ethernet cards + without a specific driver are compatible with NE2000. + + If you have a PCI NE2000 card however, say N here and Y to "PCI + NE2000 support", above. If you have a NE2000 card and are running on + an MCA system (a bus system used on some IBM PS/2 computers and + laptops), say N here and Y to "NE/2 (ne2000 MCA version) support", + below. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ne.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +SK_G16 support +CONFIG_SK_G16 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + +NE/2 (ne2000 MCA version) support +CONFIG_NE2_MCA + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ne2.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +SKnet MCA support +CONFIG_SKMC + These are Micro Channel ethernet adapters. You need to say Y to "MCA + support" in order to use this driver. Supported cards are the SKnet + Junior MC2 and the SKnet MC2(+). The driver automatically + distinguishes between the two cards. Note that using multiple boards + of different type hasn't been tested with this driver. Say Y if you + have one of these ethernet adapters. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called sk_mca.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +EISA, VLB, PCI and on board controllers +CONFIG_NET_EISA + This is another class of network cards which attach directly to the + bus. If you have one of those, say Y and read the Ethernet-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about this class of network cards. If you say Y, you + will be asked for your specific card in the following questions. If + you are unsure, say Y. + +AMD PCnet32 (VLB and PCI) support +CONFIG_PCNET32 + If you have a PCnet32 or PCnetPCI based network (Ethernet) card, + answer Y here and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pcnet32.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Ansel Communications EISA 3200 support +CONFIG_AC3200 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ac3200.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Mylex EISA LNE390A/LNE390B support (EXPERIMENTAL) +CONFIG_LNE390 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called lne390.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL) +CONFIG_NE3210 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Note that this driver + will NOT WORK for NE3200 cards as they are completely different. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ne3210.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Apricot Xen-II on board Ethernet +CONFIG_APRICOT + If you have a network (Ethernet) controller of this type, say Y and + read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + apricot.o. + +Generic DECchip & DIGITAL EtherWORKS PCI/EISA +CONFIG_DE4X5 + This is support for the DIGITAL series of PCI/EISA Ethernet cards. + These include the DE425, DE434, DE435, DE450 and DE500 models. If + you have a network card of this type, say Y and read the + Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . More specific + information is contained in Documentation/networking/de4x5.txt. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called de4x5.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +DECchip Tulip (dc21x4x) PCI support +CONFIG_DEC_ELCP + This driver is developed for the SMC EtherPower series Ethernet + cards and also works with cards based on the DECchip + 21040/21041/21140 (Tulip series) chips. Some LinkSys PCI cards are + of this type. (If your card is NOT SMC EtherPower 10/100 PCI + (smc9332dst), you can also try the driver for "Generic DECchip" + cards, above. However, most people with a network card of this type + will say Y here.) Do read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . More specific + information is contained in Documentation/networking/tulip.txt. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tulip.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Digi Intl. RightSwitch support +CONFIG_DGRS + This is support for the Digi International RightSwitch series of + PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6 + models. If you have a network card of this type, say Y and read the + Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . More specific + information is contained in Documentation/networking/dgrs.txt. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dgrs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +EtherExpress PRO/100 support +CONFIG_EEXPRESS_PRO100 + If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) + card, say Y and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eepro100.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +ICL EtherTeam 16i/32 support (EXPERIMENTAL) +CONFIG_ETH16I + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called eth16i.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +TI ThunderLAN support (EXPERIMENTAL) +CONFIG_TLAN + If you have a PCI Ethernet network card based on the ThunderLAN chip + which is supported by this driver, say Y and read the + Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + Devices currently supported by this driver are Compaq Netelligent, + Compaq NetFlex and Olicom cards. Please read the file + Documentation/networking/tlan.txt for more details. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tlan.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + + Please email feedback to james.banks@caldera.com. + +VIA Rhine support +CONFIG_VIA_RHINE + If you have a VIA "rhine" based network card (Rhine-I (3043) or + Rhine-2 (VT86c100A)), say Y here. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called via-rhine.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Racal-Interlan EISA ES3210 support (EXPERIMENTAL) +CONFIG_ES3210 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called es3210.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +SMC EtherPower II (EXPERIMENTAL) +CONFIG_EPIC100 + If you have an SMC EtherPower II 9432 PCI Ethernet network card + which is based on the SMC83c170, say Y and read the Ethernet-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called epic100.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +SGI Seeq ethernet controller support +CONFIG_SGISEEQ + Say Y here if you have an Seeq based Ethernet network card. This is + used in many Silicon Graphics machines. + +Zenith Z-Note support (EXPERIMENTAL) +CONFIG_ZNET + The Zenith Z-Note notebook computer has a built-in network + (Ethernet) card, and this is the Linux driver for it. Note that the + IBM Thinkpad 300 is compatible with the Z-Note and is also supported + by this driver. Read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + +Adaptec Starfire support +CONFIG_ADAPTEC_STARFIRE + If you have an Ethernet network card like this, say Y and read the + Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called starfire.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + +Pocket and portable adapters +CONFIG_NET_POCKET + Cute little network (Ethernet) devices which attach to the parallel + port ("pocket adapters"), commonly used with laptops. If you have + one of those, say Y and read the Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to plug a network (or some other) card into the PCMCIA + (or PC-card) slot of your laptop instead (PCMCIA is the standard for + credit card size extension cards used by all modern laptops), you + need the pcmcia-cs package (location contained in the file + Documentation/Changes) and you can say N here. + + Laptop users should read the Linux Laptop home page at + http://www.cs.utexas.edu/users/kharker/linux-laptop/ . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about this class of network devices. If you say Y, you + will be asked for your specific device in the following questions. + +AT-LAN-TEC/RealTek pocket adapter support +CONFIG_ATP + This is a network (Ethernet) device which attaches to your parallel + port. Read drivers/net/atp.c as well as the Ethernet-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto , if you + want to use this. If you intend to use this driver, you should have + said N to the Parallel Printer support, because the two drivers + don't like each other. + +D-Link DE600 pocket adapter support +CONFIG_DE600 + This is a network (Ethernet) device which attaches to your parallel + port. Read Documentation/networking/DLINK.txt as well as the + Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , if you want to use + this. It is possible to have several devices share a single parallel + port and it is safe to compile the corresponding drivers into the + kernel. + + If you want to compile this driver as a module however ( = code + which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt. + The module will be called de600.o. + +D-Link DE620 pocket adapter support +CONFIG_DE620 + This is a network (Ethernet) device which attaches to your parallel + port. Read Documentation/networking/DLINK.txt as well as the + Ethernet-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , if you want to use + this. It is possible to have several devices share a single parallel + port and it is safe to compile the corresponding drivers into the + kernel. + + If you want to compile this driver as a module however ( = code + which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt. + The module will be called de620.o. + +Token Ring driver support +CONFIG_TR + Token Ring is IBM's way of communication on a local network; the + rest of the world uses Ethernet. To participate on a Token Ring + network, you need a special Token ring network card. If you are + connected to such a Token Ring network and want to use your Token + Ring card under Linux, say Y here and to the driver for your + particular card below and read the Token-Ring mini-HOWTO, available + from http://metalab.unc.edu/mdw/linux.html#howto . Most people can + say N here. + +IBM Tropic chipset based adapter support +CONFIG_IBMTR + This is support for all IBM Token Ring cards that don't use DMA. If + you have such a beast, say Y and read the Token-Ring mini-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + Warning: this driver will almost definitely fail if more than one + active Token Ring card is present. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ibmtr.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +IBM Olympic chipset PCI adapter support +CONFIG_IBMOL + This is support for all non-Lanstreamer IBM PCI Token Ring Cards. + Specifically this is all IBM PCI, PCI Wake On Lan, PCI II, PCI II + Wake On Lan, and PCI 100/16/4 adapters. + + If you have such an adapter, say Y and read the Token-Ring + mini-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will will be called olympic.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + + Also read the file Documentation/networking/olympic.txt or check the + Linux Token Ring Project site for the latest information at + http://www.linuxtr.net + +Generic TMS380 Token Ring ISA/PCI adapter support +CONFIG_TMS380TR + This driver provides generic support for token ring adapters + based on the Texas Instruments TMS380 series chipsets. This + includes the SysKonnect TR4/16(+) ISA (SK-4190), SysKonnect + TR4/16(+) PCI (SK-4590), SysKonnect TR4/16 PCI (SK-4591), + Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and Intel + TokenExpress 4/16 and PRO ISA adapters. + + If you have such an adapter and would like to use it, say Y or M and + read the Token-Ring mini-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + Also read the file linux/Documentation/networking/sktr.txt or check + http://www.auk.cx/tms380tr/ + +Traffic Shaper (EXPERIMENTAL) +CONFIG_SHAPER + The traffic shaper is a virtual network device that allows you to + limit the rate of outgoing data flow over some other network device. + The traffic that you want to slow down can then be routed through + these virtual devices. See Documentation/networking/shaper.txt for + more information. + + An alternative to this traffic shaper is the experimental + Class-Based Queueing (CBQ) scheduling support which you get if you + say Y to "QoS and/or fair queueing" above. + + To set up and configure shaper devices, you need the shapecfg + program, available from ftp://shadow.cabi.net/pub/Linux in the + shaper package. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called shaper.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. If unsure, + say N. + +FDDI driver support +CONFIG_FDDI + Fiber Distributed Data Interface is a high speed local area network + design; essentially a replacement for high speed Ethernet. FDDI can + run over copper or fiber. If you are connected to such a network and + want a driver for the FDDI card in your computer, say Y here (and + then also Y to the driver for your FDDI card, below). Most people + will say N. + +Digital DEFEA and DEFPA adapter support +CONFIG_DEFXX + This is support for the DIGITAL series of EISA (DEFEA) and PCI + (DEFPA) controllers which can connect you to a local FDDI network. + +HIgh Performance Parallel Interface support (EXPERIMENTAL) +CONFIG_HIPPI + HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and + 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI + can run over copper (25m) or fiber (300m on multi-mode or 10km on + single-mode). HIPPI networks are commonly used for clusters and to + connect to super computers. If you are connected to a HIPPI network + and have a HIPPI network card in your computer that you want to use + under Linux, say Y here (you must also remember to enable the driver + for your HIPPI card below). Most people will say N here. + +Essential RoadRunner HIPPI PCI adapter support +CONFIG_ROADRUNNER + Say Y here if this is your PCI HIPPI network card. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called rrunner.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. If unsure, + say N. + +Use large TX/RX rings +CONFIG_ROADRUNNER_LARGE_RINGS + If you say Y here, the RoadRunner driver will preallocate up to 2 MB + of additional memory to allow for fastest operation, both for + transmitting and receiving. This memory cannot be used by any other + kernel code or by user space programs. Say Y here only if you have + the memory. + +Acorn Ether1 card +CONFIG_ARM_ETHER1 + If you have an Acorn system with one of these (AKA25) network cards, + you should say Y to this option if you wish to use it with Linux. + +Acorn/ANT Ether3 card +CONFIG_ARM_ETHER3 + If you have an Acorn system with one of these network cards, you + should say Y to this option if you wish to use it with Linux. + +I Cubed EtherH card +CONFIG_ARM_ETHERH + If you have an Acorn system with one of these network cards, you + should say Y to this option if you wish to use it with Linux. + +EBSA-110 Ethernet interface +CONFIG_ARM_AM79C961A + If you wish to compile a kernel for the EBSA-110, then you should + always answer Y to this. + +Support CDROM drives that are not SCSI or IDE/ATAPI +CONFIG_CD_NO_IDESCSI + If you have a CDROM drive that is neither SCSI nor IDE/ATAPI, say Y + here, otherwise N. Read the CDROM-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about these CDROM drives. If you are unsure what you + have, say Y and find out whether you have one of the following + drives. + + For each of these drivers, a file Documentation/cdrom/ + exists. Especially in cases where you do not know exactly which kind + of drive you have you should read there. Most of these drivers use a + file drivers/cdrom/.h where you can define your + interface parameters and switch some internal goodies. + + All these CDROM drivers are also usable as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). If you want to compile them as module, say M instead of Y and + read Documentation/modules.txt. + + If you want to use any of these CDROM drivers, you also have to + answer Y or M to "ISO 9660 CDROM filesystem support" below (this + answer will get "defaulted" for you if you enable any of the Linux + CDROM drivers). + +Sony CDU31A/CDU33A CDROM support +CONFIG_CDU31A + These CDROM drives have a spring-pop-out caddyless drawer, and a + rectangular green LED centered beneath it. NOTE: these CDROM drives + will not be auto detected by the kernel at boot time; you have to + provide the interface address as an option to the kernel at boot + time as described in Documentation/cdrom/cdu31a or fill in your + parameters into drivers/cdrom/cdu31a.c. Try "man bootparam" or + see the documentation of your boot loader (lilo or loadlin) about + how to pass options to the kernel. The lilo procedure is also + explained in the SCSI-HOWTO. + + If you say Y here, you should also say Y or M to "ISO 9660 CDROM + filesystem support" below, because that's the filesystem used on + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cdu31a.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Standard Mitsumi [no XA/Multisession] CDROM support +CONFIG_MCD + This is the older of the two drivers for the older Mitsumi models + LU-005, FX-001 and FX-001D. This is not the right driver for the + FX-001DE and the triple or quad speed models (all these are + IDE/ATAPI models). Please also the file Documentation/cdrom/mcd. + + With the old LU-005 model, the whole drive chassis slides out for cd + insertion. The FX-xxx models use a motorized tray type mechanism. + Note that this driver does not support XA or MultiSession CDs + (PhotoCDs). There is a new driver (next question) which can do + this. If you want that one, say N here. + + If you say Y here, you should also say Y or M to "ISO 9660 CDROM + filesystem support" below, because that's the filesystem used on + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mcd.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +IRQ channel for Mitsumi CD-ROM +CONFIG_MCD_IRQ + This allows you to specify the default value of the IRQ used by the + driver. This setting can be overridden by passing the "mcd=" + parameter to the kernel at boot time (or at module load time if you + said M to "Standard Mitsumi CDROM support"). + +I/O base address for Mitsumi CD-ROM +CONFIG_MCD_BASE + This allows you to specify the default value of the I/O base address + used by the driver. This setting can be overridden by passing the + "mcd=" parameter to the kernel at boot time (or at module load time + if you said M to "Standard Mitsumi CDROM support"). + +Mitsumi [XA/MultiSession] support +CONFIG_MCDX + Use this driver if you want to be able to read XA or MultiSession + CDs (PhotoCDs) as well as ordinary CDs with your Mitsumi LU-005, + FX-001 or FX-001D CDROM drive. In addition, this driver uses much + less kernel memory than the old one, if that is a concern. This + driver is able to support more than one drive, but each drive needs + a separate interface card. Please read the file + Documentation/cdrom/mcdx. + + If you say Y here, you should also say Y or M to "ISO 9660 CDROM + filesystem support" below, because that's the filesystem used on + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mcdx.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support +CONFIG_SBPCD + This driver supports most of the drives which use the Panasonic or + Sound Blaster interface. Please read the file + Documentation/cdrom/sbpcd. + + The Matsushita CR-521, CR-522, CR-523, CR-562, CR-563 drives + (sometimes labeled "Creative"), the Creative Labs CD200, the + Longshine LCS-7260, the "IBM External ISA CDROM" (in fact a CR-56x + model), the TEAC CD-55A fall under this category. Some other + "electrically compatible" drives (Vertos, Genoa, some Funai models) + are currently not supported; for the Sanyo H94A drive currently a + separate driver (asked later) is responsible. Most drives have a + uniquely shaped faceplate, with a caddyless motorized drawer, but + without external brand markings. The older CR-52x drives have a + caddy and manual loading/eject, but still no external markings. The + driver is able to do an extended auto-probing for interface + addresses and drive types; this can help to find facts in cases you + are not sure, but can consume some time during the boot process if + none of the supported drives gets found. Once your drive got found, + you should enter the reported parameters into drivers/cdrom/sbpcd.h + and set "DISTRIBUTION 0" there. + + This driver can support up to four CDROM controller cards, and each + card can support up to four CDROM drives; if you say Y here, you + will be asked how many controller cards you have. If compiled as a + module, only one controller card (but with up to four drives) is + usable. + + If you say Y here, you should also say Y or M to "ISO 9660 CDROM + filesystem support" below, because that's the filesystem used on + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sbpcd.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Matsushita/Panasonic, ... second CDROM controller support +CONFIG_SBPCD2 + Say Y here only if you have two CDROM controller cards of this type + (usually only if you have more than four drives). You should enter + the parameters for the second, third and fourth interface card into + linux/include/linux/sbpcd.h before compiling the new kernel. Read + the file Documentation/cdrom/sbpcd. + +Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support +CONFIG_AZTCD + This is your driver if you have an Aztech CDA268-01A, Orchid + CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCDROM CR520 or + CR540 CDROM drive. This driver -- just like all these CDROM drivers + -- is NOT for CDROM drives with IDE/ATAPI interfaces, such as Aztech + CDA269-031SE. Please read the file Documentation/cdrom/aztcd. + + If you say Y here, you should also say Y or M to "ISO 9660 CDROM + filesystem support" below, because that's the filesystem used on + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called aztcd.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Sony CDU535 CDROM support +CONFIG_CDU535 + This is the driver for the older Sony CDU-535 and CDU-531 CDROM + drives. Please read the file Documentation/cdrom/sonycd535. + + If you say Y here, you should also say Y or M to "ISO 9660 CDROM + filesystem support" below, because that's the filesystem used on + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sonycd535.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +Goldstar R420 CDROM support +CONFIG_GSCD + If this is your CDROM drive, say Y here. As described in the file + linux/Documentation/cdrom/gscd, you might have to change a setting + in the file linux/drivers/cdrom/gscd.h before compiling the + kernel. Please read the file Documentation/cdrom/gscd. + + If you say Y here, you should also say Y or M to "ISO 9660 CDROM + filesystem support" below, because that's the filesystem used on + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called gscd.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Philips/LMS CM206 CDROM support +CONFIG_CM206 + If you have a Philips/LMS CDROM drive cm206 in combination with a + cm260 host adapter card, say Y here. Please also read the file + Documentation/cdrom/cm206. + + If you say Y here, you should also say Y or M to "ISO 9660 CDROM + filesystem support" below, because that's the filesystem used on + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cm206.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Optics Storage DOLPHIN 8000AT CDROM support +CONFIG_OPTCD + This is the driver for the 'DOLPHIN' drive with a 34-pin Sony + compatible interface. It also works with the Lasermate CR328A. If + you have one of those, say Y. This driver does not work for the + Optics Storage 8001 drive; use the IDE-ATAPI CDROM driver for that + one. Please read the file Documentation/cdrom/optcd. + + If you say Y here, you should also say Y or M to "ISO 9660 CDROM + filesystem support" below, because that's the filesystem used on + CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called optcd.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Sanyo CDR-H94A CDROM support +CONFIG_SJCD + If this is your CDROM drive, say Y here and read the file + Documentation/cdrom/sjcd. You should then also say Y or M to + "ISO 9660 CDROM filesystem support" below, because that's the + filesystem used on CDROMs. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sjcd.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Soft configurable cdrom interface card support +CONFIG_CDI_INIT + If you want to include boot-time initialization of any cdrom + interface card that is software configurable, say Y here. Currently + only the ISP16/MAD16/Mozart sound cards with built-in cdrom + interfaces are supported. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about these CDROM drives. + +ISP16/MAD16/Mozart soft configurable cdrom interface support +CONFIG_ISP16_CDI + These are sound cards with built-in cdrom interfaces using the OPTi + 82C928 or 82C929 chips. Say Y here to have them detected and + possibly configured at boot time. In addition, You'll have to say Y + to a driver for the particular cdrom drive you have attached to the + card. Read Documentation/cdrom/isp16 for details. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called isp16.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Quota support +CONFIG_QUOTA + If you say Y here, you will be able to set per user limits for disk + usage (also called disk quotas). Currently, it works only for the + ext2 filesystem. You need additional software in order to use quota + support; for details, read the Quota mini-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . Probably the quota + support is only useful for multi user systems. If unsure, say N. + +Support for USB (EXPERIMENTAL) +CONFIG_USB + Universal Serial Bus (USB) is a specification for a serial bus + system which offers higher speeds and more features than the + traditional PC serial port. The bus supplies power to peripherals + and allows for hot swapping. Up to 127 USB peripherals can be + connected to a single USB port in a tree structure; the USB port is + the root of the tree, the peripherals are the leafs and the inner + nodes are special USB devices called hubs. Many newer PC's have USB + ports and newer peripherals such as scanners, keyboards, mice, + modems and printers support the USB protocol and can be connected to + the PC via those ports. + + Say Y here if your computer has a USB port and you want to + experiment with USB devices. You then need to say Y to at least one + of "UHCI support" or "OHCI support" below (the type of interface + that the USB hardware in your computer provides) and then choose + from among the drivers for USB peripherals. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usbcore.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +UHCI (intel PIIX4 and others) support? +CONFIG_USB_UHCI + The Universal Host Controller Interface is a standard by Intel for + accessing the USB hardware in the PC (which is also called the USB + host controller). If your USB host controller conforms to this + standard, say Y. All recent boards with Intel PCI chipsets conform + to this standard. If unsure, say Y. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-uhci.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +OHCI (compaq and some others) support? +CONFIG_USB_OHCI + The Open Host Controller Interface is a standard by Compaq for + accessing the USB PC hardware (also called USB host controller). If + your USB host controller conforms to this standard, say Y. The USB + host controllers on most non-Intel architectures and on several x86 + compatibles with non-Intel chipsets conform to this standard. + + There are currently two OHCI drivers in development. You should + compile at most one. The other one is "OHCI-HCD (other OHCI opt. + Virt. Root Hub) support?", below. + + You may want to read the file drivers/usb/README.ohci. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-ohci.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Enable tons of OHCI debugging output +CONFIG_USB_OHCI_DEBUG + Say Y here in order to have the OHCI code generate verbose debugging + output. + +OHCI-HCD (other OHCI opt. Virt. Root Hub) support? +CONFIG_USB_OHCI_HCD + This is an alternative driver for USB PC hardware (also called USB + host controller) which complies with Compaq's Open Host Controller + Interface. You may want to read the file + drivers/usb/README.ohci_hcd. + + There are currently two OHCI drivers in development. You should + compile at most one. The other one is "OHCI (compaq and some others) + support?", above. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-ohci-hcd.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + +OHCI-HCD Virtual Root Hub +CONFIG_USB_OHCI_VROOTHUB + The virtual root hub support is currently unstable, so you probably + want to say N unless you are a hacker. But you aren't a hacker since + you are reading help texts. + +Enable lots of ISOC debugging output +CONFIG_USB_DEBUG_ISOC + Say Y here if you want to get lots of debugging output related to + the USB code. + +USB hub support +CONFIG_USB_HUB + Say Y here if you want to connect several USB devices to a single + USB port. You will need an USB hub to do this. + + If unsure, say Y. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called hub.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB mouse support +CONFIG_USB_MOUSE + Say Y here if you want to connect a USB mouse to your computer's USB + port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mouse.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB HP scanner support +CONFIG_USB_HP_SCANNER + Say Y here if you want to connect a USB HP scanner to your + computer's USB port. Please read drivers/usb/README.hp_scanner + for more information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called hp_scanner.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +USB keyboard support +CONFIG_USB_KBD + Say Y here if you want to connect a USB keyboard to your computer's + USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-keyboard.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + +USB audio parsing support +CONFIG_USB_AUDIO + Say Y here if you want to connect audio equipment such as USB + speakers to your computer's USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called audio.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Communications Device Class (ACM) support (Preliminary) +CONFIG_USB_ACM + This driver allows for devices which support the Abstract Control + Model, including many USB-based modems, ISDN adapters, and network + adapters. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called acm.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Belkin and Peracom serial support +CONFIG_USB_SERIAL + Say Y here if you want to connect a Belkin, Peracom, or eTek + single port USB to serial converter. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called usb-serial.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + +USB Printer support +CONFIG_USB_PRINTER + Say Y here if you want to connect a printer to your computer's USB + port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called printer.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB CPiA Camera support +CONFIG_USB_CPIA + Say Y here if you want to connect this type of camera to your + computer's USB port. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpia.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB Kodak DC-2xx Camera support +CONFIG_USB_DC2XX + Say Y here if you want to connect this type of still camera to + your computer's USB port. See drivers/usb/README.dc2xx for more + information; some non-Kodak cameras may also work with this + driver, given application support (such as www.gPhoto.org). + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called dc2xx.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB SCSI Support +CONFIG_USB_SCSI + Say Y here if you want to connect SCSI devices to your computer's + USB port. + +USB SCSI verbose debug +CONFIG_USB_SCSI_DEBUG + Say Y here in order to have the USB SCSI code generate verbose + debugging messages. + +#EZUSB Firmware downloader +#CONFIG_USB_EZUSB + +USS720 parport driver +CONFIG_USB_USS720 + This driver is for USB parallel port adapters that use the Lucent + Technologies USS-720 chip. These adapters provide USB compatibility + to peripherals designed with parallel port interfaces. + + The chip has two modes: automatic mode and manual mode. In automatic + mode, it looks to the computer like a standard USB printer. Only + printers may be connected to the USS-720 in this mode. The generic + USB printer driver ("USB Printer support", above) may be used in + that mode, and you can say N here if you want to use the chip only + in this mode. + + Manual mode is not limited to printers, any parallel port + device should work. This driver utilizes manual mode. + Note however that some operations are three orders of a magnitude + slower than on a PCI/ISA Parallel Port, so timing critical + applications might not work. + + Say Y here if you own an USS-720 USB->Parport cable and intend to + connect anything other than a printer to it. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called uss720.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +USB /proc filesystem entry support (Preliminary) +CONFIG_USB_PROC + This reports USB drivers and devices in the /proc filesystem. + Entries are located in /proc/bus/usb. The entries are described in + the file Documentation/proc_usb_info.txt. + + Note that you must say Y to "/proc filesystem support" below for + this to work. + +ACPI support +CONFIG_ACPI + Advanced Configuration and Power Interface (ACPI) is an interface + specification to support power management of peripherals. If your + system supports it, say Y here. + +Minix fs support +CONFIG_MINIX_FS + Minix is a simple operating system used in many classes about OS's. + The minix filesystem (method to organize files on a hard disk + partition or a floppy disk) was the original filesystem for Linux, + but has been superseded by the second extended filesystem ext2fs. + You don't want to use the minix filesystem on your hard disk because + of certain built-in restrictions, but it is sometimes found on older + Linux floppy disks. This option will enlarge your kernel by about + 28 kB. If unsure, say N. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called minix.o. Note that the filesystem of your root partition (the + one containing the directory /) cannot be compiled as a module. + +Second extended fs support +CONFIG_EXT2_FS + This is the de facto standard Linux filesystem (method to organize + files on a storage device) for hard disks. + + You want to say Y here, unless you intend to use Linux exclusively + from inside a DOS partition using the umsdos filesystem. The + advantage of the latter is that you can get away without + repartitioning your hard drive (which often implies backing + everything up and restoring afterwards); the disadvantage is that + Linux becomes susceptible to DOS viruses and that umsdos is somewhat + slower than ext2fs. Even if you want to run Linux in this fashion, + it might be a good idea to have ext2fs around: it enables you to + read more floppy disks and facilitates the transition to a *real* + Linux partition later. Another (rare) case which doesn't require + ext2fs is a diskless Linux box which mounts all files over the + network using NFS (in this case it's sufficient to say Y to "NFS + filesystem support" below). Saying Y here will enlarge your kernel + by about 44 kB. + + The Ext2fs-Undeletion mini-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , gives information about + how to retrieve deleted files on ext2fs filesystems. + + To change the behavior of ext2 filesystems, you can use the tune2fs + utility ("man tune2fs"). To modify attributes of files and + directories on ext2 filesystems, use chattr ("man chattr"). + + Ext2fs partitions can be read from within DOS using the ext2tool + command line tool package (available via FTP (user: anonymous) from + ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2 ) and from + within Windows NT using the ext2nt command line tool package from + ftp://metalab.unc.edu/pub/Linux/utils/dos . Explore2fs is a graphical + explorer for ext2fs partitions which runs on Windows 95 and Windows + NT and includes experimental write support; it is available from + http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm . + + If you want to compile this filesystem as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read Documentation/modules.txt. The module + will be called ext2.o. Be aware however that the filesystem of your + root partition (the one containing the directory /) cannot be + compiled as a module, and so this could be dangerous. Most everyone + wants to say Y here. + +SCO UnixWare BFS Support +CONFIG_BFS_FS + Boot Filesystem (BFS) is a filesystem used under SCO UnixWare to + allow bootloader access the kernel image and other important files + during the boot process. It is usually mounted under /stand and + corresponds to the slice marked as "STAND" in the UnixWare + partition. This is useful if you want to access files on your /stand + slice from Linux. More information on this filesystem can be found in + Documentation/filesystems/bfs.txt file. If you do not know what it is, + say N. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called bfs.o. Note that the filesystem of your root partition (the + one containing the directory /) cannot be compiled as a module. + +ISO 9660 CDROM filesystem support +CONFIG_ISO9660_FS + This is the standard filesystem used on CDROMs. It was previously + known as "High Sierra Filesystem" and is called "hsfs" on other Unix + systems. The so-called Rock-Ridge extensions which allow for long + Unix filenames and symbolic links are also supported by this driver. + If you have a CDROM drive and want to do more with it than just + listen to audio CDs and watch its LEDs, say Y (and read + Documentation/filesystems/isofs.txt and the CDROM-HOWTO, available + from http://metalab.unc.edu/mdw/linux.html#howto ), thereby + enlarging your kernel by about 27 KB; otherwise say N. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called isofs.o. + +Microsoft Joliet CDROM extensions +CONFIG_JOLIET + Joliet is a Microsoft extension for the ISO 9660 CDROM filesystem + which allows for long filenames in unicode format (unicode is the + new 16 bit character code, successor to ASCII, which encodes the + characters of almost all languages of the world; see + http://www.unicode.org for more information). Say Y here if you want + to be able to read Joliet CDROMs under Linux. + +UDF Filesystem support (read only) +CONFIG_UDF_FS + This is the new filesystem used by some CDROMS and DVD drivers. Say + Y if you intend to mount DVD discs or CDRW's written in packet mode, + or if written to by other UDF utilities, such as DirectCD. Please + read Documentation/filesystems/udf.txt. + + This filesystem support is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module is called udf.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If unsure, say N. + +UDF write support (DANGEROUS) +CONFIG_UDF_RW + Say Y if you want to test write support for UDF filesystems. + Due to lack of support for writing to CDR/CDRW's, this option + is only supported for Hard Discs, DVD-RAM, and loopback files. + +DOS FAT fs support +CONFIG_FAT_FS + If you want to use one of the FAT-based filesystems (the MS-DOS, + VFAT (Windows 95) and UMSDOS (used to run Linux on top of an + ordinary DOS partition) filesystems), then you must say Y or M here + to include FAT support. You will then be able to mount partitions or + diskettes with FAT-based filesystems and transparently access the + files on them, i.e. MSDOS files will look and behave just like all + other Unix files. + + This FAT support is not a filesystem in itself, it only provides the + foundation for the other filesystems. You will have to say Y or M to + at least one of "msdos fs support" or "vfat fs support" in order to + make use of it. + + Another way to read and write MSDOS floppies and hard drive + partitions from within Linux (but not transparently) is with the + mtools ("man mtools") program suite. This doesn't require the FAT + filesystem support. + + It is now also becoming possible to read and write compressed FAT + filesystems; read Documentation/filesystems/fat_cvf.txt for details. + + The FAT support will enlarge your kernel by about 37 KB. If unsure, + say Y. + + If you want to compile this as a module however ( = code which can + be inserted in and removed from the running kernel whenever you + want), say M here and read Documentation/modules.txt. The module + will be called fat.o. Note that if you compile the FAT support as a + module, you cannot compile any of the FAT-based filesystems into the + kernel -- they will have to be modules as well. The filesystem of + your root partition (the one containing the directory /) cannot be a + module, so don't say M here if you intend to use UMSDOS as your root + filesystem. + +MSDOS fs support +CONFIG_MSDOS_FS + This allows you to mount MSDOS partitions of your hard drive (unless + they are compressed; to access compressed MSDOS partitions under + Linux, you can either use the DOS emulator DOSEMU, described in the + DOSEMU-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , or try dmsdosfs in + ftp://metalab.unc.edu/pub/Linux/system/filesystems/dosfs . If you + intend to use dosemu with a non-compressed MSDOS partition, say Y + here) and MSDOS floppies. This means that file access becomes + transparent, i.e. the MSDOS files look and behave just like all + other Unix files. + + If you want to use umsdos, the Unix-like filesystem on top of DOS, + which allows you to run Linux from within a DOS partition without + repartitioning, you'll have to say Y or M here. + + If you have Windows 95 or Windows NT installed on your MSDOS + partitions, you should use the VFAT filesystem (say Y to "vfat fs + support" below), or you will not be able to see the long filenames + generated by Windows 95 / Windows NT. + + This option will enlarge your kernel by about 7 KB. If unsure, + answer Y. This will only work if you said Y to "fat fs support" as + well. If you want to compile this as a module however ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read Documentation/modules.txt. The module + will be called msdos.o. + +VFAT (Windows-95) fs support +CONFIG_VFAT_FS + This option provides support for normal Windows filesystems with + long filenames. That includes non-compressed FAT-based filesystems + used by Windows 95, Windows 98, Windows NT 4.0, and mtools. + + You cannot use the VFAT filesystem for your Linux root partition + (the one containing the directory /); use UMSDOS instead if you + want to run Linux from within a DOS partition (i.e. say Y to + "umsdos: Unix like fs on top of std MSDOS fs", below). + + The VFAT support enlarges your kernel by about 10 KB and it only + works if you said Y to the "fat fs support" above. Please read the + file Documentation/filesystems/vfat.txt for details. If unsure, + say Y. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called vfat.o. + +UMSDOS: Unix-like filesystem on top of standard MSDOS filesystem +CONFIG_UMSDOS_FS + Say Y here if you want to run Linux from within an existing DOS + partition of your hard drive. The advantage of this is that you can + get away without repartitioning your hard drive (which often implies + backing everything up and restoring afterwards) and hence you're + able to quickly try out Linux or show it to your friends; the + disadvantage is that Linux becomes susceptible to DOS viruses and + that UMSDOS is somewhat slower than ext2fs. Another use of UMSDOS + is to write files with long unix filenames to MSDOS floppies; it + also allows Unix-style softlinks and owner/permissions of files on + MSDOS floppies. You will need a program called umssync in order to + make use of umsdos; read Documentation/filesystems/umsdos.txt. + + This option enlarges your kernel by about 28 KB and it only works if + you said Y to both "fat fs support" and "msdos fs support" above. If + you want to compile this as a module ( = code which can be inserted + in and removed from the running kernel whenever you want), say M + here and read Documentation/modules.txt. The module will be called + umsdos.o. Note that the filesystem of your root partition (the one + containing the directory /) cannot be a module, so saying M could be + dangerous. If unsure, say N. + +/proc filesystem support +CONFIG_PROC_FS + This is a virtual filesystem providing information about the status + of the system. "Virtual" means that it doesn't take up any space on + your hard disk: the files are created on the fly by the kernel when + you try to access them. Also, you cannot read the files with older + version of the program less: you need to use more or cat. + + It's totally cool; for example, "cat /proc/interrupts" gives + information about what the different IRQs are used for at the moment + (there is a small number of Interrupt ReQuest lines in your computer + that are used by the attached devices to gain the CPU's attention -- + often a source of trouble if two devices are mistakenly configured + to use the same IRQ). + + The /proc filesystem is explained in the file + Documentation/filesystems/proc.txt and on the proc(5) manpage ("man + 5 proc"). + + This option will enlarge your kernel by about 67 KB. Several + programs depend on this, so everyone should say Y here. + +NFS filesystem support +CONFIG_NFS_FS + If you are connected to some other (usually local) Unix computer + (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing + on that computer (the NFS server) using the Network File Sharing + protocol, say Y. "Mounting files" means that the client can access + the files with usual UNIX commands as if they were sitting on the + client's hard disk. For this to work, the server must run the + programs nfsd and mountd (but does not need to have NFS filesystem + support enabled in its kernel). NFS is explained in the Network + Administrator's Guide, available from + http://metalab.unc.edu/mdw/linux.html#guide , on its man page: "man + nfs", and in the NFS-HOWTO. + + A superior but less widely used alternative to NFS is provided by + the Coda filesystem; see "Coda filesystem support" below. + + If you say Y here, you should have said Y to TCP/IP networking also. + This option would enlarge your kernel by about 27 KB. + + This filesystem is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called nfs.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. + + If you are configuring a diskless machine which will mount its root + filesystem over NFS at boot time, say Y here and to "IP: kernel + level autoconfiguration" above and to "Root file system on NFS" + below. You cannot compile this driver as a module in this case. + There are two packages designed for booting diskless machines over + the net: netboot and etherboot, both available via FTP from + ftp://metalab.unc.edu/pub/Linux/system/boot/ethernet/ . + + If you don't know what all this is about, say N. + +Root file system on NFS +CONFIG_ROOT_NFS + If you want your Linux box to mount its whole root filesystem (the + one containing the directory /) from some other computer over the + net via NFS (presumably because your box doesn't have a hard disk), + say Y. Read Documentation/nfsroot.txt for details. It is likely that + in this case, you also want to say Y to "IP: kernel level + autoconfiguration" so that your box can discover its network address + at boot time. + + Most people say N here. + +NFS server support (EXPERIMENTAL) +CONFIG_NFSD + If you want your Linux box to act as a NFS *server*, so that other + computers on your local network which support NFS can access certain + directories on your box transparently, you have two options: you can + use the self-contained user space program nfsd, in which case you + should say N here, or you can say Y and use this new experimental + kernel based NFS server. The advantage of the kernel based solution + is that it is faster; it might not be completely stable yet, though. + + In either case, you will need support software; the respective + locations are given in the file Documentation/Changes in the NFS + section. + + Please read the NFS-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + The NFS server is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called nfsd.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. If unsure, say N. + +Emulate SUN NFS server +CONFIG_NFSD_SUN + If you would like for the server to allow clients to access + directories that are mount points on the local filesystem (this is + how nfsd behaves on Sun systems), say Y here. If unsure, say N. + +OS/2 HPFS filesystem support +CONFIG_HPFS_FS + OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS + is the filesystem used for organizing files on OS/2 hard disk + partitions. Say Y if you want to be able to read files from an OS/2 + HPFS partition of your hard drive. OS/2 floppies however are in + regular MSDOS format, so you don't need this option in order to be + able to read them. Read Documentation/filesystems/hpfs.txt. + + This filesystem is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called hpfs.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. If unsure, say N. + +Windows NT NTFS support (read only) +CONFIG_NTFS_FS + NTFS is the file system of Microsoft Windows NT. Say Y if you want + to get read access to files on NTFS partitions of your hard drive. + The Linux NTFS driver supports most of the mount options of the VFAT + driver, see Documentation/filesystems/ntfs.txt. Saying Y here will + give you read-only access to NTFS partitions. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ntfs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +NTFS write support (DANGEROUS) +CONFIG_NTFS_RW + If you say Y here, you will (hopefully) be able to write to NTFS + file systems as well as read from them. The read-write support + in NTFS is far from being complete and is not well tested. If you + enable this, back up your NTFS volume first since it may get + damaged. + + If unsure, say N. + +System V and Coherent filesystem support (read only) +CONFIG_SYSV_FS + SCO, Xenix and Coherent are commercial Unix systems for Intel + machines. Saying Y here would allow you to read from their floppies + and hard disk partitions. + + If you have floppies or hard disk partitions like that, it is likely + that they contain binaries from those other Unix systems; in order + to run these binaries, you will want to install iBCS2 (Intel Binary + Compatibility Standard is a kernel module which lets you run SCO, + Xenix, Wyse, UnixWare, Dell Unix and System V programs under Linux + and is often needed to run commercial software that's only available + for those systems. It's available via FTP (user: anonymous) from + ftp://tsx-11.mit.edu/pub/linux/BETA ). + + If you only intend to mount files from some other Unix over the + network using NFS, you don't need the System V filesystem support + (but you need NFS filesystem support obviously). + + Note that this option is generally not needed for floppies, since a + good portable way to transport files and directories between unixes + (and even other operating systems) is given by the tar program ("man + tar" or preferably "info tar"). Note also that this option has + nothing whatsoever to do with the option "System V IPC". Read about + the System V filesystem in Documentation/filesystems/sysv-fs.txt. + Saying Y here will enlarge your kernel by about 27 kB. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called sysv.o. + + If you haven't heard about all of this before, it's safe to say N. + +SYSV filesystem write support (DANGEROUS) +CONFIG_SYSV_FS_WRITE + If you say Y here, you will (hopefully) be able to write to System V + and Coherent file systems as well as read from them. The read-write + support in SYSV is not well tested yet. If you enable this, back up + your SYSV/Coherent volumes first since they may get damaged. + + If unsure, say N. + +Amiga FFS filesystem support +CONFIG_AFFS_FS + The Fast File System (FFS) is the common filesystem used on hard + disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y + if you want to be able to read and write files from and to an Amiga + FFS partition on your hard drive. Amiga floppies however cannot be + read with this driver due to an incompatibility of the floppy + controller used in an Amiga and the standard floppy controller in + PCs and workstations. Read Documentation/filesystems/affs.txt and + fs/affs/Changes. + + With this driver you can also mount disk files used by Bernd + Schmidt's Un*X Amiga Emulator (http://www.freiburg.linux.de/~uae/ ). + If you want to do this, you will also need to say Y or M to "Loop + device support", above. + + This filesystem is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called affs.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. If unsure, say N. + +Apple Macintosh filesystem support (EXPERIMENTAL) +CONFIG_HFS_FS + If you say Y here, you will be able to mount Macintosh-formatted + floppy disks and hard drive partitions with full read-write access. + Please read fs/hfs/HFS.txt to learn about the available mount + options. + + This filesystem support is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module is called hfs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +ROM filesystem support +CONFIG_ROMFS_FS + This is a very small read-only filesystem mainly intended for + initial ram disks of installation disks, but it could be used for + other read-only media as well. Read + Documentation/filesystems/romfs.txt for details. + + This filesystem support is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module is called romfs.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If you don't know whether you need it, then you don't need it: + answer N. + +QNX filesystem support (read only) (EXPERIMENTAL) +CONFIG_QNX4FS_FS + This is the filesystem used by the operating system QNX 4. Say Y if + you intend to mount QNX hard disks or floppies. Unless you say Y to + "QNXFS read-write support" below, you will only be able to read + these filesystems. + + This filesystem support is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module is called qnx4.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If unsure, say N. + +QNXFS write support (DANGEROUS) +CONFIG_QNX4FS_RW + Say Y if you want to test write support for QNX filesystems. + +Kernel automounter support +CONFIG_AUTOFS_FS + The automounter is a tool to automatically mount remote filesystems + on demand. This implementation is partially kernel-based to reduce + overhead in the already-mounted case; this is unlike the BSD + automounter (amd), which is a pure user space daemon. + + To use the automounter you need the user-space tools from + ftp://ftp.kernel.org/pub/linux/daemons/autofs ; you also want to + answer Y to "NFS filesystem support", below. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called autofs.o. + + If you are not a part of a fairly large, distributed network, you + probably do not need an automounter, and can say N here. + +EFS filesystem support (read only) (EXPERIMENTAL) +CONFIG_EFS_FS + EFS is an older filesystem used for non-ISO9660 CDROMs and hard disk + partitions by SGI's IRIX operating system (IRIX 6.0 and newer uses + the XFS filesystem for hard disk partitions however). + + This implementation only offers read-only access. If you don't know + what all this is about, it's safe to say N. For more information + about EFS see its home page at http://aeschi.ch.eu.org/efs/ . + + If you want to compile the EFS filesystem support as a module ( = + code which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt. + The module will be called efs.o. + +SGI disklabel support +CONFIG_SGI_DISKLABEL + Say Y to this only if you plan on mounting disks with SGI + disklabels. This is not required to mount EFS-format CDROMs. + +UFS filesystem support (read only) +CONFIG_UFS_FS + BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD, + OpenBSD and NeXTstep) use a filesystem called UFS. Some System V + Unixes can create and mount hard disk partitions and diskettes using + this filesystem as well. Saying Y here will allow you to read from + these partitions; if you also want to write to them, say Y to the + experimental "UFS filesystem write support", below. Please read the + file Documentation/filesystems/ufs.txt for more information. + + If you only intend to mount files from some other Unix over the + network using NFS, you don't need the UFS filesystem support (but + you need NFS filesystem support obviously). + + Note that this option is generally not needed for floppies, since a + good portable way to transport files and directories between unixes + (and even other operating systems) is given by the tar program ("man + tar" or preferably "info tar"). + + When accessing NeXTstep files, you may need to convert them from the + NeXT character set to the Latin1 character set; use the program + recode ("info recode") for this purpose. + + If you want to compile the UFS filesystem support as a module ( = + code which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt. + The module will be called ufs.o. + + If you haven't heard about all of this before, it's safe to say N. + +UFS filesystem write support (DANGEROUS) +CONFIG_UFS_FS_WRITE + Say Y here if you want to try writing to UFS partitions. This is + experimental, so you should back up your UFS partitions beforehand. + +Advanced partition selection +CONFIG_PARTITION_ADVANCED + Say Y here if you would like to use hard disks under Linux which + were partitioned under an operating system running on a different + architecture than your Linux system. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about foreign partitioning schemes. If unsure, say N. + +Alpha OSF partition support +CONFIG_OSF_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned on an Alpha machine. + +Macintosh partition map support +CONFIG_MAC_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned on a Macintosh. + +PC BIOS (MSDOS partition tables) support +CONFIG_MSDOS_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned on an x86 PC (not necessarily by DOS). + +BSD disklabel (FreeBSD partition tables) support +CONFIG_BSD_DISKLABEL + FreeBSD uses its own hard disk partition scheme on your PC. It + requires only one entry in the primary partition table of your disk + and manages it similarly to DOS extended partitions, putting in its + first sector a new partition table in BSD disklabel format. Saying Y + here allows you to read these disklabels and further mount FreeBSD + partitions from within Linux if you have also said Y to "UFS + filesystem support", above. If you don't know what all this is + about, say N. + +Sun partition tables support +CONFIG_SUN_PARTITION + Like most systems, SunOS uses its own hard disk partition table + format, incompatible with all others. Saying Y here allows you to + read these partition tables and further mount SunOS partitions from + within Linux if you have also said Y to "UFS filesystem support", + above. This is mainly used to carry data from a SPARC under SunOS to + your Linux box via a removable medium like magneto-optical or ZIP + drives; note however that a good portable way to transport files and + directories between unixes (and even other operating systems) is + given by the tar program ("man tar" or preferably "info tar"). If + you don't know what all this is about, say N. + +Solaris (x86) partition table support +CONFIG_SOLARIS_X86_PARTITION + Like most systems, Solaris x86 uses its own hard disk partition + table format, incompatible with all others. Saying Y here allows you + to read these partition tables and further mount Solaris x86 + partitions from within Linux if you have also said Y to "UFS + filesystem support", above. + +SGI partition support +CONFIG_SGI_PARTITION + Say Y here if you would like to be able to read the hard disk + partition table format used by SGI machines. + +ADFS filesystem support (read only) (EXPERIMENTAL) +CONFIG_ADFS_FS + The Acorn Disc Filing System is the standard filesystem of the + RiscOS operating system which runs on Acorn's ARM-based Risc PC + systems and the Acorn Archimedes range of machines. If you say Y + here, Linux will be able to read from ADFS partitions on hard drives + and from ADFS-formatted floppy discs. + + The ADFS partition should be the first partition (i.e., + /dev/[hs]d?1) on each of your drives. Please read the file + Documentation/filesystems/adfs.txt for further details. + + This code is also available as a module called adfs.o ( = code which + can be inserted in and removed from the running kernel whenever you + want). If you want to compile it as a module, say M here and read + Documentation/modules.txt. + + If unsure, say N. + +/dev/pts filesystem for Unix98 PTYs +CONFIG_DEVPTS_FS + You should say Y here if you said Y to "Unix98 PTY support" above. + You'll then get a virtual filesystem which can be mounted on + /dev/pts with "mount -t devpts". This, together with the pseudo + terminal master multiplexer /dev/ptmx, is used for pseudo terminal + support as described in The Open Group's Unix98 standard: in order + to acquire a pseudo terminal, a process opens /dev/ptmx; the number + of the pseudo terminal is then made available to the process and the + pseudo terminal slave can be accessed as /dev/pts/. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + The GNU C library glibc 2.1 contains the requisite support for this + mode of operation; you also need client programs that use the Unix98 + API. + +UnixWare slices support (EXPERIMENTAL) +CONFIG_UNIXWARE_DISKLABEL + Like some systems, UnixWare uses its own slice table inside a + partition (VTOC - Virtual Table of Contents). Its format is + incompatible with all other OSes. Saying Y here allows you to read + VTOC and further mount UnixWare partitions read-only from within + Linux if you have also said Y to "UFS filesystem support" or "System + V and Coherent filesystem support", above. + + This is mainly used to carry data from a UnixWare box to your + Linux box via a removable medium like magneto-optical, ZIP or + removable IDE drives. Note, however, that a good portable way to + transport files and directories between unixes (and even other + operating systems) is given by the tar program ("man tar" or + preferably "info tar"). + + If you don't know what all this is about, say N. + +SMB filesystem support (to mount Windows shares etc.) +CONFIG_SMB_FS + SMB (Server Message Block) is the protocol Windows for Workgroups + (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share + files and printers over local networks. Saying Y here allows you to + mount their filesystems (often called "shares" in this context) and + access them just like any other Unix directory. Currently, this + works only if the Windows machines use TCP/IP as the underlying + transport protocol, and not NetBEUI. For details, read + Documentation/filesystems/smbfs.txt and the SMB-HOWTO, available + from http://metalab.unc.edu/mdw/linux.html#howto . + + Note: if you just want your box to act as an SMB *server* and make + files and printing services available to Windows clients (which need + to have a TCP/IP stack), you don't need to say Y here; you can use + the program samba (available via FTP (user: anonymous) in + ftp://metalab.unc.edu/pub/Linux/system/network/samba ) for that. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at http://www.eats.com/linux_mac_win.html . + + If you want to compile the SMB support as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read Documentation/modules.txt. The module + will be called smbfs.o. Most people say N, however. + +Coda filesystem support (advanced network fs) +CONFIG_CODA_FS + Coda is an advanced network filesystem, similar to NFS in that it + enables you to mount filesystems of a remote server and access them + with regular Unix commands as if they were sitting on your hard + disk. Coda has several advantages over NFS: support for disconnected + operation (e.g. for laptops), read/write server replication, + security model for authentication and encryption, persistent client + caches and write back caching. + + If you say Y here, your Linux box will be able to act as a Coda + *client*. You will need user level code as well, both for the client + and server. Servers are currently user level, i.e. need no kernel + support. Please read Documentation/filesystems/coda.txt and check + out the Coda home page http://www.coda.cs.cmu.edu . + + If you want to compile the coda client support as a module ( = code + which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt. + The module will be called coda.o. + +NCP filesystem support (to mount NetWare volumes) +CONFIG_NCP_FS + NCP (NetWare Core Protocol) is a protocol that runs over IPX and is + used by Novell NetWare clients to talk to file servers. It is to IPX + what NFS is to TCP/IP, if that helps. Saying Y here allows you to + mount NetWare file server volumes and to access them just like any + other Unix directory. For details, please read the file + Documentation/filesystems/ncpfs.txt in the kernel source and the + IPX-HOWTO from http://metalab.unc.edu/mdw/linux.html#howto . + + You do not have to say Y here if you want your Linux box to act as a + file *server* for Novell NetWare clients. + + General information about how to connect Linux, Windows machines and + Macs is on the WWW at http://www.eats.com/linux_mac_win.html . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ncpfs.o. Say N unless you are connected to a Novell network. + +Packet signatures +CONFIG_NCPFS_PACKET_SIGNING + NCP allows packets to be signed for stronger security. If you want + security, say Y. Normal users can leave it off. To be able to use + packet signing you must use ncpfs > 2.0.12. + +Proprietary file locking +CONFIG_NCPFS_IOCTL_LOCKING + Allows locking of records on remote volumes. Say N unless you have + special applications which are able to utilize this locking scheme. + +Clear remove/delete inhibit when needed +CONFIG_NCPFS_STRONG + Allows manipulation of files flagged as Delete or Rename Inhibit. To + use this feature you must mount volumes with the ncpmount parameter + "-s" (ncpfs-2.0.12 and newer). Say Y unless you are not mounting + volumes with -f 444. + +Use NFS namespace when available +CONFIG_NCPFS_NFS_NS + Allows you to utilize NFS namespace on NetWare servers. It brings + you case sensitive filenames. Say Y. You can disable it at + mount-time with the `-N nfs' parameter of ncpmount. + +Use OS2/LONG namespace when available +CONFIG_NCPFS_OS2_NS + Allows you to utilize OS2/LONG namespace on NetWare servers. + Filenames in this namespace are limited to 255 characters, they are + case insensitive, and case in names is preserved. Say Y. You can + disable it at mount time with the -N os2 parameter of ncpmount. + +Lowercase DOS filenames on LONG namespace volume +CONFIG_NCPFS_SMALLDOS + If you say Y here, every filename on a NetWare server volume using + the OS2/LONG namespace will be converted to lowercase characters. + (For regular NetWare file server volumes with DOS namespace, this is + done automatically, even if you say N here.) Saying N here will give + you these filenames in uppercase. + + This is only a cosmetic option since the OS2/LONG namespace is case + insensitive. The only major reason for this option is backward + compatibility when moving from DOS to OS2/LONG namespace support. + Long filenames (created by Win95) will not be affected. + + This option does not solve the problem that filenames appear + differently under Linux and under Windows, since Windows does an + additional conversions on the client side. You can achieve similar + effects by saying Y to "Allow using of Native Language Support" + below. + +Allow mounting of volume subdirectories +CONFIG_NCPFS_MOUNT_SUBDIR + Allows you to mount not only whole servers or whole volumes, but + also subdirectories from a volume. It can be used to reexport data + and so on. There is no reason to say N, so Y is recommended unless + you count every byte. + + To utilize this feature you must use ncpfs-2.0.12 or newer. + +NDS interserver authentication domains +CONFIG_NCPFS_NDS_DOMAINS + This allows storing NDS private keys in kernel space where they + can be used to authenticate another server as interserver NDS + accesses need it. You must use ncpfs-2.0.12.1 or newer to utilize + this feature. Say Y if you are using NDS connections to NetWare + servers. Do not say Y if security is primary for you because root + can read your session key (from /proc/kcore). + +Allow using of Native Language Support +CONFIG_NCPFS_NLS + Allows you to use codepages and I/O charsets for file name + translation between the server file system and input/output. This + may be useful, if you want to access the server with other operating + systems, e.g. Windows 95. See also NLS for more Information. + + To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer. + +Symbolic links and mode permission bits +CONFIG_NCPFS_EXTRAS + This enables the use of symbolic links and an execute permission + bit on NCPFS. The file server need not have long name space or NFS + name space loaded for these to work. + + To use the new attributes, it is recommended to use the flags + '-f 600 -d 755' on the ncpmount command line. + +nls codepage 437 +CONFIG_NLS_CODEPAGE_437 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored + in so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage that is used in + the United States and parts of Canada. This is recommended. + +nls codepage 737 +CONFIG_NLS_CODEPAGE_737 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored + in so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage that is used for + Greek. If unsure, say N. + +nls codepage 775 +CONFIG_NLS_CODEPAGE_775 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored + in so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage that is used + for the Baltic Rim Languages. If unsure, say N. + +nls codepage 850 +CONFIG_NLS_CODEPAGE_850 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage that is used for + much of Europe -- United Kingdom, Germany, Spain, Italy, and [add + more countries here]. It has some characters useful to many European + languages that are not part of the US codepage 437. + + If unsure, say Y. + +nls codepage 852 +CONFIG_NLS_CODEPAGE_852 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the Latin 2 codepage used by DOS + for much of Central and Eastern Europe. It has all the required + characters for these languages: Albanian, Croatian, Czech, English, + Finnish, Hungarian, Irish, German, Polish, Romanian, Serbian (Latin + transcription), Slovak, Slovenian, and Sorbian. + +nls codepage 855 +CONFIG_NLS_CODEPAGE_855 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Cyrillic. + +nls codepage 857 +CONFIG_NLS_CODEPAGE_857 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Turkish. + +nls codepage 860 +CONFIG_NLS_CODEPAGE_860 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Portuguese. + +nls codepage 861 +CONFIG_NLS_CODEPAGE_861 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Icelandic. + +nls codepage 862 +CONFIG_NLS_CODEPAGE_862 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Hebrew. + +nls codepage 863 +CONFIG_NLS_CODEPAGE_863 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Canadian + French. + +nls codepage 864 +CONFIG_NLS_CODEPAGE_864 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Arabic. + +nls codepage 865 +CONFIG_NLS_CODEPAGE_865 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for the Nordic + European countries. + +nls codepage 866 +CONFIG_NLS_CODEPAGE_866 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for + Cyrillic/Russian. + +nls codepage 869 +CONFIG_NLS_CODEPAGE_869 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Greek. +### +### Why do we have two codepages for Greek and Cyrillic? +### + +nls codepage 874 +CONFIG_NLS_CODEPAGE_874 + The Microsoft fat filesystem family can deal with filenames in + native language character sets. These character sets are stored in + so-called DOS codepages. You need to include the appropriate + codepage if you want to be able to read/write these filenames on + DOS/Windows partitions correctly. This does apply to the filenames + only, not to the file contents. You can include several codepages; + say Y here if you want to include the DOS codepage for Thai. + +nls iso8859-1 +CONFIG_NLS_ISO8859_1 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 1 character + set, which covers most West European languages such as Albanian, + Catalan, Danish, Dutch, English, Faeroese, Finnish, French, German, + Galician, Irish, Icelandic, Italian, Norwegian, Portuguese, Spanish, + and Swedish. It is also the default for the US. If unsure, say Y. + +nls iso8859-2 +CONFIG_NLS_ISO8859_2 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 2 character + set, which works for most Latin-written Slavic and Central European + languages: Czech, German, Hungarian, Polish, Rumanian, Croatian, + Slovak, Slovene. + +nls iso8859-3 +CONFIG_NLS_ISO8859_3 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 3 character + set, which is popular with authors of Esperanto, Galician, Maltese, + and Turkish. + +nls iso8859-4 +CONFIG_NLS_ISO8859_4 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 4 character + set which introduces letters for Estonian, Latvian, and + Lithuanian. It is an incomplete predecessor of Latin 6. + +nls iso8859-5 +CONFIG_NLS_ISO8859_5 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for ISO8859-5, a Cyrillic + character set with which you can type Bulgarian, Byelorussian, + Macedonian, Russian, Serbian, and Ukrainian. Note that the charset + KOI8-R is preferred in Russia. + +nls iso8859-6 +CONFIG_NLS_ISO8859_6 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for ISO8859-6, the Arabic + character set. + +nls iso8859-7 +CONFIG_NLS_ISO8859_7 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for ISO8859-7, the Modern + Greek character set. + +nls iso8859-8 +CONFIG_NLS_ISO8859_8 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for ISO8859-8, the Hebrew + character set. + +nls iso8859-9 +CONFIG_NLS_ISO8859_9 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 5 character + set, and it replaces the rarely needed Icelandic letters in Latin 1 + with the Turkish ones. Useful in Turkey. + +nls iso8859-10 +CONFIG_NLS_ISO8859_10 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 6 character + set, which adds the last Inuit (Greenlandic) and Sami (Lappish) + letters that were missing in Latin 4 to cover the entire Nordic + area. + +NLS ISO 8859-14 (Latin 8; Celtic) +CONFIG_NLS_ISO8859_14 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 8 character + set, which adds the last accented vowels for Welsh (and Manx Gaelic) + that were missing in Latin 1. http://linux.speech.cymru.org/ + has further information. + +nls iso8859-15 +CONFIG_NLS_ISO8859_15 + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the Latin 9 character + set, which covers most West European languages such as Albanian, + Catalan, Danish, Dutch, English, Estonian, Faeroese, Finnish, + French, German, Galician, Irish, Icelandic, Italian, Norwegian, + Portuguese, Spanish, and Swedish. Latin 9 is an update to + Latin 1 (ISO 8859-1) that removes a handful of rarely used + characters and instead adds support for Estonian, corrects the + support for French and Finnish, and adds the new Euro character. If + unsure, say Y. + +nls koi8-r +CONFIG_NLS_KOI8_R + If you want to display filenames with native language characters + from the Microsoft fat filesystem family or from JOLIET CDROMs + correctly on the screen, you need to include the appropriate + input/output character sets. Say Y here for the preferred Russian + character set. + +Virtual terminal +CONFIG_VT + If you say Y here, you will get support for terminal devices with + display and keyboard devices. These are called "virtual" because you + can run several virtual terminals (also called virtual consoles) on + one physical terminal. This is rather useful, for example one + virtual terminal can collect system messages and warnings, another + one can be used for a text-mode user session, and a third could run + an X session, all in parallel. Switching between virtual terminals + is done with certain key combinations, usually Alt-. + + The setterm command ("man setterm") can be used to change the + properties (such as colors) of a virtual terminal. + + You need at least one virtual terminal device in order to make use + of your keyboard and monitor. Therefore, only people configuring an + embedded system would want to say N here in order to save some + memory; the only way to log into such a system is then via a serial + or network connection. + + If unsure, say Y, or else you won't be able to do much with your new + shiny Linux system :-) + +Support for console on virtual terminal +CONFIG_VT_CONSOLE + The system console is the device which receives all kernel messages + and warnings and which allows logins in single user mode. If you + answer Y here, a virtual terminal (the device used to interact with + a physical terminal) can be used as system console. This is the most + common mode of operations, so you should say Y here unless you want + the kernel messages be output only to a serial port (in which case + you should say Y to "Console on serial port", below). + + If you do say Y here, by default the currently visible virtual + terminal (/dev/tty0) will be used as system console. You can change + that with a kernel command line option such as "console=tty3" which + would use the third virtual terminal as system console. (Try "man + bootparam" or see the documentation of your boot loader (lilo or + loadlin) about how to pass options to the kernel at boot time. The + lilo procedure is also explained in the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto .) + + If unsure, say Y. + +Software generated cursor +CONFIG_SOFTCURSOR + If you say Y here, you'll be able to do lots of nice things with the + cursors of your virtual consoles -- for example turn them into + non-blinking block cursors which are more visible on laptop screens, + or change their colors depending on the virtual console they're on. + See Documentation/VGA-softcursor.txt for more information. + +Support for PowerMac keyboard +CONFIG_MAC_KEYBOARD + This option allows you to use an ADB keyboard attached to your + machine. Note that this disables any other (ie. PS/2) keyboard + support, even if your machine is physically capable of using both at + the same time. + + If you use an ADB keyboard (4 pin connector), say Y here. + If you use a PS/2 keyboard (6 pin connector), say N here. + +Standard/generic serial support +CONFIG_SERIAL + This selects whether you want to include the driver for the standard + serial ports. The standard answer is Y. People who might say N here + are those that are setting up dedicated Ethernet WWW/FTP servers, or + users that have one of the various bus mice instead of a serial + mouse and don't intend to use their machine's standard serial port + for anything. (Note that the Cyclades and Stallion multi serial port + drivers do not need this driver built in for them to work.) + + If you want to compile this driver as a module, say M here and read + Documentation/modules.txt. The module will be called serial.o. + [WARNING: Do not compile this driver as a module if you are using + non-standard serial ports, since the configuration information will + be lost when the driver is unloaded. This limitation may be lifted + in the future.] + + BTW1: If you have a mouseman serial mouse which is not recognized by + the X window system, try running gpm first. + + BTW2: If you intend to use a software modem (also called Winmodem) + under Linux, forget it. These modems are crippled and require + proprietary drivers which are only available under Windows. + + Most people will say Y or M here, so that they can use serial mice, + modems and similar devices connecting to the standard serial ports. + +Support for console on serial port +CONFIG_SERIAL_CONSOLE + If you say Y here, it will be possible to use a serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). This could be useful if some terminal or printer is connected + to that serial port. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyS1". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time. The lilo procedure is also explained in the + SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto .) + + If you don't have a VGA card installed and you say Y here, the + kernel will automatically use the first serial line, /dev/ttyS0, as + system console. + + If unsure, say N. + +Support for PowerMac serial ports +CONFIG_MAC_SERIAL + If you have Macintosh style serial ports (8 pin mini-DIN), say Y + here. If you also have regular serial ports and enable the driver + for them, you can't currently use the serial console feature. + +Comtrol Rocketport support +CONFIG_ROCKETPORT + This is a driver for the Comtrol Rocketport cards which provide + multiple serial ports. You would need something like this to connect + more than two modems to your Linux box, for instance in order to + become a dial-in server. + + If you want to compile this driver as a module, say M here and read + Documentation/modules.txt. The module will be called rocket.o. + +Digiboard Intelligent async support +CONFIG_DIGIEPCA + This is a driver for Digi International's Xx, Xeve, and Xem series + of cards which provide multiple serial ports. You would need + something like this to connect more than two modems to your Linux + box, for instance in order to become a dial-in server. This driver + supports the original PC (ISA) boards as well as PCI, and EISA. If + you have a card like this, say Y here and read the file + Documentation/digiepca.txt. + + NOTE: There is another, separate driver for the Digiboard PC boards: + "Digiboard PC/Xx Support" below. You should (and can) only select + one of the two drivers. + + If you want to compile this driver as a module, say M here and read + Documentation/modules.txt. The module will be called epca.o. + +Digiboard PC/Xx Support +CONFIG_DIGI + This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards + that give you many serial ports. You would need something like this + to connect more than two modems to your Linux box, for instance in + order to become a dial-in server. If you have a card like that, say + Y here and read the file Documentation/digiboard.txt. + + If you want to compile this driver as a module, say M here and read + Documentation/modules.txt. The module will be called pcxx.o. + +SDL RISCom/8 card support +CONFIG_RISCOM8 + This is a driver for the SDL Communications RISCom/8 multiport card, + which gives you many serial ports. You would need something like + this to connect more than two modems to your Linux box, for instance + in order to become a dial-in server. If you have a card like that, + say Y here and read the file Documentation/riscom8.txt. + + Also it's possible to say M here and compile this driver as kernel + loadable module; the module will be called riscom8.o. + +Computone IntelliPort Plus serial support +CONFIG_COMPUTONE + This driver supports the entire family of Intelliport II/Plus + controllers with the exception of the MicroChannel controllers. It + does not support products previous to the Intelliport II. These are + multiport cards, which give you many serial ports. You would need + something like this to connect more than two modems to your Linux + box, for instance in order to become a dial-in server. If you have a + card like that, say Y here and read Documentation/computone.txt. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. You will get two + modules called ip2.o and ip2main.o. + +Specialix IO8+ card support +CONFIG_SPECIALIX + This is a driver for the Specialix IO8+ multiport card (both the + ISA and the PCI version) which gives you many serial ports. You + would need something like this to connect more than two modems to + your Linux box, for instance in order to become a dial-in server. + + If you have a card like that, say Y here and read the file + Documentation/specialix.txt. Also it's possible to say M here and + compile this driver as kernel loadable module which will be called + specialix.o. + +Specialix DTR/RTS pin is RTS +CONFIG_SPECIALIX_RTSCTS + The Specialix card can only support either RTS or DTR. If you say N + here, the driver will use the pin as "DTR" when the tty is in + software handshake mode. If you say Y here or hardware handshake is + on, it will always be RTS. Read the file Documentation/specialix.txt + for more information. + +Cyclades async mux support +CONFIG_CYCLADES + This is a driver for a card that gives you many serial ports. You + would need something like this to connect more than two modems to + your Linux box, for instance in order to become a dial-in server. + For information about the Cyclades-Z card, read + drivers/char/README.cycladesZ. + + As of 1.3.9x kernels, this driver's minor numbers start at 0 instead + of 32. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called cyclades.o. + + If you haven't heard about it, it's safe to say N. + +Cyclades-Z interrupt mode operation (EXPERIMENTAL) +CONFIG_CYZ_INTR + The Cyclades-Z family of multiport cards allows 2 (two) driver + op modes: polling and interrupt. In polling mode, the driver will + check the status of the Cyclades-Z ports every certain amount of + time (which is called polling cycle and is configurable). In + interrupt mode, it will use an interrupt line (IRQ) in order to check + the status of the Cyclades-Z ports. The default op mode is polling. + If unsure, say N. + +Stallion multiport serial support +CONFIG_STALDRV + Stallion cards give you many serial ports. You would need something + like this to connect more than two modems to your Linux box, for + instance in order to become a dial-in server. If you say Y here, you + will be asked for your specific card model in the next questions. + Make sure to read drivers/char/README.stallion in this case. If you + have never heard about all this, it's safe to say N. + +Stallion EasyIO or EC8/32 support +CONFIG_STALLION + If you have an EasyIO or EasyConnection 8/32 multiport Stallion + card, then this is for you; say Y. Make sure to read + Documentation/stallion.txt. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called stallion.o. + +Stallion EC8/64, ONboard, Brumby support +CONFIG_ISTALLION + If you have an EasyConnection 8/64, ONboard, Brumby or Stallion + serial multiport card, say Y here. Make sure to read + Documentation/stallion.txt. + + To compile it as a module ( = code which can be inserted in and + removed from the running kernel whenever you want), say M here and + read Documentation/modules.txt. The module will be called + istallion.o. + +Microgate SyncLink adapter support +CONFIG_SYNCLINK + Provides support for the SyncLink ISA and PCI + multiprotocol serial adapters. These adapters + support asynchronous and HDLC bit synchronous + communication up to 10Mbps (PCI adapter). + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called synclink.o. If you want to do that, say M + here. + +Synchronous HDLC line discipline support +CONFIG_N_HDLC + Allows synchronous HDLC communications with tty device drivers that + support synchronous HDLC such as the Microgate SyncLink adapter. + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called n_hdlc.o. If you want to do that, say M + here. + +Specialix SX (and SI) card support +CONFIG_SX + This is a driver for the SX and SI multiport serial cards. + Please read the file Documentation/sx.txt for details. + + This driver can only be built as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called sx.o. If you want to do that, say M here. + +Hayes ESP serial port support +CONFIG_ESPSERIAL + This is a driver which supports Hayes ESP serial ports. Both single + port cards and multiport cards are supported. Make sure to read + Documentation/hayes-esp.txt. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read Documentation/modules.txt. The module will be called esp.o. + If unsure, say N. + +Multi-Tech multiport card support (EXPERIMENTAL) +CONFIG_ISI + This is a driver for the Multi-Tech cards which provide several + serial ports. The driver is experimental and can currently only be + built as a module ( = code which can be inserted in and removed from + the running kernel whenever you want). Please read + Documentation/modules.txt. The module will be called isicom.o + +Unix98 PTY support +CONFIG_UNIX98_PTYS + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx for + masters and /dev/ttyxx for slaves of pseudo terminals. This scheme + has a number of problems. The GNU C library glibc 2.1 and later, + however, supports the Unix98 naming standard: in order to acquire a + pseudo terminal, a process opens /dev/ptmx; the number of the pseudo + terminal is then made available to the process and the pseudo + terminal slave can be accessed as /dev/pts/. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + The entries in /dev/pts/ are created on the fly by a virtual + filesystem; therefore, if you say Y here you should say Y to + "/dev/pts filesystem for Unix98 PTYs" as well. + + If you want to say Y here, you need to have the C library glibc 2.1 + or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*"). + Read the instructions in Documentation/Changes pertaining to pseudo + terminals. It's safe to say N. + +Maximum number of Unix98 PTYs in use (0-2048) +CONFIG_UNIX98_PTY_COUNT + The maximum number of Unix98 PTYs that can be used at any one time. + The default is 256, and should be enough for desktop systems. Server + machines which support incoming telnet/rlogin/ssh connections and/or + serve several X terminals may want to increase this: every incoming + connection and every xterm uses up one PTY. + + When not in use, each additional set of 256 PTYs occupy + approximately 8 KB of kernel memory on 32-bit architectures. + +Parallel printer support +CONFIG_PRINTER + If you intend to attach a printer to the parallel port of your Linux + box (as opposed to using a serial printer; if the connector at the + printer has 9 or 25 holes ["female"], then it's serial), say Y. Also + read the Printing-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + It is possible to share one parallel port among several devices + (e.g. printer and ZIP drive) and it is safe to compile the + corresponding drivers into the kernel. If you want to compile this + driver as a module however ( = code which can be inserted in and + removed from the running kernel whenever you want), say M here and + read Documentation/modules.txt and Documentation/parport.txt. The + module will be called lp.o. + + If you have several parallel ports, you can specify which ports to + use with the "lp" kernel command line option. (Try "man bootparam" + or see the documentation of your boot loader (lilo or loadlin) about + how to pass options to the kernel at boot time. The lilo procedure + is also explained in the SCSI-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto .) The syntax of the "lp" + command line option can be found in drivers/char/lp.c. + + If you have more than 3 printers, you need to increase the LP_NO + variable in lp.c. + +Support for console on line printer +CONFIG_LP_CONSOLE + If you want kernel messages to be printed out as they occur, you + can have a console on the printer. This option adds support for + doing that; to actually get it to happen you need to pass the + option "console=lp" to the kernel at boot time. + + Note that kernel messages can get lost if the printer is out of + paper (or off, or unplugged, or too busy..), but this behaviour + can be changed. See drivers/char/lp.c (do this at your own risk). + + If unsure, say N. + +Bus Mouse Support +CONFIG_BUSMOUSE + Say Y here if your machine has a bus mouse as opposed to a serial + mouse. Most people have a regular serial MouseSystem or + Microsoft mouse (made by Logitech) that plugs into a COM port + (rectangular with 9 or 25 pins). These people say N here. If you + have something else, read the Busmouse-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto , and say Y here. + + If you have a laptop, you either have to check the documentation or + experiment a bit to find out whether the trackball is a serial mouse + or not; it's best to say Y here for you. + + This is the generic bus mouse driver code. If you have a bus mouse, + you will have to say Y here and also to the specific driver for your + mouse below. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called busmouse.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Mouse Support (not serial and bus mice) +CONFIG_MOUSE + This is for machines with a mouse which is neither a serial nor a + bus mouse. Examples are PS/2 mice (such as the track balls on some + laptops) and some digitizer pads. Most people have a regular serial + MouseSystem or Microsoft mouse (made by Logitech) that plugs into a + COM port (rectangular with 9 or 25 pins). These people say N here. + If you have something else, read the Busmouse-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . This HOWTO contains + information about all non-serial mice, not just bus mice. + + If you have a laptop, you either have to check the documentation or + experiment a bit to find out whether the trackball is a serial mouse + or not; it's best to say Y here for you. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause this configure script to skip all + the questions about non-serial mice. If unsure, say Y. + +Logitech busmouse support +CONFIG_LOGIBUSMOUSE + Logitech mouse connected to a proprietary interface card. It's + generally a round connector with 9 pins. Note that the newer mice + made by Logitech don't use the Logitech protocol anymore; for those, + you don't need this option. You want to read the Busmouse-HOWTO , + available from http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called busmouse.o. If you are unsure, say N and read the HOWTO + nevertheless: it will tell you what you have. + +PS/2 mouse (aka "auxiliary device") support +CONFIG_PSMOUSE + The PS/2 mouse connects to a special mouse port that looks much like + the keyboard port (small circular connector with 6 pins). This way, + the mouse does not use any serial ports. This port can also be used + for other input devices like light pens, tablets, keypads. Compaq, + AST and IBM all use this as their mouse port on currently shipping + machines. The trackballs of some laptops are PS/2 mice also. In + particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 mouse. + + Although PS/2 mice are not technically bus mice, they are explained + in detail in the Busmouse-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + When using a PS/2 mouse, you can get problems if you want to use the + mouse both on the Linux console and under X. Using the "-R" option + of the Linux mouse managing program gpm (available from + ftp://metalab.unc.edu/pub/Linux/system/mouse ) solves this + problem, or you can get the "mconv2" utility from the same location. + +C&T 82C710 mouse port support (as on TI Travelmate) +CONFIG_82C710_MOUSE + This is a certain kind of PS/2 mouse used on the TI Travelmate. If + you are unsure, try first to say N here and come back if the mouse + doesn't work. Read the Busmouse-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + +PC110 digitizer pad support +CONFIG_PC110_PAD + This drives the digitizer pad on the IBM PC110 palmtop. It can turn + the digitizer pad into a PS/2 mouse emulation with tap gestures or + into an absolute pad. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called pc110pad.o. + +Microsoft busmouse support +CONFIG_MS_BUSMOUSE + These animals (also called Inport mice) are connected to an + expansion board using a round connector with 9 pins. If this is what + you have, say Y and read the Busmouse-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you are unsure, say N and read the HOWTO nevertheless: it will + tell you what you have. Also be aware that several vendors talk + about 'Microsoft busmouse' and actually mean PS/2 busmouse -- so + count the pins on the connector. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called msbusmouse.o. + +Apple Desktop Bus mouse support +CONFIG_ADBMOUSE + Say Y here if you have this type of bus mouse (4 pin connector) as + is common on Macintoshes. You may want to read the Busmouse-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called adbmouse.o. + +ATIXL busmouse support +CONFIG_ATIXL_BUSMOUSE + This is a rare type of busmouse that is connected to the back of an + ATI video card. Say Y if you have one of those. Note however that + most mice by ATI are actually Microsoft busmice; you should say Y to + "Microsoft busmouse support" above if you have one of those. Read + the Busmouse-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called atixlmouse.o. + + If you are unsure, say N and read the HOWTO nevertheless: it will + tell you what you have. + +QIC-02 tape support +CONFIG_QIC02_TAPE + If you have a non-SCSI tape drive like that, say Y. Or, if you want + to compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read Documentation/modules.txt. The module will be called + tpqic02.o. + +Do you want runtime configuration for QIC-02 +CONFIG_QIC02_DYNCONF + You can either configure this driver once and for all by editing a + header file (include/linux/tpqic02.h), in which case you should + say N, or you can fetch a program via anonymous FTP which is able + to configure this driver during runtime. The program to do this is + called 'qic02conf' and it is part of the tpqic02-support-X.Y.tar.gz + support package. + + If you want to use the qic02conf program, say Y. + +Floppy tape drive (QIC-80/40/3010/3020/TR-1/TR-2/TR-3) support +CONFIG_FTAPE + If you have a tape drive that is connected to your floppy + controller, say Y here. + + Some tape drives (like the Seagate "Tape Store 3200" or the Iomega + "Ditto 3200" or the Exabyte "Eagle TR-3") come with a "high speed" + controller of their own. These drives (and their companion + controllers) are also supported if you say Y here. + + If you have a special controller (such as the CMS FC-10, FC-20, + Mountain Mach-II, or any controller that is based on the Intel 82078 + FDC like the high speed controllers by Seagate and Exabyte and + Iomega's "Ditto Dash") you must configure it by selecting the + appropriate entries from the "Floppy tape controllers" sub-menu + below and possibly modify the default values for the IRQ and DMA + channel and the IO base in ftape's configuration menu. + + If you want to use your floppy tape drive on a PCI-bus based system, + please read the file drivers/char/ftape/README.PCI. + + The ftape kernel driver is also available as a runtime loadable + module ( = code which can be inserted in and removed from the + running kernel whenever you want). If you want to compile it as a + module, say M here and read Documentation/modules.txt. The module + will be called ftape.o. + + Note that the Ftape-HOWTO is out of date (sorry) and documents the + older version 2.08 of this software but still contains useful + information. There is a web page with more recent documentation at + http://www.math1.rwth-aachen.de/~heine/ftape/ . This page + always contains the latest release of the ftape driver and useful + information (backup software, ftape related patches and + documentation, FAQ). Note that the file system interface has changed + quite a bit compared to previous versions of ftape. Please read + Documentation/ftape.txt. + +The file system interface for ftape +CONFIG_ZFTAPE + Normally, you want to say Y or M. DON'T say N here or you + WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE. + + The ftape module itself no longer contains the routines necessary + to interface with the kernel VFS layer (i.e. to actually write data + to and read data from the tape drive). Instead the file system + interface (i.e. the hardware independent part of the driver) has + been moved to a separate module. + + If you say M zftape will be compiled as a runtime loadable + module ( = code which can be inserted in and removed from the + running kernel whenever you want). In this case you should read + Documentation/modules.txt. The module will be called zftape.o. + + Regardless of whether you say Y or M here, an additional runtime + loadable module called `zft-compressor.o' which contains code to + support user transparent on-the-fly compression based on Ross + William's lzrw3 algorithm will be produced. If you have enabled the + kernel module loader (i.e. have said Y to "Kernel module loader + support", above) then `zft-compressor.o' will be loaded + automatically by zftape when needed. + + Despite its name, zftape does NOT use compression by default. The + file Documentation/ftape.txt contains a short description of the + most important changes in the file system interface compared to + previous versions of ftape. The ftape home page + http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/ contains + further information. + + IMPORTANT NOTE: zftape can read archives created by previous + versions of ftape and provide file mark support (i.e. fast skipping + between tape archives) but previous version of ftape will lack file + mark support when reading archives produced by zftape. + +Default block size for zftape +CONFIG_ZFT_DFLT_BLK_SZ + If unsure leave this at its default value, i.e. 10240. Note that + you specify only the default block size here. The block size can be + changed at run time using the MTSETBLK tape operation with the + MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the + shell command line). + + The probably most striking difference between zftape and previous + versions of ftape is the fact that all data must be written or read + in multiples of a fixed block size. The block size defaults to + 10240 which is what GNU tar uses. The values for the block size + should be either 1 or multiples of 1024 up to a maximum value of + 63488 (i.e. 62 K). If you specify `1' then zftape's builtin + compression will be disabled. + + Reasonable values are `10240' (GNU tar's default block size), + `5120' (afio's default block size), `32768' (default block size some + backup programs assume for SCSI tape drives) or `1' (no restriction + on block size, but disables builtin compression). + +Number of DMA buffers +CONFIG_FT_NR_BUFFERS + Please leave this at `3' unless you REALLY know what you are doing. + It is not necessary to change this value. Values below 3 make the + proper use of ftape impossible, values greater than 3 are a waste of + memory. You can change the amount of DMA memory used by ftape at + runtime with "mt -f /dev/qft0 setdrvbuffer #NUMBUFFERS". Each buffer + wastes 32 KB of memory. Please note that this memory cannot be + swapped out. + +Procfs entry for ftape +CONFIG_FT_PROC_FS + Optional. Saying Y will result in creation of a directory + `/proc/ftape' under the proc file system. The files can be viewed + with your favorite pager (i.e. use "more /proc/ftape/history" or + "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The + file will contain some status information about the inserted + cartridge, the kernel driver, your tape drive, the floppy disk + controller and the error history for the most recent use of the + kernel driver. Saying Y will enlarge the size of the ftape driver + by approximately 2 KB. + + WARNING: When compiling ftape as a module (i.e. saying M to + "Floppy tape drive") it is dangerous to use ftape's proc file system + interface. Accessing `/proc/ftape' while the module is unloaded will + result in a kernel Oops. This cannot be fixed from inside ftape. + +Controlling the amount of debugging output of ftape +CONFIG_FT_NORMAL_DEBUG + This option controls the amount of debugging output the ftape driver + is ABLE to produce; it does not increase or diminish the debugging + level itself. If unsure, leave this at its default setting, + i.e. choose "Normal". + + Ftape can print lots of debugging messages to the system console + resp. kernel log files. Reducing the amount of possible debugging + output reduces the size of the kernel module by some KB, so it might + be a good idea to use "None" for emergency boot floppies. + + If you want to save memory then the following strategy is + recommended: leave this option at its default setting "Normal" until + you know that the driver works as expected, afterwards reconfigure + the kernel, this time specifying "Reduced" or "None" and recompile + and install the kernel as usual. Note that choosing "Excessive" + debugging output does not increase the amount of debugging output + printed to the console but only makes it possible to produce + "Excessive" debugging output. + + Please read Documentation/ftape.txt for a short description + how to control the amount of debugging output. + +The floppy drive controller for ftape +CONFIG_FT_STD_FDC + Only change this setting if you have a special controller. If you + didn't plug any add-on card into your computer system but just + plugged the floppy tape cable into the already existing floppy drive + controller then you don't want to change the default setting, + i.e. choose "Standard". + + Choose "MACH-2" if you have a Mountain Mach-2 controller. + Choose "FC-10/FC-20" if you have a Colorado FC-10 or FC-20 + controller. + Choose "Alt/82078" if you have another controller that is located at + an IO base address different from the standard floppy drive + controller's base address of `0x3f0', or uses an IRQ (interrupt) + channel different from `6', or a DMA channel different from + `2'. This is necessary for any controller card that is based on + Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high + speed" controllers. + + If you choose something other than "Standard" then please make + sure that the settings for the IO base address and the IRQ and DMA + channel in the configuration menus below are correct. Use the manual + of your tape drive to determine the correct settings! + + If you are already successfully using your tape drive with another + operating system then you definitely should use the same settings + for the IO base, the IRQ and DMA channel that have proven to work + with that other OS. + + Note that this menu lets you specify only the default setting for + the hardware setup. The hardware configuration can be changed at + boot time (when ftape is compiled into the kernel, i.e. if you + have said Y to "Floppy tape drive") or module load time (i.e. if you + have said M to "Floppy tape drive"). + + Please read also the file Documentation/ftape.txt which + contains a short description of the parameters that can be set at + boot or load time. If you want to use your floppy tape drive on a + PCI-bus based system, please read the file + drivers/char/ftape/README.PCI. + +IO base of the floppy disk controller used with Ftape +CONFIG_FT_FDC_BASE + You don't need to specify a value if the following default + settings for the base IO address are correct: + <<< MACH-2 : 0x1E0 >>> + <<< FC-10/FC-20: 0x180 >>> + <<< Secondary : 0x370 >>> + Secondary refers to a secondary FDC controller like the "high speed" + controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. + Please make sure that the setting for the IO base address + specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR + CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already + successfully using the tape drive with another operating system then + you definitely should use the same settings for the IO base that has + proven to work with that other OS. + + Note that this menu lets you specify only the default setting for + the IO base. The hardware configuration can be changed at boot time + (when ftape is compiled into the kernel, i.e. if you specified Y to + "Floppy tape drive") or module load time (i.e. if you have said M to + "Floppy tape drive"). + + Please read also the file Documentation/ftape.txt which contains a + short description of the parameters that can be set at boot or load + time. + +IRQ channel for the floppy disk controller used with Ftape +CONFIG_FT_FDC_IRQ + You don't need to specify a value if the following default + settings for the interrupt channel are correct: + <<< MACH-2 : 6 >>> + <<< FC-10/FC-20: 9 >>> + <<< Secondary : 6 >>> + Secondary refers to secondary a FDC controller like the "high speed" + controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. + Please make sure that the setting for the IO base address + specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR + CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already + successfully using the tape drive with another operating system then + you definitely should use the same settings for the IO base that has + proven to work with that other OS. + + Note that this menu lets you specify only the default setting for + the IRQ channel. The hardware configuration can be changed at boot + time (when ftape is compiled into the kernel, i.e. if you said Y to + "Floppy tape drive") or module load time (i.e. if you said M to + "Floppy tape drive"). + + Please read also the file Documentation/ftape.txt which contains a + short description of the parameters that can be set at boot or load + time. + +DMA channel for the floppy disk controller used with Ftape +CONFIG_FT_FDC_DMA + You don't need to specify a value if the following default + settings for the DMA channel are correct: + <<< MACH-2 : 2 >>> + <<< FC-10/FC-20: 3 >>> + <<< Secondary : 2 >>> + Secondary refers to a secondary FDC controller like the "high speed" + controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash. + Please make sure that the setting for the IO base address + specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR + CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already + successfully using the tape drive with another operating system then + you definitely should use the same settings for the IO base that has + proven to work with that other OS. + + Note that this menu lets you specify only the default setting for + the DMA channel. The hardware configuration can be changed at boot + time (when ftape is compiled into the kernel, i.e. if you said Y to + "Floppy tape drive") or module load time (i.e. if you said M to + "Floppy tape drive"). + + Please read also the file Documentation/ftape.txt which contains a + short description of the parameters that can be set at boot or load + time. + +FDC FIFO Threshold before requesting DMA service +CONFIG_FT_FDC_THR + Set the FIFO threshold of the FDC. If this is higher the DMA + controller may serve the FDC after a higher latency time. If this is + lower, fewer DMA transfers occur leading to less bus contention. + You may try to tune this if ftape annoys you with "reduced data + rate because of excessive overrun errors" messages. However, this + doesn't seem to have too much effect. + + If unsure, don't touch the initial value, i.e. leave it at "8". + +FDC maximum data rate +CONFIG_FT_FDC_MAX_RATE + With some motherboard/FDC combinations ftape will not be able to + run your FDC/tape drive combination at the highest available + speed. If this is the case you'll encounter "reduced data rate + because of excessive overrun errors" messages and lots of retries + before ftape finally decides to reduce the data rate. + + In this case it might be desirable to tell ftape beforehand that + it need not try to run the tape drive at the highest available + speed. If unsure, leave this disabled, i.e. leave it at 2000 + bits/sec. + +Direct Rendering Manager (XFree86 DRI support) +CONFIG_DRM + Kernel-level support for the Direct Rendering Infrastructure (DRI) + introduced in XFree86 4.x. These modules provide support for + synchronization, security, and DMA transfers. Select the module that + provides support for your graphics card. + +3dlabs GMX 2000 Direct Rendering Driver (XFree86 DRI support) +CONFIG_DRM_GAMMA + Choose M here if you have a 3dlabs GMX 2000 graphics card. + +MTRR control and configuration +CONFIG_MTRR + On Intel P6 family processors (Pentium Pro, Pentium II and later) + the Memory Type Range Registers (MTRRs) may be used to control + processor access to memory ranges. This is most useful when you have + a video (VGA) card on a PCI or AGP bus. Enabling write-combining + allows bus write transfers to be combined into a larger transfer + before bursting over the PCI/AGP bus. This can increase performance + of image write operations 2.5 times or more. This option creates a + /proc/mtrr file which may be used to manipulate your + MTRRs. Typically the X server should use this. This should have a + reasonably generic interface so that similar control registers on + other processors can be easily supported. + + The Cyrix 6x86, 6x86MX and M II processors have Address Range + Registers (ARRs) which provide a similar functionality to MTRRs. For + these, the ARRs are used to emulate the MTRRs, which means that it + makes sense to say Y here for these processors as well. + + The AMD K6-2 (stepping 8 and above) and K6-3 processors have two + MTRRs. The Centaur C6 (WinChip) has 8 MCRs, allowing + write-combining. All of these processors are supported by this code. + + The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These + are supported. + + Saying Y here also fixes a problem with buggy SMP BIOSes which only + set the MTRRs for the boot CPU and not the secondary CPUs. This can + lead to all sorts of problems. + + You can safely say Y even if your machine doesn't have MTRRs, you'll + just add about 9K to your kernel. + + See Documentation/mtrr.txt for more information. + +Main CPU frequency, only for DEC alpha machine +CONFIG_FT_ALPHA_CLOCK + On some DEC Alpha machines the CPU clock frequency cannot be + determined automatically, so you need to specify it here ONLY if + running a DEC Alpha, otherwise this setting has no effect. + +Zilog serial support +CONFIG_SUN_ZS + This driver does not exist at this point, so you might as well + say N. + +Double Talk PC internal speech card support +CONFIG_DTLK + This driver is for the DoubleTalk PC, a speech synthesizer + manufactured by RC Systems (http://www.rcsys.com/ ). It is also + called the `internal DoubleTalk'. If you want to compile this as a + module ( = code which can be inserted in and removed from the + running kernel whenever you want), say M here and read + Documentation/modules.txt. The module will be called dtlk.o. + +Siemens R3964 serial protocol support +CONFIG_R3964 + This driver allows synchronous communication with devices using the + Siemens R3964 packet protocol. Unless you are dealing with special + hardware like PLCs, you are unlikely to need this. + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read Documentation/modules.txt. The module will be called + n_r3964.o. + + If unsure, say N. + +Applicom intelligent fieldbus card support +CONFIG_APPLICOM + This driver provides the kernel-side support for the intelligent + fieldbus cards made by Applicom International. More information + about these cards can be found on the WWW at the address + http://www.applicom-int.com/ , or by email from David Woodhouse + . + + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read Documentation/modules.txt. The module will be called + applicom.o. + + If unsure, say N. + +Advanced Power Management +CONFIG_APM + APM is a BIOS specification for saving power using several different + techniques. This is mostly useful for battery powered laptops with + APM compliant BIOSes. If you say Y here, the system time will be + reset after a RESUME operation, the /proc/apm device will provide + battery status information, and user-space programs will receive + notification of APM "events" (e.g. battery status change). + + If you select "Y" here, you can disable actual use of the APM + BIOS by passing the "apm=off" option to the kernel at boot time. + + Note that the APM support is almost completely disabled for + machines with more than one CPU. + + Supporting software is available; for more information, read the + Battery Powered Linux mini-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . + + This driver does not spin down disk drives (see the hdparm(8) + manpage ("man 8 hdparm") for that), and it doesn't turn off + VESA-compliant "green" monitors. + + This driver does not support the TI 4000M TravelMate and the ACER + 486/DX4/75 because they don't have compliant BIOSes. Many "green" + desktop machines also don't have compliant BIOSes, and this driver + may cause those machines to panic during the boot phase. + + If you are running Linux on a laptop, you may also want to read the + Linux Laptop home page on the WWW at + http://www.cs.utexas.edu/users/kharker/linux-laptop/ . + + Generally, if you don't have a battery in your machine, there isn't + much point in using this driver and you should say N. If you get + random kernel OOPSes or reboots that don't seem to be related to + anything, try disabling/enabling this option (or disabling/enabling + APM in your BIOS). + + Some other things you should try when experiencing seemingly random, + "weird" problems: + + 1) make sure that you have enough swap space and that it is + enabled. + 2) pass the "no-hlt" option to the kernel + 3) switch on floating point emulation in the kernel and pass + the "no387" option to the kernel + 4) pass the "floppy=nodma" option to the kernel + 5) pass the "mem=4M" option to the kernel (thereby disabling + all but the first 4 MB of RAM) + 6) make sure that the CPU is not over clocked. + 7) read the sig11 FAQ at http://www.bitwizard.nl/sig11/ + 8) disable the cache from your BIOS settings + 9) install a fan for the video card or exchange video RAM + 10) install a better fan for the CPU + 11) exchange RAM chips + 12) exchange the motherboard. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called apm.o. + +Ignore USER SUSPEND +CONFIG_APM_IGNORE_USER_SUSPEND + This option will ignore USER SUSPEND requests. On machines with a + compliant APM BIOS, you want to say N. However, on the NEC Versa M + series notebooks, it is necessary to say Y because of a BIOS bug. + +Enable APM at boot time +CONFIG_APM_DO_ENABLE + Enable APM features at boot time. From page 36 of the APM BIOS + specification: "When disabled, the APM BIOS does not automatically + power manage devices, enter the Standby State, enter the Suspend + State, or take power saving steps in response to CPU Idle calls." + This driver will make CPU Idle calls when Linux is idle (unless this + feature is turned off -- see "Do CPU IDLE calls", below). This + should always save battery power, but more complicated APM features + will be dependent on your BIOS implementation. You may need to turn + this option off if your computer hangs at boot time when using APM + support, or if it beeps continuously instead of suspending. Turn + this off if you have a NEC UltraLite Versa 33/C or a Toshiba + T400CDT. This is off by default since most machines do fine without + this feature. + +Do CPU IDLE calls +CONFIG_APM_CPU_IDLE + Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop. + On some machines, this can activate improved power savings, such as + a slowed CPU clock rate, when the machine is idle. These idle calls + are made after the idle loop has run for some length of time (e.g., + 333 mS). On some machines, this will cause a hang at boot time or + whenever the CPU becomes idle. (On machines with more than one CPU, + this option does nothing.) + +Enable console blanking using APM +CONFIG_APM_DISPLAY_BLANK + Enable console blanking using the APM. Some laptops can use this to + turn off the LCD backlight when the screen blanker of the Linux + virtual console blanks the screen. Note that this is only used by + the virtual console screen blanker, and won't turn off the backlight + when using the X Window system. This also doesn't have anything to + do with your VESA-compliant power-saving monitor. Further, this + option doesn't work for all laptops -- it might not turn off your + backlight at all, or it might print a lot of errors to the console, + especially if you are using gpm. + +Power off on shutdown +CONFIG_APM_POWER_OFF + Enable the ability to power off the computer after the Linux kernel + is halted. You will need software (e.g., a suitable version of the + halt(8) command ("man 8 halt")) to cause the computer to power down. + Recent versions of the sysvinit package available from + ftp://metalab.unc.edu/pub/Linux/system/daemons/init/ contain support + for this ("halt -p" shuts down Linux and powers off the computer, if + executed from runlevel 0). As with the other APM options, this + option may not work reliably with some APM BIOS implementations. + +Ignore multiple suspend/standby events +CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + This option is necessary on the IBM Thinkpad 560, but should work on + all other laptops. When the APM BIOS returns multiple suspend or + standby events while one is already being processed they will be + ignored. Without this the Thinkpad 560 has troubles with the user + level daemon apmd, and with the PCMCIA package pcmcia-cs. + +Ignore multiple suspend/resume cycles +CONFIG_APM_IGNORE_SUSPEND_BOUNCE + This option is necessary on the Dell Inspiron 3200 and others, but + should be safe for all other laptops. When enabled, a system suspend + event that occurs within three seconds of a resume is ignored. + Without this the Inspiron will shut itself off a few seconds after + you open the lid, requiring you to press the power button to resume + it a second time. Say Y. + +RTC stores time in GMT +CONFIG_APM_RTC_IS_GMT + Say Y here if your RTC (Real Time Clock a.k.a. hardware clock) + stores the time in GMT (Greenwich Mean Time). Say N if your RTC + stores localtime. + + It is in fact recommended to store GMT in your RTC, because then you + don't have to worry about daylight savings time changes. The only + reason not to use GMT in your RTC is if you also run a broken OS + that doesn't understand GMT. + +Allow interrupts during APM BIOS calls +CONFIG_APM_ALLOW_INTS + Normally we disable external interrupts while we are making calls to + the APM BIOS as a measure to lessen the effects of a badly behaving + BIOS implementation. The BIOS should reenable interrupts if it + needs to. Unfortunately, some BIOSes do not - especially those in + many of the newer IBM Thinkpads. If you experience hangs when you + suspend, try setting this to Y. Otherwise, say N. + +Watchdog Timer Support +CONFIG_WATCHDOG + If you say Y here (and to one of the following options) and create a + character special file /dev/watchdog with major number 10 and minor + number 130 using mknod ("man mknod"), you will get a watchdog, i.e.: + subsequently opening the file and then failing to write to it for + longer than 1 minute will result in rebooting the machine. This + could be useful for a networked machine that needs to come back + online as fast as possible after a lock-up. There's both a watchdog + implementation entirely in software (which can sometimes fail to + reboot the machine) and a driver for hardware watchdog boards, which + are more robust and can also keep track of the temperature inside + your computer. For details, read Documentation/watchdog.txt in the + kernel source. + + The watchdog is usually used together with the watchdog daemon + which is available via FTP (user: anonymous) from + ftp://tsx-11.mit.edu/pub/linux/sources/sbin/ . This daemon can also + monitor NFS connections and can reboot the machine when the process + table is full. + + If unsure, say N. + +Disable watchdog shutdown on close +CONFIG_WATCHDOG_NOWAYOUT + The default watchdog behaviour (which you get if you say N here) is + to stop the timer if the process managing it closes the file + /dev/watchdog. It's always remotely possible that this process might + get killed. If you say Y here, the watchdog cannot be stopped once + it has been started. + +WDT Watchdog timer +CONFIG_WDT + If you have a WDT500P or WDT501P watchdog board, say Y here, + otherwise N. It is not possible to probe for this board, which means + that you have to set the IO port and IRQ it uses in the kernel + source at the top of drivers/char/wdt.c. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called wdt.o. + +WDT501 features +CONFIG_WDT_501 + Saying Y here and creating a character special file /dev/temperature + with major number 10 and minor number 131 ("man mknod") will give + you a thermometer inside your computer: reading from + /dev/temperature yields one byte, the temperature in degrees + Fahrenheit. This works only if you have a WDT501P watchdog board + installed. + +Fan Tachometer +CONFIG_WDT_501_FAN + Enable the Fan Tachometer on the WDT501. Only do this if you have a + fan tachometer actually set up. + +Software Watchdog +CONFIG_SOFT_WATCHDOG + A software monitoring watchdog. This will fail to reboot your system + from some situations that the hardware watchdog will recover + from. Equally it's a lot cheaper to install. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called softdog.o. + +Berkshire Products PC Watchdog +CONFIG_PCWATCHDOG + This is the driver for the Berkshire Products PC Watchdog card. + This card simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of + time. This driver is like the WDT501 driver but for different + hardware. Please read Documentation/pcwd-watchdog.txt. The PC + watchdog cards can be ordered from http://www.berkprod.com . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called pcwd.o. If you want to compile it as a module, + say M here and read Documentation/modules.txt. + + Most people will say N. + +Acquire SBC Watchdog Timer +CONFIG_ACQUIRE_WDT + This is the driver for the hardware watchdog on the PSC-6x86 Single + Board Computer produced by Acquire Inc (and others). This watchdog + simply watches your kernel to make sure it doesn't freeze, and if + it does, it reboots your computer after a certain amount of time. + + This driver is like the WDT501 driver but for different hardware. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called pscwdt.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. Most people + will say N. + +Enhanced Real Time Clock Support +CONFIG_RTC + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock built into your computer. + Every PC has such a clock built in. It can be used to generate + signals from as low as 1Hz up to 8192Hz, and can also be used as a + 24 hour alarm. It reports status information via the file /proc/rtc + and its behaviour is set by various ioctls on /dev/rtc. + + If you run Linux on a multiprocessor machine and said Y to + "Symmetric Multi Processing" above, you should say Y here to read + and set the RTC in an SMP compatible fashion. + + If you think you have a use for such a device (such as periodic data + sampling), then say Y here, and read Documentation/rtc.txt for + details. + +Tadpole ANA H8 Support +CONFIG_H8 + The Hitachi H8/337 is a microcontroller used to deal with the power + and thermal environment. If you say Y here, you will be able to + communicate with it via a character special device. + + If unsure, say N. + +/dev/nvram support +CONFIG_NVRAM + If you say Y here and create a character special file /dev/nvram + with major number 10 and minor number 144 using mknod ("man mknod"), + you get read and write access to the 50 bytes of non-volatile memory + in the real time clock (RTC), which is contained in every PC and + most Ataris. + + This memory is conventionally called "CMOS RAM" on PCs and "NVRAM" + on Ataris. /dev/nvram may be used to view settings there, or to + change them (with some utility). It could also be used to frequently + save a few bits of very important data that may not be lost over + power-off and for which writing to disk is too insecure. Note + however that most NVRAM space in a PC belongs to the BIOS and you + should NEVER idly tamper with it. See Ralf Brown's interrupt list + for a guide to the use of CMOS bytes by your BIOS. + + On Atari machines, /dev/nvram is always configured and does not need + to be selected. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called nvram.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Joystick support +CONFIG_JOYSTICK + If you have a joystick, you can say Y here to enable generic + joystick support. You will also need to say Y or M to at least one + of the hardware specific joystick drivers. This will make the + joysticks available as /dev/jsX devices. Please read the file + Documentation/joystick.txt which contains more information and the + location of the joystick package that you'll need. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called joystick.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Classic PC analog joysticks and gamepads +CONFIG_JOY_ANALOG + Say Y here if you have an analog joystick or gamepad that connects + to the PC gameport. This supports many different types, including + joysticks with throttle control, with rudders, or with extensions + like additional hats and buttons compatible with CH Flightstick Pro, + ThrustMaster FCS or 6 and 8 button gamepads. For more information on + how to use the driver please read Documentation/joystick.txt + +FPGaming and MadCatz A3D controllers +CONFIG_JOY_ASSASIN + Say Y here if you have an FPGaming Assasin 3D, MadCatz Panther or + MadCatz Panther XL. For more information on how to use the driver + please read Documentation/joystick.txt + +Gravis GrIP joysticks and gamepads +CONFIG_JOY_GRAVIS + Say Y here if you have a Gravis GamePad Pro, Gravis Xterminator or + Gravis Blackhawk Digital. For more information on how to use the + driver please read Documentation/joystick.txt + +PDPI Lightning 4 gamecards +CONFIG_JOY_LIGHTNING + Say Y here if you have a PDPI Lightning 4 gamecard and an analog + joystick or gamepad connected to it. For more information on how to + use the driver please read Documentation/joystick.txt + +Logitech Digital joysticks and gamepads +CONFIG_JOY_LOGITECH + Say Y here if you have a Logitech WingMan Extreme Digital, + Logitech ThunderPad Digital or Logitech CyberMan 2. For more + information on how to use the driver please read + Documentation/joystick.txt + +Microsoft SideWinder, Genius Digital joysticks and gamepads +CONFIG_JOY_SIDEWINDER + Say Y here if you have a Microsoft SideWinder 3d Pro, Microsoft + SideWinder Precision Pro, Microsoft SideWinder Force Feedback Pro, + Microsoft Sidewinder GamePad or Genius Flight2000 F-23 Digital. For + more information on how to use the driver please read + Documentation/joystick.txt + +ThrustMaster DirectConnect joysticks and gamepads +CONFIG_JOY_THRUSTMASTER + Say Y here if you have a ThrustMaster Millenium 3D Inceptor or a + ThrustMaster 3D Rage Pad. For more information on how to use the + driver please read Documentation/joystick.txt + +NES, SNES, PSX, Multisystem joysticks and gamepads +CONFIG_JOY_CONSOLE + Say Y here if you have a Nintendo Entertainment System gamepad, + Super Nintendo Entertainment System gamepad, Sony PlayStation + gamepad or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC + joystick. For more information on how to use the driver please read + Documentation/joystick.txt and Documentation/joystick-parport.txt + +Sega, Multisystem joysticks and gamepads +CONFIG_JOY_DB9 + Say Y here if you have a Sega Master System gamepad, Sega Genesis + gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga, + Commodore, Amstrad CPC joystick. For more information on how to use + the driver please read Documentation/joystick.txt and + Documentation/joystick-parport.txt + +TurboGraFX Multisystem joystick interface +CONFIG_JOY_TURBOGRAFX + Say Y here if you have the TurboGraFX interface by Steffen Schwenke, + and want to use it with Multiststem -- Atari, Amiga, Commodore, + Amstrad CPC joystick. For more information on how to use the driver + please read Documentation/joystick.txt and + Documentation/joystick-parport.txt + +Amiga joysticks +CONFIG_JOY_AMIGA + Say Y here if you have an Amiga with a digital joystick connected + to it. For more information on how to use the driver please read + Documentation/joystick.txt + +Atomwide Serial Support +CONFIG_ATOMWIDE_SERIAL + If you have an Atomwide Serial card for an Acorn system, say Y to + this option. The driver can handle 1, 2, or 3 port cards. + If unsure, say N + +The Serial Port Dual Serial Port +CONFIG_DUALSP_SERIAL + If you have the Serial Port's dual serial card for an Acorn system, + say Y to this option. If unsure, say N + +NetWinder Button +CONFIG_NWBUTTON + If you say Y here and create a character device node /dev/nwbutton + with major and minor numbers 10 and 158 ("man mknod"), then every + time the orange button is pressed a number of times, the number of + times the button was pressed will be written to that device. + + This is most useful for applications, as yet unwritten, which + perform actions based on how many times the button is pressed in a + row. + + Do not hold the button down for too long, as the driver does not + alter the behaviour of the hardware reset circuitry attached to the + button; it will still execute a hard reset if the button is held + down for longer than approximately five seconds. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called nwbutton.o. + + Most people will answer Y to this question and "Reboot Using Button" + below to be able to initiate a system shutdown from the button. + +Reboot Using Button +CONFIG_NWBUTTON_REBOOT + If you say Y here, then you will be able to initiate a system + shutdown and reboot by pressing the orange button a number of times. + The number of presses to initiate the shutdown is two by default, + but this can be altered by modifying the value of NUM_PRESSES_REBOOT + in nwbutton.h and recompiling the driver or, if you compile the + driver as a module, you can specify the number of presses at load + time with "insmod button reboot_count=". + +Sound card support +CONFIG_SOUND + If you have a sound card in your computer, i.e. if it can say more + than an occasional beep, say Y. Be sure to have all the information + about your sound card and its configuration down (I/O port, + interrupt and DMA channel), because you will be asked for it. + + You want to read the Sound-HOWTO, available from + http://metalab.unc.edu/mdw/linux.html#howto . General information + about the modular sound system is contained in the files + Documentation/sound/Introduction. The file + Documentation/sound/README.OSS contains some slightly outdated but + still useful information as well. + + If you have a PnP sound card and you want to configure it at boot + time using the ISA PnP tools (read + http://www.roestock.demon.co.uk/isapnptools/ ), then you need to + compile the sound card support as a module ( = code which can be + inserted in and removed from the running kernel whenever you want) + and load that module after the PnP configuration is finished. To do + this, say M here and read Documentation/modules.txt as well as + Documentation/sound/README.modules; the module will be called + soundcore.o. + + I'm told that even without a sound card, you can make your computer + say more than an occasional beep, by programming the PC speaker. + Kernel patches and supporting utilities to do that are in the pcsp + package, available at ftp://ftp.infradead.org/pub/pcsp/. + +OSS sound modules +CONFIG_SOUND_OSS + OSS is the Open Sound System suite of sound card drivers. They make + sound programming easier since they provide a common API. Say Y or M + here (the module will be called sound.o) if you haven't found a + driver for your sound card above, then pick your driver from the + list below. + +Persistent DMA buffers +CONFIG_SOUND_DMAP + Linux can often have problems allocating DMA buffers for ISA sound + cards on machines with more than 16MB of RAM. This is because ISA + DMA buffers must exist below the 16MB boundary and it is quite + possible that a large enough free block in this region cannot be + found after the machine has been running for a while. If you say Y + here the DMA buffers (64Kb) will be allocated at boot time and kept + until the shutdown. This option is only useful if you said Y to + "OSS sound modules", above. If you said M to "OSS sound modules" + then you can get the persistent DMA buffer functionality by passing + the command-line argument "dmabuf=1" to the sound.o module. + + Say Y unless you have 16MB or less RAM or a PCI sound card. + +Support for Aztech Sound Galaxy (non-PnP) cards +CONFIG_SOUND_SGALAXY + This module initializes the older non Plug and Play sound galaxy + cards from Aztech. It supports the Waverider Pro 32 - 3D and the + Galaxy Washington 16. + +Support for AD1816(A) based cards (EXPERIMENTAL) +CONFIG_SOUND_AD1816 + Say M here if you have a sound card based on the Analog Devices + AD1816(A) chip. + + NOTE: This driver is still EXPERIMENTAL. + See Documentation/sound/AD1816 for further information. + +Yamaha OPL3-SA1 audio controller +CONFIG_SOUND_OPL3SA1 + Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is + usually built into motherboards. Read Documentation/sound/OPL3-SA + for details. + +ProAudioSpectrum 16 support +CONFIG_SOUND_PAS + Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio + 16 or Logitech SoundMan 16 sound card. Don't answer Y if you have + some other card made by Media Vision or Logitech since they are not + PAS16 compatible. + +100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support +CONFIG_SOUND_SB + Answer Y if you have an original Sound Blaster card made by Creative + Labs or a 100% hardware compatible clone (like the Thunderboard or + SM Games). For an unknown card you may answer Y if the card claims + to be Sound Blaster-compatible. + + Please read the file Documentation/sound/Soundblaster. + + You should also say Y here for cards based on the Avance Logic + ALS-007 chip (read Documentation/sound/ALS007) and for cards based + on ESS chips (read Documentation/sound/ESS1868 and + Documentation/sound/ESS). If you have an SB AWE 32 or SB AWE 64, say + Y here and also to "Additional lowlevel drivers" and to "SB32/AWE + support" below and read Documentation/sound/INSTALL.awe. If you have + an IBM Mwave card, say Y here and read Documentation/sound/mwave. + + You can say M here to compile this driver as a module; the module is + called sb.o. + +Generic OPL2/OPL3 FM synthesizer support +CONFIG_SOUND_ADLIB + Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). + Answering Y is usually a safe and recommended choice, however some + cards may have software (TSR) FM emulation. Enabling FM support with + these cards may cause trouble (I don't currently know of any such + cards, however). + + Please read the file Documentation/sound/OPL3 if your card has an + OPL3 chip. + + If unsure, say Y. + + +#Loopback MIDI device support +#CONFIG_SOUND_VMIDI +### +### somebody please fill this in. +### +# +Gravis Ultrasound support +CONFIG_SOUND_GUS + Say Y here for any type of Gravis Ultrasound card, including + the GUS or GUS MAX. See also Documentation/sound/ultrasound for + more information on configuring this card with modules. + +MPU-401 support (NOT for SB16) +CONFIG_SOUND_MPU401 + Be careful with this question. The MPU401 interface is supported by + all sound cards. However, some natively supported cards have their + own driver for MPU401. Enabling this MPU401 option with these cards + will cause a conflict. Also, enabling MPU401 on a system that + doesn't really have a MPU401 could cause some trouble. If your card + was in the list of supported cards, look at the card specific + instructions in the drivers/sound/Readme.cards file. It's safe to + answer Y if you have a true MPU401 MIDI interface card. + +6850 UART support +CONFIG_SOUND_UART6850 + This option enables support for MIDI interfaces based on the 6850 + UART chip. This interface is rarely found on sound cards. It's safe + to answer N to this question. + +VIDC Sound +CONFIG_VIDC_SOUND + Say Y here for ARM systems with the VIDC video controller and 16-bit + Linear sound DACs. If unsure, say N. + +PSS (AD1848, ADSP-2115, ESC614) support +CONFIG_SOUND_PSS + Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven + ADSP-16 or some other card based on the PSS chipset (AD1848 codec + + ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on + how to compile it into the kernel or as a module see the file + Documentation/sound/PSS. + +Enable PSS mixer (Beethoven ADSP-16 and other compatible) +CONFIG_PSS_MIXER + Answer Y for Beethoven ADSP-16. You may try to say Y also for other + cards if they have master volume, bass, treble, and you can't + control it under Linux. If you answer N for Beethoven ADSP-16, you + can't control master volume, bass, treble and synth volume. + + If you said M to "PSS support" above, you may enable or disable this + PSS mixer with the module parameter pss_mixer. For more information + see the file Documentation/sound/PSS. + +Have DSPxxx.LD firmware file +CONFIG_PSS_HAVE_BOOT + If you have the DSPxxx.LD file or SYNTH.LD file for you card, say Y + to include this file. Without this file the synth device (OPL) may + not work. + +Full pathname of DSPxxx.LD firmware file +CONFIG_PSS_BOOT_FILE + Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file, + starting from /. + +16 bit sampling option of GUS (_NOT_ GUS MAX) +CONFIG_SOUND_GUS16 + Answer Y if you have installed the 16 bit sampling daughtercard on + your GUS. Answer N if you have a GUS MAX, since saying Y here + disables GUS MAX support. + +GUS MAX support +CONFIG_SOUND_GUSMAX + Answer Y only if you have a Gravis Ultrasound MAX. + +Microsoft Sound System support +CONFIG_SOUND_MSS + Again think carefully before answering Y to this question. It's safe + to answer Y if you have the original Windows Sound System card made + by Microsoft or Aztech SG 16 Pro (or NX16 Pro). Also you may say Y + in case your card is NOT among these: + + ATI Stereo F/X, AdLib, Audio Excell DSP16, Cardinal DSP16, + Ensoniq SoundScape (and compatibles made by Reveal and Spea), + Gravis Ultrasound, Gravis Ultrasound ACE, Gravis Ultrasound Max, + Gravis Ultrasound with 16 bit option, Logitech Sound Man 16, + Logitech SoundMan Games, Logitech SoundMan Wave, MAD16 Pro (OPTi + 82C929), Media Vision Jazz16, MediaTriX AudioTriX Pro, Microsoft + Windows Sound System (MSS/WSS), Mozart (OAK OTI-601), Orchid + SW32, Personal Sound System (PSS), Pro Audio Spectrum 16, Pro + Audio Studio 16, Pro Sonic 16, Roland MPU-401 MIDI interface, + Sound Blaster 1.0, Sound Blaster 16, Sound Blaster 16ASP, Sound + Blaster 2.0, Sound Blaster AWE32, Sound Blaster Pro, TI TM4000M + notebook, ThunderBoard, Turtle Beach Tropez, Yamaha FM + synthesizers (OPL2, OPL3 and OPL4), 6850 UART MIDI Interface. + + For cards having native support in VoxWare, consult the card + specific instructions in drivers/sound/Readme.cards. Some drivers + have their own MSS support and saying Y to this option will cause a + conflict. + +SGI Visual Workstation on-board audio +CONFIG_SOUND_VWSND + Say Y or M if you have an SGI Visual Workstation and you want to + be able to use its on-board audio. Read Documentation/sound/visws + for more info on this driver's capabilities. + +Ensoniq Soundscape support +CONFIG_SOUND_SSCAPE + Answer Y if you have a sound card based on the Ensoniq SoundScape + chipset. Such cards are being manufactured at least by Ensoniq, Spea + and Reveal (Reveal makes also other cards). + +MediaTriX AudioTriX Pro support +CONFIG_SOUND_TRIX + Answer Y if you have the AudioTriX Pro sound card manufactured + by MediaTrix. + +Have TRXPRO.HEX firmware file +CONFIG_TRIX_HAVE_BOOT + The MediaTrix AudioTrix Pro has an on-board microcontroller which + needs to be initialized by downloading the code from the file + TRXPRO.HEX in the DOS driver directory. If you don't have the + TRXPRO.HEX file handy you may skip this step. However, the SB and + MPU-401 modes of AudioTrix Pro will not work without this file! + +Full pathname of TRXPRO.HEX firmware file +CONFIG_TRIX_BOOT_FILE + Enter the full pathname of your TRXPRO.HEX file, starting from /. + +Support for OPTi MAD16 and/or Mozart based cards +CONFIG_SOUND_MAD16 + Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi + 82C928 or 82C929 or 82C931) audio interface chip. For the 82C931, + please read drivers/sound/README.C931. These chips are currently + quite common so it's possible that many no-name cards have one of + them. In addition the MAD16 chip is used in some cards made by known + manufacturers such as Turtle Beach (Tropez), Reveal (some models) + and Diamond (latest ones). Note however that the Tropez sound cards + have their own driver; if you have one of those, say N here and Y or + M to "Full support for Turtle Beach WaveFront", below. + + See also Documentation/sound/Opti and Documentation/sound/MAD16 for + more information on setting these cards up as modules. + +Full support for Turtle Beach WaveFront synth/sound cards +CONFIG_SOUND_WAVEFRONT + Answer Y or M if you have a Tropez Plus, Tropez or Maui sound card + and read the files Documentation/sound/Wavefront and + Documentation/sound/Tropez+. + +Support MIDI in older MAD16 based cards (requires SB) +CONFIG_MAD16_OLDCARD + Answer Y (or M) if you have an older card based on the C928 or + Mozart chipset and you want to have MIDI support. If you enable this + option you also need to enable support for Sound Blaster. + +Support for Crystal CS4232 based (PnP) cards +CONFIG_SOUND_CS4232 + Say Y here if you have a card based on the Crystal CS4232 chip set, + which uses its own Plug and Play protocol. + + See Documentation/sound/CS4232 for more information on configuring + this card. + +Support for Yamaha OPL3-SA2, SA3, and SAx based PnP cards +CONFIG_SOUND_OPL3SA2 + Say Y or M if you have a card based on one of these Yamaha + sound chipsets. Read Documentation/sound/OPL3-SA2 for more + information on configuring these cards. + +Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers +CONFIG_SOUND_MAUI + Say Y here if you have a Turtle Beach Wave Front, Maui, or Tropez + sound card. + +Have OSWF.MOT firmware file +CONFIG_MAUI_HAVE_BOOT + Turtle Beach Maui and Tropez sound cards have a microcontroller + which needs to be initialized prior to use. OSWF.MOT is a file + distributed with the card's DOS/Windows drivers. Answer Y if you + have this file. + +Full pathname of OSWF.MOT firmware file +CONFIG_MAUI_BOOT_FILE + Enter the full pathname of your OSWF.MOT file, starting from /. + +Support for Turtle Beach MultiSound Classic, Tahiti, Monterey +CONFIG_SOUND_MSNDCLAS + Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or + Monterey (not for the Pinnacle or Fiji). + + See Documentation/sound/MultiSound for important information about + this driver. + +Full pathname of MSNDINIT.BIN firmware file +CONFIG_MSNDCLAS_INIT_FILE + The MultiSound cards have two firmware files which are required for + operation, and are not currently included. These files can be + obtained from Turtle Beach. See Documentation/sound/MultiSound for + information on how to obtain this. + +Full pathname of MSNDPERM.BIN firmware file +CONFIG_MSNDCLAS_PERM_FILE + The MultiSound cards have two firmware files which are required for + operation, and are not currently included. These files can be + obtained from Turtle Beach. See Documentation/sound/MultiSound for + information on how to obtain this. + +Support for Turtle Beach MultiSound Pinnacle, Fiji +CONFIG_SOUND_MSNDPIN + Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. + See Documentation/sound/MultiSound for important information about + this driver. + +Full pathname of PNDSPINI.BIN firmware file +CONFIG_MSNDPIN_INIT_FILE + The MultiSound cards have two firmware files which are required for + operation, and are not currently included. These files can be + obtained from Turtle Beach. See Documentation/sound/MultiSound for + information on how to obtain this. + +Full pathname of PNDSPERM.BIN firmware file +CONFIG_MSNDPIN_PERM_FILE + The MultiSound cards have two firmware files which are required for + operation, and are not currently included. These files can be + obtained from Turtle Beach. See Documentation/sound/MultiSound for + information on how to obtain this. + +MSND Pinnacle have S/PDIF I/O +CONFIG_MSNDPIN_DIGITAL + If you have the S/PDIF daughter board for the Pinnacle or Fiji, + answer Y here; otherwise, say N. If you have this, you will be able + to play and record from the S/PDIF port (digital signal). See + Documentation/sound/MultiSound for information on how to make use of + this capability. + +MSND Pinnacle non-PnP Mode +CONFIG_MSNDPIN_NONPNP + The Pinnacle and Fiji card resources can be configured either with + PnP, or through a configuration port. Say Y here if your card is NOT + in PnP mode. For the Pinnacle, configuration in non-PnP mode allows + use of the IDE and joystick peripherals on the card as well; these + do not show up when the card is in PnP mode. Specifying zero for any + resource of a device will disable the device. If you are running the + card in PnP mode, you must say N here and use isapnptools to + configure the card's resources. + +MSND Pinnacle config port +CONFIG_MSNDPIN_CFG + This is the port which the Pinnacle and Fiji uses to configure the + card's resources when not in PnP mode. If your card is in PnP mode, + then be sure to say N to the previous option, "MSND Pinnacle Non-PnP + Mode". + +MSND buffer size (kB) +CONFIG_MSND_FIFOSIZE + Configures the size of each audio buffer, in kilobytes, for + recording and playing in the MultiSound drivers (both the Classic + and Pinnacle). Larger values reduce the chance of data overruns at + the expense of overall latency. If unsure, use the default. + +/dev/dsp and /dev/audio support +CONFIG_SOUND_AUDIO + If you say Y here, you will get the /dev/dsp and /dev/audio devices; + these are the analog-digital and digital-analog converter devices + and are very useful, so say Y. + +MIDI interface support +CONFIG_SOUND_MIDI + Answering N disables /dev/midixx devices and access to any MIDI + ports using /dev/sequencer and /dev/music. This option also affects + any MPU401 and/or General MIDI compatible devices. Answer Y. + +FM synthesizer (YM3812/OPL-3) support +CONFIG_SOUND_YM3812 + Answer Y here, unless you know you will not need the option. + +Sun Audio support +CONFIG_SUN_AUDIO + This is support for the sound cards on Sun workstations. The code + does not exist yet, so you might as well say N here. + +Additional low level drivers +CONFIG_LOWLEVEL_SOUND + If you need additional low level sound drivers which have not yet + appeared, say Y. The answer to this question does not directly + affect the kernel; saying Y will simply cause this configure script + to present you with more options. If unsure, say Y. + +ACI mixer (miroPCM12/PCM20) +CONFIG_ACI_MIXER + ACI (Audio Command Interface) is a protocol used to communicate with + the microcontroller on some sound cards produced by miro, e.g. the + miroSOUND PCM12 and PCM20. The main function of the ACI is to + control the mixer and to get a product identification. + + This Voxware ACI driver currently only supports the ACI functions on + the miroSOUND PCM12 and PCM20 cards. On the PCM20, ACI also controls + the radio tuner. This is supported in the video4linux + radio-miropcm20 driver. + +SB32/AWE support +CONFIG_AWE32_SYNTH + Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or + similar sound card. See Documentation/sound/README.awe, + Documentation/sound/AWE32 and the Soundblaster-AWE mini-HOWTO, + available from http://metalab.unc.edu/mdw/linux.html#howto for more + info. + +Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600) +CONFIG_AEDSP16 + Answer Y if you have a Gallant's Audio Excel DSP 16 card. This + driver supports Audio Excel DSP 16 but not the III nor PnP versions + of this card. + + The Gallant's Audio Excel DSP 16 card can emulate either an SBPro or + a Microsoft Sound System card, so you should have said Y to either + "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" + or "Microsoft Sound System support", above, and you need to answer + the "MSS emulation" and "SBPro emulation" questions below + accordingly. You should say Y to one and only one of these two + questions. + + Read the drivers/sound/lowlevel/README.aedsp16 file and the head of + drivers/sound/lowlevel/aedsp16.c as well as + Documentation/sound/AudioExcelDSP16 to get more information about + this driver and its configuration. + +I/O base for Audio Excel DSP 16 +CONFIG_AEDSP16_BASE + This is the base I/O address of the Audio Excel DSP 16 card. It must + be 220 or 240. If you compiled aedsp16.o as a module you can specify + this parameter as 'io=0xNNN'. + +Audio Excel DSP 16 (SBPro emulation) +CONFIG_AEDSP16_SBPRO + Answer Y if you want your audio card to emulate Sound Blaster Pro. + You should then say Y to "100% Sound Blaster compatibles + (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS + emulation)". + +Audio Excel DSP 16 IRQ +CONFIG_AEDSP16_SB_IRQ + This is the IRQ of the Audio Excel DSP 16 card. It must be 5, 7, 9, + 10 or 11. If you compiled aedsp16.o as a module you can specify + this parameter as 'irq=NN'. + +Audio Excel DSP 16 DMA +CONFIG_AEDSP16_SB_DMA + This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 or + 3. If you compiled aedsp16.o as a module you can specify this + parameter as 'dma=NN'. + +Audio Excel DSP 16 (MSS emulation) +CONFIG_AEDSP16_MSS + Answer Y if you want your audio card to emulate Microsoft Sound + System. You should then say Y to "Microsoft Sound System support" + and say N to "Audio Excel DSP 16 (SBPro emulation)". + +Audio Excel DSP 16 IRQ +CONFIG_AEDSP16_MSS_IRQ + This is the IRQ of the Audio Excel DSP 16 card. It must be 5, 7, 9, + 10 or 11. If you compiled aedsp16.o as a module you can specify + this parameter as 'irq=NN'. + +Audio Excel DSP 16 DMA +CONFIG_AEDSP16_MSS_DMA + This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 + or 3. If you compiled aedsp16.o as a module you can specify this + parameter as 'dma=NN'. + +SC-6600 based audio cards (new Audio Excel DSP 16) +CONFIG_SC6600 + The SC6600 is the new version of DSP mounted on the Audio Excel DSP + 16 cards. Find in the manual the FCC ID of your audio card and + answer Y if you have an SC6600 DSP. + +SC-6600 Joystick Interface +CONFIG_SC6600_JOY + Say Y here in order to use the joystick interface of the Audio Excel + DSP 16 card. + +SC-6600 CDROM Interface +CONFIG_SC6600_CDROM + This is used to activate the the CDROM interface of the Audio Excel + DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no + CDROM present. + +Audio Excel DSP 16 (MPU401 emulation) +CONFIG_AEDSP16_MPU401 + Answer Y if you want your audio card to emulate the MPU-401 midi + interface. You should then also say Y to "MPU-401 support". + + Note that the I/O base for MPU-401 support of aedsp16 is the same + you have selected for "MPU-401 support". If you are using this + driver as a module you have to specify the MPU I/O base address with + the parameter 'mpu_base=0xNNN'. + +MPU401 IRQ for Audio Excel DSP 16 +CONFIG_AEDSP16_MPU_IRQ + This is the IRQ of the MPU-401 emulation of your Audio Excel DSP 16 + card. It must be 5, 7, 9, 10 or 0 (to disable MPU-401 interface). If + you compiled aedsp16.o as a module you can specify this parameter as + 'mpu_irq=NN'. + +Ensoniq ES1370 based PCI sound cards +CONFIG_SOUND_ES1370 + Say Y or M if you have a PCI sound card utilizing the Ensoniq + ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find + out if your sound card uses an ES1370 without removing your + computer's cover, use lspci -n and look for the PCI ID + 1274:5000. Since Ensoniq was bought by Creative Labs, + Sound Blaster 64/PCI models are either ES1370 or ES1371 based. + This driver differs slightly from OSS/Free, so PLEASE READ + Documentation/sound/es1370. + +Ensoniq ES1371 based PCI sound cards +CONFIG_SOUND_ES1371 + Say Y or M if you have a PCI sound card utilizing the Ensoniq + ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if + your sound card uses an ES1371 without removing your computer's + cover, use lspci -n and look for the PCI ID 1274:1371. Since + Ensoniq was bought by Creative Labs, Sound Blaster 64/PCI + models are either ES1370 or ES1371 based. This driver differs + slightly from OSS/Free, so PLEASE READ Documentation/sound/es1371. + +ESS Solo1 based PCI sound cards (eg. SC1938) +CONFIG_SOUND_ESSSOLO1 + Say Y or M if you have a PCI sound card utilizing the ESS Technology + Solo1 chip. To find out if your sound card uses a + Solo1 chip without removing your computer's cover, use + lspci -n and look for the PCI ID 125D:1969. This driver + differs slightly from OSS/Free, so PLEASE READ + Documentation/sound/solo1. + +S3 SonicVibes based PCI sound cards +CONFIG_SOUND_SONICVIBES + Say Y or M if you have a PCI sound card utilizing the S3 + SonicVibes chipset. To find out if your sound card uses a + SonicVibes chip without removing your computer's cover, use + lspci -n and look for the PCI ID 5333:CA00. This driver + differs slightly from OSS/Free, so PLEASE READ + Documentation/sound/sonicvibes. + +Rockwell WaveArtist +CONFIG_SOUND_WAVEARTIST + Say Y here to include support for the Rockwell WaveArtist sound + system. This driver is mainly for the NetWinder. + +VIA 82Cxxx Audio Codec +CONFIG_SOUND_VIA82CXXX + Say Y here to include support for the audio codec found on + VIA 82Cxxx-based chips. Typically these are built into a motherboard. + DO NOT select SoundBlaster or Adlib with this driver, unless you have + a SoundBlaster or Adlib card in addition to your VIA audio chip. + +NeoMagic 256AV/256ZX sound chipsets +CONFIG_SOUND_NM256 + Say M here to include audio support for the NeoMagic 256AV/256ZX + chipsets. These are the audio chipsets found in the Sony Z505S/SX/DX, + some Sony F-series, and the Dell Latitude CPi and CPt laptops. It includes + support for an AC97-compatible mixer and an apparently proprietary sound + engine. + + See Documentation/sound/NM256 for further information. + +Are you using a crosscompiler +CONFIG_CROSSCOMPILE + Say Y here if you are compiling the kernel on a different + architecture than the one it is intended to run on. + +Build fp exception handler module +CONFIG_MIPS_FPE_MODULE + Build the floating point exception handler module. This option is + only useful for people working on the floating point exception + handler. If you don't, say N. + +Remote GDB kernel debugging +CONFIG_REMOTE_DEBUG + If you say Y here, it will be possible to remotely debug the MIPS + kernel using gdb. This enlarges your kernel image disk size by + several megabytes and requires a machine with more than 16 MB, + better 32 MB RAM to avoid excessive linking time. This is only + useful for kernel hackers. If unsure, say N. + +Magic System Request Key support +CONFIG_MAGIC_SYSRQ + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). This is accomplished + by pressing various keys while holding SysRq (Alt+PrintScreen). The + keys are documented in Documentation/sysrq.txt. Don't say Y unless + you really know what this hack does. + +ISDN subsystem +CONFIG_ISDN + ISDN ("Integrated Services Digital Networks", called RNIS in France) + is a special type of fully digital telephone service; it's mostly + used to connect to your Internet service provider (with SLIP or + PPP). The main advantage is that the speed is higher than ordinary + modem/telephone connections, and that you can have voice + conversations while downloading stuff. It only works if your + computer is equipped with an ISDN card and both you and your service + provider purchased an ISDN line from the phone company. For details, + read http://alumni.caltech.edu/~dank/isdn/ on the WWW. + + This driver allows you to use an ISDN-card for networking + connections and as dialin/out device. The isdn-tty's have a built in + AT-compatible modem emulator. Network devices support autodial, + channel-bundling, callback and caller-authentication without having + a daemon running. A reduced T.70 protocol is supported with tty's + suitable for German BTX. On D-Channel, the protocols EDSS1 + (Euro-ISDN) and 1TR6 (German style) are supported. See + Documentation/isdn/README for more information. + + If you want to compile the ISDN code as a module ( = code which can + be inserted in and removed from the running kernel whenever you + want), say M here and read Documentation/modules.txt. The module + will be called isdn.o. If unsure, say N. + +Support synchronous PPP +CONFIG_ISDN_PPP + Over digital connections such as ISDN, there is no need to + synchronize sender and recipient's clocks with start and stop bits + as is done over analog telephone lines. Instead, one can use + "synchronous PPP". Saying Y here will include this protocol. This + protocol is used by Cisco and Sun for example. So you want to say Y + here if the other end of your ISDN connection supports it. You will + need a special version of pppd (called ipppd) for using this + feature. See Documentation/isdn/README.syncppp and + Documentation/isdn/syncPPP.FAQ for more information. + +Support generic MP (RFC 1717) +CONFIG_ISDN_MPP + With synchronous PPP enabled, it is possible to increase throughput + by bundling several ISDN-connections, using this protocol. See + Documentation/isdn/README.syncppp for more information. + +Use VJ-compression with synchronous PPP +CONFIG_ISDN_PPP_VJ + This enables Van Jacobson header compression for synchronous PPP. + Say Y if the other end of the connection supports it. + +Support audio via ISDN +CONFIG_ISDN_AUDIO + If you say Y here, the modem-emulator will support a subset of the + EIA Class 8 Voice commands. Using a getty with voice-support + (mgetty+sendfax by gert@greenie.muc.de with an extension, available + with the ISDN utility package for example), you will be able to use + your Linux box as an ISDN-answering machine. Of course, this must be + supported by the lowlevel driver also. Currently, the HiSax driver + is the only voice-supporting driver. See + Documentation/isdn/README.audio for more information. + +X.25 PLP on top of ISDN +CONFIG_ISDN_X25 + This feature provides the X.25 protocol over ISDN connections. + See Documentation/isdn/README.x25 for more information + if you are thinking about using this. + +ISDN diversion services support +CONFIG_ISDN_DIVERSION + This option allows you to use some supplementary diversion + services in conjunction with the HiSax driver on an EURO/DSS1 + line. + + Supported options are CD (call deflection), CFU (Call forward + unconditional), CFB (Call forward when busy) and CFNR (call forward + not reachable). Additionally the actual CFU, CFB and CFNR state may + be interrogated. + + The use of CFU, CFB, CFNR and interrogation may be limited to some + countries. The keypad protocol is still not implemented. CD should + work in all countries if the service has been subscribed to. + + Please read the file Documentation/isdn/README.diversion. + +ICN 2B and 4B support +CONFIG_ISDN_DRV_ICN + This enables support for two kinds of ISDN-cards made by a German + company called ICN. 2B is the standard version for a single ISDN + line with two B-channels, 4B supports two ISDN lines. For running + this card, additional firmware is necessary, which has to be + downloaded into the card using a utility which is distributed + separately. See Documentation/isdn/README and README.icn for more + information. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called icn.o. + +isdnloop support +CONFIG_ISDN_DRV_LOOP + This driver provides a virtual ISDN card. Its primary purpose is + testing of linklevel features or configuration without getting + charged by your service-provider for lots of phone calls. + You need will need the loopctrl utility from the latest isdn4k-utils + package to set up this driver. + +HiSax SiemensChipSet driver support +CONFIG_ISDN_DRV_HISAX + This is a driver supporting the Siemens chipset on various + ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles + S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many + compatibles). + + HiSax is just the name of this driver, not the name of any hardware. + + If you have a card with such a chipset, you should say Y here and + also to the configuration option of the driver for your particular + card, below. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called hisax.o. See Documentation/isdn/README.HiSax for more + information on using this driver. + +HiSax Support for EURO/DSS1 +CONFIG_HISAX_EURO + Enable this if you have a EURO ISDN line. + +Support for german chargeinfo +CONFIG_DE_AOC + If you have german AOC, you can enable this to get the charginfo. + +Disable sending complete +CONFIG_HISAX_NO_SENDCOMPLETE + If you have trouble with some ugly exchanges or you live in + Australia select this option. + +Disable sending low layer compatibility +CONFIG_HISAX_NO_LLC + If you have trouble with some ugly exchanges try to select this + option. + +HiSax Support for german 1TR6 +CONFIG_HISAX_1TR6 + Enable this if you have a old german 1TR6 line. + +HiSax Support for Teles 16.0/8.0 +CONFIG_HISAX_16_0 + This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 + and many compatibles. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port/shmem settings. + +HiSax Support for Teles 16.3 or PNP or PCMCIA +CONFIG_HISAX_16_3 + This enables HiSax support for the Teles ISDN-cards S0-16.3 the + Teles/Creatix PnP and the Teles PCMCIA. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for Teles PCI +CONFIG_HISAX_TELESPCI + This enables HiSax support for the Teles PCI. + See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for Teles S0Box +CONFIG_HISAX_S0BOX + This enables HiSax support for the Teles/Creatix parallel port + S0BOX. See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for AVM A1 (Fritz) +CONFIG_HISAX_AVM_A1 + This enables HiSax support for the AVM A1 (aka "Fritz"). + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for AVM PnP/PCI (Fritz!PNP/PCI) +CONFIG_HISAX_FRITZPCI + This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI". + See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for AVM A1 PCMCIA (Fritz) +CONFIG_HISAX_AVM_A1_PCMCIA + This enables HiSax support for the AVM A1 "Fritz!PCMCIA"). + See Documentation/isdn/README.HiSax on how to configure it. + +HiSax Support for Elsa cards +CONFIG_HISAX_ELSA + This enables HiSax support for the Elsa Mircolink ISA cards, for the + Elsa Quickstep series cards and Elsa PCMCIA. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for ITK ix1-micro Revision 2 +CONFIG_HISAX_IX1MICROR2 + This enables HiSax support for the ITK ix1-micro Revision 2 card. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for Eicon.Diehl Diva cards +CONFIG_HISAX_DIEHLDIVA + This enables HiSax support for the Eicon.Diehl Diva none PRO + versions passive ISDN cards. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for ASUSCOM cards +CONFIG_HISAX_ASUSCOM + This enables HiSax support for the AsusCom and their OEM versions + passive ISDN cards. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for TELEINT cards +CONFIG_HISAX_TELEINT + This enables HiSax support for the TELEINT SA1 semiactiv ISDN card. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for HFC-S based cards +CONFIG_HISAX_HFCS + This enables HiSax support for the HFC-S 2BDS0 based cards, like + teles 16.3c. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for Sedlbauer cards +CONFIG_HISAX_SEDLBAUER + This enables HiSax support for the Sedlbauer passive ISDN cards. + + See Documentation/isdn/README.HiSax on how to configure it using the + different cards, a different D-channel protocol, or non-standard + IRQ/port settings. + +HiSax Support for USR Sportster internal TA +CONFIG_HISAX_SPORTSTER + This enables HiSax support for the USR Sportster internal TA card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for MIC card +CONFIG_HISAX_MIC + This enables HiSax support for the ITH MIC card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for NETjet card +CONFIG_HISAX_NETJET + This enables HiSax support for the NetJet from Traverse + Technologies. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for Niccy PnP/PCI card +CONFIG_HISAX_NICCY + This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for Siemens I-Surf card +CONFIG_HISAX_ISURF + This enables HiSax support for the Siemens I-Talk/I-Surf card with + ISAR chip. + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for HST Saphir card +CONFIG_HISAX_HSTSAPHIR + This enables HiSax support for the HST Saphir card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for Telekom A4T card +CONFIG_HISAX_BKM_A4T + This enables HiSax support for the Telekom A4T card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for Scitel Quadro card +CONFIG_HISAX_SCT_QUADRO + This enables HiSax support for the Scitel Quadro card. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for Gazel cards +CONFIG_HISAX_GAZEL + This enables HiSax support for the Gazel cards. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for HFC PCI-Bus cards +CONFIG_HISAX_HFC_PCI + This enables HiSax support for the HFC-S PCI 2BDS0 based cards. + + For more informations see under Documentation/isdn/README.hfc-pci. + +HiSax Support for Winbond W6692 based cards +CONFIG_HISAX_W6692 + This enables HiSax support for Winbond W6692 based PCI ISDN cards. + + See Documentation/isdn/README.HiSax on how to configure it using a + different D-channel protocol, or non-standard IRQ/port settings. + +HiSax Support for Am7930 (EXPERIMENTAL) +CONFIG_HISAX_AMD7930 + This enables HiSax support for the AMD7930 chips on some SPARCs. + This code is not finished yet. + +PCBIT-D support +CONFIG_ISDN_DRV_PCBIT + This enables support for the PCBIT ISDN-card. This card is + manufactured in Portugal by Octal. For running this card, additional + firmware is necessary, which has to be downloaded into the card + using a utility which is distributed separately. See + Documentation/isdn/README and Documentation/isdn/README.pcbit for + more information. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called pcbit.o. + +Spellcaster support (EXPERIMENTAL) +CONFIG_ISDN_DRV_SC + This enables support for the Spellcaster BRI ISDN boards. This + driver currently builds only in a modularized version ( = code which + can be inserted in and removed from the running kernel whenever you + want, details in Documentation/modules.txt); the module will be + called sc.o. See Documentation/isdn/README.sc and + http://www.spellcast.com for more information. + +Eicon.Diehl active card support +CONFIG_ISDN_DRV_EICON + Say Y here if you have an Eicon active ISDN card. In order to use + this card, additional firmware is necessary, which has to be loaded + into the card using the eiconctrl utility which is part of the + latest isdn4k-utils package. Please read the file + Documentation/isdn/README.eicon for more information. + +Eicon old-type card support +CONFIG_ISDN_DRV_EICON_ISA + Say Y here if you have an old-type Eicon active ISDN card. In order + to use this card, additional firmware is necessary, which has to be + loaded into the card using the eiconctrl utility which is part of + the latest isdn4k-utils package. Please read the file + Documentation/isdn/README.eicon for more information. + +Support AT-Fax Class 2 commands +CONFIG_ISDN_TTY_FAX + If you say Y here, the modem-emulator will support a subset of the + Fax Class 2 commands. Using a getty with fax-support + (mgetty+sendfax, hylafax), you will be able to use your Linux box as + an ISDN-fax-machine. This must be supported by the lowlevel driver + also. See Documentation/isdn/README.fax for more information. + +AVM CAPI2.0 support +CONFIG_ISDN_DRV_AVMB1 + This enables support for the AVM B1/T1 ISDN networking cards.In + addition, a CAPI (Common ISDN Application Programming Interface, a + standard making it easy for programs to access ISDN hardware, see + http://www.capi.org/; to browse the WWW, you need to have access to + a machine on the Internet that has a program like lynx or netscape) + interface for this card is provided. In order to use this card, + additional firmware is necessary, which has to be downloaded into + the card using a utility which is distributed separately. Please + read the file Documentation/isdn/README.avmb1. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called avmb1.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +AVM B1 ISA support +CONFIG_ISDN_DRV_AVMB1_B1ISA + Enable support for the ISA version of the AVM B1 card. + +AVM B1 PCI support +CONFIG_ISDN_DRV_AVMB1_B1PCI + Enable support for the PCI version of the AVM B1 card. + +AVM T1/T1-B ISA support +CONFIG_ISDN_DRV_AVMB1_T1ISA + Enable support for the AVM T1 T1B card. + Note: This is a PRI card and handle 30 B-channels. + +AVM B1/M1/M2 PCMCIA support +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA + Enable support for the PCMCIA version of the AVM B1 card. + +AVM T1/T1-B PCI support +CONFIG_ISDN_DRV_AVMB1_T1PCI + Enable support for the AVM T1 T1B card. + Note: This is a PRI card and handle 30 B-channels. + +Verbose reason code reporting (kernel size +=7K) +CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON + If you say Y here, the AVM B1 driver will give verbose reasons for + disconnecting. This will increase the size of the kernel by 7 KB. If + unsure, say Y. + + +IBM Active 2000 support (EXPERIMENTAL) +CONFIG_ISDN_DRV_ACT2000 + Say Y here if you have an IBM Active 2000 ISDN card. In order to use + this card, additional firmware is necessary, which has to be loaded + into the card using a utility which is part of the latest + isdn4k-utils package. Please read the file + Documentation/isdn/README.act2000 for more information. + +Support for AP1000 multicomputer +CONFIG_AP1000 + This enables support for a SPARC based parallel multi-computer + called AP1000+. For details on our efforts to port Linux to this + machine see http://cap.anu.edu.au/cap/projects/linux or mail to + hackers@cafe.anu.edu.au + +Support for Sun4 architecture +CONFIG_SUN4 + Say Y here if, and only if, your machine is a Sun4. Note that + a kernel compiled with this option will run only on Sun4. + (And the current version will probably work only on sun4/330.) + +SPARC ESP SCSI support +CONFIG_SCSI_SUNESP + This is the driver for the Sun ESP SCSI host adapter. The ESP + chipset is present in most SPARC-based computers. + +SPARC /dev/openprom compatibility driver (EXPERIMENTAL) +CONFIG_SUN_OPENPROMIO + This driver provides user programs with an interface to the SPARC + PROM device tree. The driver implements a SunOS-compatible + interface and a NetBSD-compatible interface. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M and read Documentation/modules.txt. If unsure, say Y. + +Mostek real time clock support +CONFIG_SUN_MOSTEK_RTC + The Mostek RTC chip is used on all knows Sun computers except + some JavaStations. For a JavaStation you need to say Y both here + and to "Enhanced Real Time Clock Support". + + Say Y here unless you are building a special purpose kernel. + +#Siemens SAB82532 serial support +#CONFIG_SAB82532 +### +### Please someone fill these in. +### + +# +# m68k-specific kernel options +# Documented by Chris Lawrence et al. +# +Amiga support +CONFIG_AMIGA + This option enables support for the Amiga series of computers. If + you plan to use this kernel on an Amiga, say Y here and browse the + material available in Documentation/m68k; otherwise say N. + +Atari support +CONFIG_ATARI + This option enables support for the 68000-based Atari series of + computers (including the TT, Falcon and Medusa). If you plan to use + this kernel on an Atari, say Y here and browse the material + available in Documentation/m68k; otherwise say N. + +Hades support +CONFIG_HADES + This option enables support for the Hades Atari clone. If you plan + to use this kernel on a Hades, say Y here; otherwise say N. + +Macintosh support +CONFIG_MAC + This option enables support for the Apple Macintosh series of + computers (yes, there is experimental support now, at least for part + of the series). + + Say N unless you're willing to code the remaining necessary support. + ;) + +HP9000/300 support +CONFIG_HP300 + This option enables support for the HP9000/300 series of + workstations. Support for these machines is still very experimental. + If you plan to try to use the kernel on such a machine say Y here. + Everybody else says N. + +Sun 3 support +CONFIG_SUN3 + This option enables support for the Sun 3 series of workstations. Be + warned that this support is very experimental. You will also want to + say Y to 68020 support and N to the other processors below. + Currently, it is not possible to build a kernel with support for the + Sun 3 and something else, so make sure you have said N to all the + other machines. This option does not support the sun3x series of + machines (the Sun 3/80 and 3/460). If you don't want to compile a + kernel for a Sun 3, say N. + +68020 support +CONFIG_M68020 + If you anticipate running this kernel on a computer with a MC68020 + processor, say Y. Otherwise, say N. Note that the 68020 requires a + 68851 MMU (Memory Management Unit) to run Linux/m68k, except on the + Sun 3, which provides its own version. + +68030 support +CONFIG_M68030 + If you anticipate running this kernel on a computer with a MC68030 + processor, say Y. Otherwise, say N. Note that a MC68EC030 will not + work, as it does not include an MMU (Memory Management Unit). + +68040 support +CONFIG_M68040 + If you anticipate running this kernel on a computer with a MC68LC040 + or MC68040 processor, say Y. Otherwise, say N. Note that an + MC68EC040 will not work, as it does not include an MMU (Memory + Management Unit). + +68060 support +CONFIG_M68060 + If you anticipate running this kernel on a computer with a MC68060 + processor, say Y. Otherwise, say N. + +Math emulation support (EXPERIMENTAL) +CONFIG_M68KFPU_EMU + At some point in the future, this will cause floating-point math + instructions to be emulated by the kernel on machines that lack a + floating-point math coprocessor. Thrill-seekers and chronically + sleep-deprived psychotic hacker types can say Y now, everyone else + should probably wait a while. + +Math emulation only kernel +CONFIG_M68KFPU_EMU_ONLY + This option prevents any floating-point instructions from being + compiled into the kernel, thereby the kernel doesn't save any + floating point context anymore during task switches, so this + kernel will only be usable on machines without a floating-point + math coprocessor. This makes the kernel a bit faster as no tests + needs to be executed whether a floating-point instruction in the + kernel should be executed or not. + +Math emulation extra precision +CONFIG_M68KFPU_EMU_EXTRAPREC + The fpu uses normally a few bit more during calculations for + correct rounding, the emulator can (often) do the same but this + extra calculation can cost quite some time, so you can disable + it here. The emulator will then "only" calculate with a 64 bit + mantissa and round slightly incorrect, what is more then enough + for normal usage. + +Advanced processor options +CONFIG_ADVANCED_CPU + This gives you access to some advanced options for the CPU. The + defaults should be fine for most users, but these options may make + it possible for you to improve performance somewhat if you know what + you are doing. Most users should say N to this question. + +Use read-modify-write instructions +CONFIG_RMW_INSNS + This allows to use certain instructions that work with indivisible + read-modify-write bus cycles. While this is faster than the + workaround of disabling interrupts, it can conflict with DMA + ( = direct memory access) on many Amiga systems, and it is also said + to destabilize other machines. It is very likely that this will + cause serious problems on any Amiga or Atari Medusa if set. The only + configuration where it should work are 68030-based Ataris, where it + apparently improves performance. But you've been warned! Unless you + really know what you are doing, say N. Try Y only if you're quite + adventurous. + +Amiga AutoConfig Identification +CONFIG_ZORRO + This enables support for automatic identification of Amiga expansion + cards that obey the AutoConfig(tm) specification. + Say Y if you want your expansion cards to be identified on bootup; + it will enlarge your kernel by about 10 KB. The identification + information is also available through /proc/zorro (say Y to + "/proc filesystem support"!). + + Note that even if you say N here, you can still use your expansion + cards. If in doubt, say Y. + +Amiga 1200/600 PCMCIA support (EXPERIMENTAL) +CONFIG_AMIGA_PCMCIA + Include support in the kernel for pcmcia on Amiga 1200 and Amiga + 600. If you intend to use pcmcia cards say Y; otherwise say N. + +Amiga GSP (TMS340x0) support +CONFIG_AMIGA_GSP + Include support for Amiga graphics cards that use the Texas + Instruments TMS340x0 GSP (Graphics Signal Processor) chips. Say Y + if you want to use a DMI Resolver or Commodore A2410 (Lowell) + graphics card on an Amiga; otherwise, say N. + +DMI Resolver support +CONFIG_GSP_RESOLVER + Include support in the kernel for the DMI Resolver graphics card. If + you have one, say Y; otherwise, say N. + +A2410 support +CONFIG_GSP_A2410 + Include support in the kernel for the Commodore/University of Lowell + A2410 graphics card. If you have one, say Y; otherwise, say N. + +Amiga Zorro II ramdisk support +CONFIG_AMIGA_Z2RAM + This enables support for using Chip RAM and Zorro II RAM as a + ramdisk or as a swap partition. Say Y if you want to include this + driver in the kernel. This driver is also available as a module + ( = code which can be inserted in and removed from the running + kernel whenever you want). The module is called z2ram.o. If you want + to compile it as a module, say M here and read + Documentation/modules.txt. + +Atari ST-RAM swap support +CONFIG_STRAM_SWAP + This enables support for using (parts of) ST-RAM as swap space, + instead of as normal system memory. This can first enhance system + performance if you have lots of alternate RAM (compared to the size + of ST-RAM), because executable code always will reside in faster + memory. ST-RAM will remain as ultra-fast swap space. On the other + hand, it allows much improved dynamic allocations of ST-RAM buffers + for device driver modules (e.g. floppy, ACSI, SLM printer, DMA + sound). The probability that such allocations at module load time + fail is drastically reduced. + +Atari ACSI support +CONFIG_ATARI_ACSI + This enables support for the Atari ACSI interface. The driver + supports hard disks and CD-ROMs, which have 512-byte sectors, or can + be switched to that mode. Due to the ACSI command format, only disks + up to 1 GB are supported. Special support for certain ACSI to SCSI + adapters, which could relax that, isn't included yet. The ACSI + driver is also the basis for certain other drivers for devices + attached to the ACSI bus: Atari SLM laser printer, BioNet-100 + Ethernet, and PAMsNet Ethernet. If you want to use one of these + devices, you need ACSI support, too. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called acsi.o. + +Probe all LUNs on each ACSI device +CONFIG_ACSI_MULTI_LUN + If you have a ACSI device that supports more than one LUN (Logical + Unit Number), e.g. a CD jukebox, you should say Y here so that all + will be found by the ACSI driver. An ACSI device with multiple LUNs + acts logically like multiple ACSI devices. The vast majority of ACSI + devices have only one LUN, and so most people can say N here and + should in fact do so, because it is safer. + +Atari SLM laser printer support +CONFIG_ATARI_SLM + If you have an Atari SLM laser printer, say Y to include support for + it in the kernel. Otherwise, say N. This driver is also available as + a module ( = code which can be inserted in and removed from the + running kernel whenever you want). The module will be called + acsi_slm.o. Be warned: the driver needs much ST-RAM and can cause + problems due to that fact! + +A3000 WD33C93A support +CONFIG_A3000_SCSI + If you have an Amiga 3000 and have SCSI devices connected to the + built-in SCSI controller, say Y. Otherwise, say N. This driver is + also available as a module ( = code which can be inserted in and + removed from the running kernel whenever you want). The module is + called wd33c93.o. If you want to compile it as a module, say M here + and read Documentation/modules.txt. + +A2091 WD33C93A support +CONFIG_A2091_SCSI + If you have a Commodore A2091 SCSI controller, say Y. Otherwise, + say N. This driver is also available as a module ( = code which can + be inserted in and removed from the running kernel whenever you + want). The module is called wd33c93.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +GVP Series II WD33C93A support +CONFIG_GVP11_SCSI + If you have a Great Valley Products Series II SCSI controller, + answer Y. Also say Y if you have a later model of GVP SCSI + controller (such as the GVP A4008 or a Combo board). Otherwise, + answer N. This driver does NOT work for the T-Rex series of + accelerators from TekMagic and GVP-M. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module will be called gvp11.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. + +Cyberstorm SCSI support +CONFIG_CYBERSTORM_SCSI + If you have an Amiga with an original (MkI) Phase5 Cyberstorm + accelerator board and the optional Cyberstorm SCSI controller, + answer Y. Otherwise, say N. + +Cyberstorm II SCSI support +CONFIG_CYBERSTORMII_SCSI + If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board + and the optional Cyberstorm SCSI controller, say Y. Otherwise, + answer N. + +Blizzard 2060 SCSI support +CONFIG_BLZ2060_SCSI + If you have an Amiga with a Phase5 Blizzard 2060 accelerator board + and want to use the onboard SCSI controller, say Y. Otherwise, + answer N. + +Blizzard 1230IV/1260 SCSI support +CONFIG_BLZ1230_SCSI + If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard + 1260 accelerator, and the optional SCSI module, say Y. Otherwise, + say N. + +Blizzard PowerUP 603e+ SCSI support (EXPERIMENTAL) +CONFIG_BLZ603EPLUS_SCSI + If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+ + accelerator, say Y. Otherwise, say N. + +Fastlane SCSI support +CONFIG_FASTLANE_SCSI + If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use + one in the near future, say Y to this question. Otherwise, say N. + +Atari native SCSI support +CONFIG_ATARI_SCSI + If you have an Atari with built-in NCR5380 SCSI controller (TT, + Falcon, ...) say Y to get it supported. Of course also, if you have + a compatible SCSI controller (e.g. for Medusa). This driver is also + available as a module ( = code which can be inserted in and removed + from the running kernel whenever you want). The module is called + atari_scsi.o. If you want to compile it as a module, say M here and + read Documentation/modules.txt. This driver supports both styles of + NCR integration into the system: the TT style (separate DMA), and + the Falcon style (via ST-DMA, replacing ACSI). It does NOT support + other schemes, like in the Hades (without DMA). + +Long delays for Toshiba CD-ROMs +CONFIG_ATARI_SCSI_TOSHIBA_DELAY + This option increases the delay after a SCSI arbitration to + accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to + use a Toshiba CD-ROM drive; otherwise, the option is not needed and + would impact performance a bit, so say N. + +Hades SCSI DMA emulator (EXPERIMENTAL) +CONFIG_TT_DMA_EMUL + This option enables code which emulates the TT SCSI DMA chip on the + Hades. This increases the SCSI transfer rates at least ten times + compared to PIO transfers. Note that this code is experimental and + has only been tested on a Hades with a 68060 processor. Before you + use this, make backups of your entire hard disk. + +Ariadne support +CONFIG_ARIADNE + If you have a Village Tronic Ariadne Ethernet adapter, say Y. + Otherwise, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module is called ariadne.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +Ariadne II support +CONFIG_ARIADNE2 + If you have a Village Tronic Ariadne II Ethernet adapter, say Y. + Otherwise, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module is called ariadne2.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +A2065 support +CONFIG_A2065 + If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise, + say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module is called a2065.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Hydra support +CONFIG_HYDRA + If you have a Hydra Ethernet adapter, say Y. Otherwise, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module is called hydra.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Pcmcia NE2000 compatible support +CONFIG_APNE + If you have a pcmcia ne2000 compatible adapter, say Y. Otherwise, + say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). The module is called apne.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Atari Lance support +CONFIG_ATARILANCE + Say Y to include support for several Atari Ethernet adapters based + on the AMD Lance chipset: RieblCard (with or without battery), or + PAMCard VME (also the version by Rhotron, with different addresses). + +BioNet-100 support +CONFIG_ATARI_BIONET + Say Y to include support for BioData's BioNet-100 Ethernet adapter + for the ACSI port. The driver works (has to work...) with a polled + I/O scheme, so it's rather slow :-( + +PAMsNet support +CONFIG_ATARI_PAMSNET + Say Y to include support for the PAMsNet Ethernet adapter for the + ACSI port ("ACSI node"). The driver works (has to work...) with a + polled I/O scheme, so it's rather slow :-( + +Multiface Card III parallel support +CONFIG_MULTIFACE_III_LP + If you have a Multiface III card for your Amiga, and want to use its + parallel port in Linux, say Y. Otherwise, say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called lp_m68k.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Amiga mouse support +CONFIG_AMIGAMOUSE + If you want to be able to use an Amiga mouse in Linux, say Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called amigamouse.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Amiga Copper Console +CONFIG_COPCON + This configures the console to use the Amiga's graphics coprocessor + for scrolling, instead of using the CPU. This option markedly + improves response times in the high color modes (5 bitplanes and + up). If you would like to use this, say Y; otherwise, say N. + +Atari mouse support +CONFIG_ATARIMOUSE + If you want to be able to use an Atari mouse in Linux, say Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called atarimouse.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + +Atari MFP serial support +CONFIG_ATARI_MFPSER + If you like to use the MFP serial ports ("Modem1", "Serial1") under + Linux, say Y. The driver equally supports all kinds of MFP serial + ports and automatically detects whether Serial1 is available. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. + + Note for Falcon users: You also have an MFP port, it's just not + wired to the outside... But you could use the port under Linux. + +Atari SCC serial support +CONFIG_ATARI_SCC + If you have serial ports based on a Zilog SCC chip (Modem2, Serial2, + LAN) and like to use them under Linux, say Y. All built-in SCC's are + supported (TT, MegaSTE, Falcon), and also the ST-ESCC. If you have + two connectors for channel A (Serial2 and LAN), they are visible as + two separate devices. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. + +Atari SCC serial DMA support +CONFIG_ATARI_SCC_DMA + This enables DMA support for receiving data on channel A of the SCC. + If you have a TT you may say Y here and read + drivers/char/atari_SCC.README. All other users should say N here, + because only the TT has SCC-DMA, even if your machine keeps claiming + so at boot time. + +Atari MIDI serial support +CONFIG_ATARI_MIDI + If you want to use your Atari's MIDI port in Linux, say Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). If you want to compile it as a module, say M here and read + Documentation/modules.txt. + +Atari DSP56k Digital Signal Processor support (EXPERIMENTAL) +CONFIG_ATARI_DSP56K + If you want to be able to use the DSP56001 in Falcons, say Y. This + driver is still experimental, and if you don't know what it is, or + if you don't have this processor, just say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. + +Amiga builtin serial support +CONFIG_AMIGA_BUILTIN_SERIAL + If you want to use your Amiga's built-in serial port in Linux, + answer Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). If you want to compile it as a module, say M here and read + Documentation/modules.txt. + +GVP IO-Extender support +CONFIG_GVPIOEXT + If you want to use a GVP IO-Extender serial card in Linux, say Y. + Otherwise, say N. + +Multiface Card III serial support +CONFIG_MULTIFACE_III_TTY + If you want to use a Multiface III card's serial port in Linux, + answer Y. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. + +Amiga or Atari DMA sound support +CONFIG_DMASOUND + If you want to use the internal audio of your Atari or Amiga in + Linux, answer Y to this question. This will provide a Sun-like + /dev/audio, compatible with the Linux/i386 sound system. Otherwise, + say N. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). If you want to compile it as a module, say M here and read + Documentation/modules.txt. + +HP DCA serial support +CONFIG_HPDCA + If you want to use the internal "DCA" serial ports on an HP300 + machine, say Y here. + +HP on-board LANCE support +CONFIG_HPLANCE + If you want to use the builtin "LANCE" Ethernet controller on an + HP300 machine, say Y here. + +Sun 3 onboard LANCE support +CONFIG_SUN3LANCE + If you want to use the onboard AMD "LANCE" (le) Ethernet hardware + on a Sun 3, you will need to say Y here. + +DIO bus support +CONFIG_DIO + Say Y here to enable support for the "DIO" expansion bus used in + HP300 machines. If you are using such a system you almost certainly + want this. + +Processor Type +CONFIG_6xx + There are two types of PowerPC chips supported. The more common + types (601,603,604,740,750) and the embedded versions (821 and 860). + Unless you are building a kernel for one of the embedded boards + using the 821 or 860 choose 6xx. + +Machine Type +CONFIG_PMAC + Linux currently supports several different kinds of PowerPC-based + machines: Apple Power Macintoshes and clones (such as the Motorola + Starmax series), PReP (PowerPC Reference Platform) machines such as + the Motorola PowerStack, Amiga Power-Up systems (APUS), CHRP and the + embedded MBX boards from Motorola. Currently, a single kernel binary + only supports one type or the other. However, there is very early + work on support for CHRP, PReP and PowerMac's from a single binary. + +Support for Open Firmware device tree in /proc +CONFIG_PROC_DEVICETREE + This option adds a device-tree directory under /proc which contains + an image of the device tree that the kernel copies from Open + Firmware. If unsure, say Y here. + +MESH (Power Mac internal SCSI) support +CONFIG_SCSI_MESH + Many Power Macintoshes and clones have a MESH (Macintosh Enhanced + SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the + other Power Macintoshes do). Say Y to include support for this SCSI + adaptor. This driver is also available as a module called mesh.o + ( = code which can be inserted in and removed from the running + kernel whenever you want). If you want to compile it as a module, + say M here and read Documentation/modules.txt. + +Maximum synchronous transfer rate +CONFIG_SCSI_MESH_SYNC_RATE + On Power Macintoshes (and clones) where the MESH SCSI bus adaptor + drives a bus which is entirely internal to the machine (such as the + 7500, 7600, 8500, etc.), the MESH is capable of synchronous + operation at up to 10 MB/s. On machines where the SCSI bus + controlled by the MESH can have external devices connected, it is + usually rated at 5 MB/s. 5 is a safe value here unless you know the + MESH SCSI bus is internal only; in that case you can say 10. Say 0 + to disable synchronous operation. + +53C94 (Power Mac external SCSI) support +CONFIG_SCSI_MAC53C94 + On Power Macintoshes (and clones) with two SCSI buses, the external + SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older + machines which only have one SCSI bus, such as the 7200, also use + the 53C94. Say Y to include support for the 53C94. + + This driver is also available as a module called mac53c94.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +MACE (Power Mac Ethernet) support +CONFIG_MACE + Power Macintoshes and clones with Ethernet built-in on the + motherboard will usually use a MACE (Medium Access Control for + Ethernet) interface. Say Y to include support for the MACE chip. + + This driver is also available as a module called mace.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +BMAC (G3 ethernet) support +CONFIG_BMAC + Say Y for support of BMAC Ethernet interfaces. These are used on G3 + computers. + + This driver is also available as a module called bmac.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Video For Linux +CONFIG_VIDEO_DEV + Support for audio/video capture and overlay devices and FM radio + cards. The exact capabilities of each device vary. User tools for + this are available from + ftp://ftp.uk.linux.org/pub/linux/video4linux . + + If you are interested in writing a driver for such an audio/video + device or user software interacting with such a driver, please read + the file Documentation/video4linux/API.html. + + This driver is also available as a module called videodev.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +AIMSlab RadioTrack (aka RadioReveal) support +CONFIG_RADIO_RTRACK + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + Note that newer AIMSlab RadioTrack cards have a different chipset + and are not supported by this driver. For these cards, use the + RadioTrack II driver below. + + If you have a GemTeks combined (PnP) sound- and radio card you must + use this driver as a module and setup the card with isapnptools. You + must also pass the module a suitable io parameter, 0x248 has been + reported to be used by these cards. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . More information + is contained in the file Documentation/video4linux/radiotrack.txt. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-aimslab.o. + +RadioTrack i/o port +CONFIG_RADIO_RTRACK_PORT + Enter either 0x30f or 0x20f here. The card default is 0x30f, if you + haven't changed the jumper setting on the card. + +AIMSlab RadioTrack II support +CONFIG_RADIO_RTRACK2 + Choose Y here if you have this FM radio card, and then fill in the + port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-rtrack2.o. + +RadioTrack II i/o port +CONFIG_RADIO_RTRACK2_PORT + Enter either 0x30c or 0x20c here. The card default is 0x30c, if you + haven't changed the jumper setting on the card. + +Aztech/Packard Bell Radio +CONFIG_RADIO_AZTECH + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-aztech.o. + +Aztech/Packard Bell radio card i/o port +CONFIG_RADIO_AZTECH_PORT + Enter either 0x350 or 0x358 here. The card default is 0x350, if you + haven't changed the setting of jumper JP3 on the card. Removing the + jumper sets the card to 0x358. + +ADS Cadet AM/FM Radio Tuner Card +CONFIG_RADIO_CADET + Choose Y here if you have one of these AM/FM radio cards, and then + fill in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + Further documentation on this driver can be found on the WWW at + http://linux.blackhawke.net/cadet.html . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-cadet.o. + +ADS Cadet AM/FM Radio Tuner Card I/O Port +CONFIG_RADIO_CADET_PORT + Enter the I/O address of the card here (most commonly 330). + +SF16FMI Radio +CONFIG_RADIO_SF16FMI + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-sf16fmi.o + +SF16FMI I/O port (0x284 or 0x384) +CONFIG_RADIO_SF16FMI_PORT + Enter the I/O port of your SF16FMI radio card. + +Typhoon Radio +CONFIG_RADIO_TYPHOON + Choose Y here if you have one of these FM radio cards, and then fill + in the port address and the frequency used for muting below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-typhoon.o + +Support for /proc/radio-typhoon +CONFIG_RADIO_TYPHOON_PROC_FS + Say Y here if you want the typhoon radio card driver to write + status information (frequency, volume, muted, mute frequency, + base address) to /proc/radio-typhoon. The file can be viewed with + your favorite pager (i.e. use "more /proc/radio-typhoon" or "less + /proc/radio-typhoon" or simply "cat /proc/radio-typhoon"). + +Typhoon I/O port (0x316 or 0x336) +CONFIG_RADIO_TYPHOON_PORT + Enter the I/O port of your Typhoon or EcoRadio radio card. + +Typhoon frequency set when muting the device (kHz) +CONFIG_RADIO_TYPHOON_MUTEFREQ + Enter the frequency used for muting the radio. The device is never + completely silent. If the volume is just turned down, you can still + hear silent voices and music. For that reason, the frequency of the + radio device is set to the frequency you can enter here whenever + the device is muted. There should be no local radio station at that + frequency. + +Zoltrix Radio +CONFIG_RADIO_ZOLTRIX + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-zoltrix.o + +ZOLTRIX I/O port (0x20c or 0x30c) +CONFIG_RADIO_ZOLTRIX_PORT + Enter the I/O port of your Zoltrix radio card. + +IIC on parallel port +CONFIG_I2C_PARPORT + I2C is a simple serial bus system used in many micro controller + applications. Saying Y here will allow you to use your parallel port + as an I2C interface. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called i2c-parport.o. + +Miro PCM20 Radio +CONFIG_RADIO_MIROPCM20 + Choose Y here if you have this FM radio card. You also need to say Y + to "ACI mixer (miroPCM12/PCM20)" (in "additional low level sound + drivers") for this to work. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-miropcm20.o + +GemTek Radio Card +CONFIG_RADIO_GEMTEK + Choose Y here if you have this FM radio card, and then fill in the + port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-gemtek.o. + +GemTek i/o port +CONFIG_RADIO_GEMTEK_PORT + Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is + 0x34c, if you haven't changed the jumper setting on the card. + +PlanB Video-In for PowerMacs +CONFIG_VIDEO_PLANB + PlanB is the V4L driver for the PowerMac 7x00/8x00 series video + input hardware. If you want to experiment with this, say Y. + Otherwise, or if you don't understand a word, say N. + See http://www.cpu.lu/~mlan/planb.html for more info. + + Saying M will compile this driver as a module (planb.o). + +TerraTec ActiveRadio +CONFIG_RADIO_TERRATEC + Choose Y here if you have this FM radio card, and then fill in the + port address below. (TODO) + + Note: This driver is in its early stages. Right now volume and + frequency control and muting works at least for me, but + unfortunately i have not found anybody who wants to use this card + with linux. So if it is this what YOU are trying to do right now, + PLEASE DROP ME A NOTE!! Rolf Offermanns (rolf@offermanns.de) + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW, + you need to have access to a machine on the Internet that has a + program like lynx or netscape. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called radio-terratec.o. + +# Zoran ZR36057/36060 support +# CONFIG_VIDEO_ZORAN + +# Include support for Iomega Buz +# CONFIG_VIDEO_BUZ + +BT848 Video For Linux +CONFIG_VIDEO_BT848 + Support for BT848 based frame grabber/overlay boards. This includes + the Miro, Hauppauge and STB boards. Please read the material in + Documentation/video4linux/bttv for more information. + + This driver is also available as a module called bttv.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +SAA5249 Teletext processor +CONFIG_VIDEO_SAA5249 + Support for I2C bus based teletext using the SAA5249 chip. At the + moment this is only useful on some European WinTV cards. + + This driver is also available as a module called saa5249.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Quickcam BW Video For Linux +CONFIG_VIDEO_BWQCAM + Say Y have if you the black and white version of the QuickCam + camera. See the next option for the color version. + + This driver is also available as a module called bw-qcam.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + +Colour QuickCam Video For Linux +CONFIG_VIDEO_CQCAM + This is the video4linux driver for the colour version of the + Connectix Quickcam. If you have one of these cameras, say Y here, + otherwise say N. This driver does not work with the original + monochrome Quickcam, Quickcam VC or QuickClip. It is also available + as a module (c-qcam.o). + +Mediavision Pro Movie Studio Video For Linux +CONFIG_VIDEO_PMS + Say Y if you have such a thing. This driver is also available as a + module called pms.o ( = code which can be inserted in and removed + from the running kernel whenever you want). If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +Compaq SMART2 support +CONFIG_BLK_CPQ_DA + This is the driver for Compaq Smart Array controllers. + Everyone using these boards should say Y here. + See the file Documentation/cpqarray.txt for the current list of + boards supported by this driver, and for further information + on the use of this driver. + +# +# ARM options +# +CPU Optimization +CONFIG_CPU_ARM2 + This selects the processor type of your CPU. This is only used to + determine C compiler optimization options, and can affect the + compatibility of the kernel on other processors. If you specify + ARM6, the kernel should work on all 32-bit processors. If you + specify ARM2, ARM250 or ARM3, it should work on all 26-bit + processors. If you're not sure, set it to "None". + +ARM System type +CONFIG_ARCH_ARC + This selects what ARM system you wish to build the kernel for. It + also selects to some extent the CPU type. If you are unsure what + to set this option to, please consult any information supplied with + your system. + +Include support for Chalice CATS boards +CONFIG_CATS + Say Y here if you intend to run this kernel on a CATS system. + +Include support for Intel EBSA285 +CONFIG_ARCH_EBSA285 + board. + +Include support for the NetWinder +CONFIG_ARCH_NETWINDER + Say Y here if you intend to run this kernel on the NetWinder. + +Virtual/Physical Memory Split +CONFIG_1GB + If you are compiling a kernel which will never run on a machine + with more than 1 Gigabyte total physical RAM, answer "3GB/1GB" + here (default choice). + + On 32-bit x86 systems Linux can use up to 64 Gigabytes of physical + memory. However 32-bit x86 processors have only 4 Gigabytes of + virtual memory space. This option specifies the maximum amount of + virtual memory space one process can potentially use. Certain types + of applications (eg. database servers) perform better if they have + as much virtual memory per process as possible. + + The remaining part of the 4G virtual memory space is used by the + kernel to 'permanently map' as much physical memory as possible. + Certain types of applications perform better if there is more + 'permanently mapped' kernel memory. + + [WARNING! Certain boards do not support PCI DMA to physical addresses + bigger than 2 Gigabytes. Non-DMA-able memory must not be permanently + mapped by the kernel, thus a 1G/3G split will not work on such boxes.] + + As you can see there is no 'perfect split' - the fundamental + problem is that 4G of 32-bit virtual memory space is short. So + you'll have to pick your own choice - depending on the application + load of your box. A 2G/2G split is typically a good choice for a + generic Linux server with lots of RAM. + + Any potentially remaining (not permanently mapped) part of physical + memory is called 'high memory'. How much total high memory the kernel + can handle is influenced by the (next) High Memory configuration option. + + The actual amount of total physical memory will either be + autodetected or can be forced by using a kernel command line option + such as "mem=256M". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time. The lilo procedure is also explained in the + SCSI-HOWTO, available from http://metalab.unc.edu/mdw/linux.html#howto .) + +Math emulation +CONFIG_NWFPE + Say Y to include the NWFPE floating point emulator in the kernel. + This is necessary to run most binaries. Linux does not currently + support floating point hardware so you need to say Y here even if + your machine has an FPA or floating point co-processor podule. + + It is also possible to say M to build the emulator as a module + (nwfpe.o) or indeed to leave it out altogether. However, unless you + know what you are doing this can easily render your machine + unbootable. Saying Y is the safe option. + + You may say N here if you are going to load the Acorn FPEmulator + early in the bootup. + +DS1620 Thermometer support +CONFIG_DS1620 + Say Y here to include support for the thermal management hardware + found in the NetWinder. This driver allows the user to control the + temperature set points and to read the current temperature. + + It is also possible to say M here to build it as a module (ds1620.o) + It is recommended to be used on a NetWinder, but it is not a + necessity. + +Verbose kernel error messages +CONFIG_DEBUG_ERRORS + This option controls verbose debugging information which can be + printed when the kernel detects an internal error. This debugging + information is useful to kernel hackers when tracking down problems, + but mostly meaningless to other people. It's safe to say Y unless + you are concerned with the code size or don't want to see these + messages. + +Build Tools Selection +CONFIG_BINUTILS_NEW + Say Y here if and only if you're using GCC 2.8.1/EGCS with a + binutils version >= 2.8.1 to compile the kernel (check with "gcc + --version" and "ld -v"). + +Compile kernel with frame pointer +CONFIG_FRAME_POINTER + If you say Y here, the resulting kernel will be slightly larger and + slower, but it will give useful debugging information. If you don't + debug the kernel, you can say N. + +User fault debugging +CONFIG_DEBUG_USER + When a user program crashes due to an exception, the kernel can + print a brief message explaining what the problem was. This is + sometimes helpful for debugging but serves no purpose on a + production system. Most people should say N here. + +Include gdb debugging information in kernel binary +CONFIG_DEBUG_INFO + Say Y here to include source-level debugging information in the + `vmlinux' binary image. This is handy if you want to use gdb or + addr2line to debug the kernel. It has no impact on the in-memory + footprint of the running kernel but it can increase the amount of + time and disk space needed for compilation of the kernel. If in + doubt say N. + +Split initialisation functions into discardable section +CONFIG_TEXT_SECTIONS + If you say Y here, kernel code that is only used during + initialisation is collected into a special area of the kernel so + that it can be discarded and the memory reclaimed when + initialisation is complete. In addition, if the kernel you wish to + build is able to run on multiple architectures, it allows the unused + code to be discarded. Some versions of binutils, however, have a bug + that causes the kernel to crash during startup when this option is + enabled. Say Y unless you experience problems that you suspect may + be caused by this. + +Disable pgtable cache (EXPERIMENTAL) +CONFIG_NO_PGT_CACHE + Normally the kernel maintains a `quicklist' of preallocated + pagetable structures in order to increase performance. On machines + with very few pages this may however be a loss. Say Y here to + disable the pgtable cache. + +RISC OS personality +CONFIG_ARTHUR + Say Y here to include the kernel code necessary if you want to run + Acorn RISC OS/Arthur binaries under Linux. This code is still very + experimental; if this sounds frightening, say N and sleep in peace. + You can also say M here to compile this support as a module (which + will be called arthur.o). + +Initial kernel command line +CONFIG_CMDLINE + On some architectures (EBSA110 and CATS), there is currently no way + for the boot loader to pass arguments to the kernel. For these + architectures, you should supply some command-line options at build + time by entering them here. As a minimum, you should specify the + memory size and the root device (e.g., mem=64M root=/dev/nfs) + +Hardware alignment trap (EXPERIMENTAL) +CONFIG_ALIGNMENT_TRAP + ARM processors can not fetch/store information which is not + naturally aligned on the bus, i.e., a 4 byte fetch must start at an + address divisible by 4. On 32-bit ARM processors, these non-aligned + fetch/store instructions will be emulated in software if you say + here, which has a severe performance impact. This is necessary for + correct operation of some network protocols. With an IP-only + configuration it is safe to say N, otherwise say Y. + +21285 serial port support +CONFIG_SERIAL_21285 + If you have a machine based on a 21285 (Footbridge) StrongARM/PCI + bridge you can enable its onboard serial port by enabling this + option. The device has major ID 4, minor 64. + +Console on 21285 serial port +CONFIG_SERIAL_21285_CONSOLE + If you have enabled the serial port on the 21285 footbridge you can + make it the console by answering Y to this option. + +Footbridge Mode +CONFIG_HOST_FOOTBRIDGE + The 21285 Footbridge chip can operate in either `host mode' or + `add-in' mode. Say Y if your 21285 is in host mode, and therefore + is the configuration master, otherwise say N. This must not be + set to Y if the card is used in 'add-in' mode. + +MFM hard disk support +CONFIG_BLK_DEV_MFM + Support the MFM hard drives on the Acorn Archimedes both + on-board the A4x0 motherboards and via the Acorn MFM podules. + Drives up to 64MB are supported. If you haven't got one of these + machines or drives just say N. + +Old Archimedes floppy (1772) support +CONFIG_BLK_DEV_FD1772 + Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540, + R140 and R260) series of computers; it supports only 720K floppies + at the moment. If you don't have one of these machines just answer + N. + +Autodetect hard drive geometry +CONFIG_BLK_DEV_MFM_AUTODETECT + If you answer Y, the MFM code will attempt to automatically detect + the cylinders/heads/sectors count on your hard drive. WARNING: This + sometimes doesn't work and it also does some dodgy stuff which + potentially might damage your drive. + +IrDA Protocols +CONFIG_IRDA + Say Y here if you want to build support for the IrDA (TM) protocols. + The Infrared Data Associations (tm) specifies standards for wireless + infrared communication and is supported by most laptops and PDA's. + + To use Linux support for the IrDA (tm) protocols, you will also need + some user-space utilities like the irmanager and probably irattach + as well. For more information, see the file + Documentation/networking/irda.txt. You also want to read the + IR-HOWTO, available at http://metalab.unc.edu/mdw/linux.html#howto . + + This support is also available as a module. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + +IrDA Cache last LSAP +CONFIG_IRDA_CACHE_LAST_LSAP + Say Y here if you want IrLMP to cache the last LSAP used. This makes + sense since most frames will be sent/received on the same + connection. Enabling this option will save a hash-lookup per frame. + + If unsure, say Y. + +IrDA Fast RR's +CONFIG_IRDA_FAST_RR + Say Y here is you want IrLAP to send fast RR (Receive Ready) frames + when acting as a primary station. This will make IrLAP send out a RR + frame immediately when receiving a frame if its own transmit queue + is currently empty. This will give a lot of speed improvement when + receiving much data since the secondary station will not have to + wait the max. turn around time before it is allowed to transmit the + next time. If the transmit queue of the secondary is also empty the + primary will back off waiting longer for sending out the RR frame + until the timeout reaches the normal value. Enabling this option + will make the IR-diode burn more power and thus reduce your battery + life. + + If unsure, say N. + +IrDA Debug +CONFIG_IRDA_DEBUG + Say Y here if you want the IrDA subsystem to write debug information + to your syslog. You can change the debug level in + /proc/sys/net/irda/debug + + If unsure, say Y (since it makes it easier to find the bugs). + +IrLAP Compression support +CONFIG_IRDA_COMPRESSION + Compression is _not_ part of the IrDA(tm) protocol specification, + but it's working great! Linux is the first to try out compression + support at the IrLAP layer. This means that you will only benefit + from compression if you are running a Linux <-> Linux configuration. + + If you say Y here, you also need to say Y or M to a compression + protocol below. + +IrLAP Deflate Compression Protocol (EXPERIMENTAL) +CONFIG_IRDA_DEFLATE + Say Y here if you want to build support for the Deflate compression + protocol. The deflate compression (GZIP) is exactly + the same as the one used by the PPP protocol. + + If you want to compile this compression support as a module, say M + here and read Documentation/modules.txt. The module will be called + irda_deflate.o. + +IrLAN Protocol +CONFIG_IRLAN + Say Y here if you want to build support for the IrLAN protocol. If + you want to compile it as a module, say M here and read + Documentation/modules.txt. IrLAN emulates an Ethernet and makes it + possible to put up a wireless LAN using infrared beams. + + The IrLAN protocol can be used to talk with infrared access points + like the HP NetbeamIR, or the ESI JetEye NET. You can also connect + to another Linux machine running the IrLAN protocol for ad-hoc + networking! + +IrCOMM Protocol +CONFIG_IRCOMM + Say Y here if you want to build support for the IrCOMM protocol. If + you want to compile it as a module, say M here and read + Documentation/modules.txt. IrCOMM implements serial port emulation, + and makes it possible to use all existing applications that + understands TTY's with an infrared link. Thus you should be able to + use application like PPP, minicom and others. Enabling this option + will create two modules called ircomm and ircomm_tty. For more + information go to http://www.pluto.dti.ne.jp/~thiguchi/irda/ + +IrTTY IrDA Device Driver +CONFIG_IRTTY_SIR + Say Y here if you want to build support for the IrTTY line + discipline. If you want to compile it as a module, say M here and + read Documentation/modules.txt. IrTTY makes it possible to use + Linux's own serial driver for all IrDA ports that are 16550 + compatible. Most IrDA chips are 16550 compatible so you should + probably say Y to this option. Using IrTTY will however limit the + speed of the connection to 115200 bps (IrDA SIR mode) + + If unsure, say Y. + +IrPORT IrDA Device Driver +CONFIG_IRPORT_SIR + Say Y here if you want to build support for the IrPORT IrDA device + driver. If you want to compile it as a module, say M here and + read Documentation/modules.txt. IrPORT can be used instead of + IrTTY and sometimes this can be better. One example is if your + IrDA port does not have echo-canceling, which will work OK with + IrPORT since this driver is working in half-duplex mode only. You + don't need to use irattach with IrPORT, but you just insert it + the same way as FIR drivers (insmod irport io=0x3e8 irq=11). + Notice that IrPORT is a SIR device driver which means that speed + is limited to 115200 bps. + + If unsure, say Y. + +SiS5513 chipset support +CONFIG_BLK_DEV_SIS5513 + This driver ensures (U)DMA support for SIS5513 chipset based + mainboards. SiS620/530 UDMA mode 4, SiS5600/5597 UDMA mode 2, all + other DMA mode 2 limited chipsets are unsupported to date. + + If you say Y here, you need to say Y to "Use DMA by default when + available" as well. + + Please read the comments at the top of drivers/block/sis5513.c + +Winbond W83977AF IrDA Device Driver +CONFIG_WINBOND_FIR + Say Y here if you want to build IrDA support for the Winbond + W83977AF super-io chipset. If you want to compile it as a module, + say M here and read Documentation/modules.txt. This driver should be + used for the IrDA chipset in the Corel NetWinder. The driver + supports SIR, MIR and FIR (4Mbps) speeds. + +NSC PC87108 IrDA Device Driver +CONFIG_NSC_FIR + Say Y here if you want to build support for the NSC PC87108 IrDA + chipset. If you want to compile it as a module, say M here and + read Documentation/modules.txt. This drivers currently only supports + the ACTiSYS IR2000B ISA card and supports SIR, MIR and FIR (4Mbps) + speeds. + +Toshiba Type-O IR Port Device Driver +CONFIG_TOSHIBA_FIR + Say Y here if you want to build support for the Toshiba Type-O IR + chipset. If you want to compile it as a module, say M here and + read Documentation/modules.txt. This chipset is used by the Toshiba + Libretto 100CT, and many more laptops. + +ESI JetEye PC Dongle +CONFIG_ESI_DONGLE + Say Y here if you want to build support for the Extended Systems + JetEye PC dongle. If you want to compile it as a module, say M here + and read Documentation/modules.txt. The ESI dongle attaches to the + normal 9-pin serial port connector, and can currently only be used + by IrTTY. To activate support for ESI dongles you will have to + insert "irattach -d esi" in the /etc/irda/drivers script. + +ACTiSYS IR-220L and IR220L+ dongle +CONFIG_ACTISYS_DONGLE + Say Y here if you want to build support for the ACTiSYS + IR-220L and IR220L+ dongles. If you want to compile it as a module, + say M here and read Documentation/modules.txt. The ACTiSYS dongles + attaches to the normal 9-pin serial port connector, and can + currently only be used by IrTTY. To activate support for ACTiSYS + dongles you will have to insert "irattach -d actisys" or + "irattach -d actisys_plus" in the/etc/irda/drivers script. + +Tekram IrMate 210B dongle +CONFIG_TEKRAM_DONGLE + Say Y here if you want to build support for the Tekram IrMate 210B + dongle. If you want to compile it as a module, say M here + and read Documentation/modules.txt. The Tekram dongle attaches to + the normal 9-pin serial port connector, and can currently only be + used by IrTTY. To activate support for Tekram dongles you will have + to insert "irattach -d tekram" in the /etc/irda/drivers script. + +Greenwich GIrBIL dongle +CONFIG_GIRBIL_DONGLE + Say Y here if you want to build support for the Greenwich GIrBIL + dongle. If you want to compile it as a module, say M here and read + Documentation/modules.txt. The Greenwich dongle attaches to the + normal 9-pin serial port connector, and can currently only be used + by IrTTY. To activate support for Greenwich dongles you will have to + insert "irattach -d girbil" in the /etc/irda/drivers script. + +Parallax Litelink dongle +CONFIG_LITELINK_DONGLE + Say Y here if you want to build support for the Parallax Litelink + dongle. If you want to compile it as a module, say M here and read + Documentation/modules.txt. The Parallax dongle attaches to the + normal 9-pin serial port connector, and can currently only be used + by IrTTY. To activate support for Parallax dongles you will have to + insert "irattach -d litelink" in the /etc/irda/drivers script. + +Adaptec Airport 1000 and 2000 dongle +CONFIG_AIRPORT_DONGLE + Say Y here if you want to build support for the Adaptec Airport 1000 + and 2000 dongles. If you want to compile it as a module, say M here + and read Documentation/modules.txt. The module will be called + airport.o. The Airport dongle attaches to the normal 9-pin serial + port connector, and can currently only be used by IrTTY. To activate + support for Airport dongles you will have to insert "irattach -d + airport" in the /etc/irda/drivers script. + +VME (Motorola and BVM) support +CONFIG_VME + Say Y here if you want to build a kernel for a 680x0 based VME + board. Boards currently supported include Motorola boards MVME162, + MVME166, MVME167, MVME172, and MVME177. BVME4000 and BVME6000 + boards from BVM Ltd are also supported. + +MVME162, 166 and 167 support +CONFIG_MVME16x + Say Y to include support for Motorola VME boards. This will build a + kernel which can run on MVME162, MVME166, MVME167, MVME172, and + MVME177 boards. If you select this option you will have to select + the appropriate drivers for SCSI, Ethernet and serial ports later + on. + +BVME4000 and BVME6000 support +CONFIG_BVME6000 + Say Y to include support for VME boards from BVM Ltd. This will + build a kernel which can run on BVME4000 and BVME6000 boards. If + you select this option you will have to select the appropriate + drivers for SCSI, Ethernet and serial ports later on. + +Use write-through caching for 68060 supervisor accesses +CONFIG_060_WRITETHROUGH + The 68060 generally uses copyback caching of recently accessed data. + Copyback caching means that memory writes will be held in an on-chip + cache and only written back to memory some time later. Saying Y + here will force supervisor (kernel) accesses to use writethrough + caching. Writethrough caching means that data is written to memory + straight away, so that cache and memory data always agree. + Writethrough caching is less efficient, but is needed for some + drivers on 68060 based systems where the 68060 bus snooping signal + is hardwired on. The 53c710 SCSI driver is known to suffer from + this problem. + +NCR53C710 SCSI driver for MVME16x +CONFIG_MVME16x_SCSI + The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710 + SCSI controller chip. Almost everyone using one of these boards + will want to say Y to this question. + +NCR53C710 SCSI driver for BVME6000 +CONFIG_BVME6000_SCSI + The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710 + SCSI controller chip. Almost everyone using one of these boards + will want to say Y to this question. + +Simple 53c710 SCSI support (Compaq, NCR machines) +CONFIG_SCSI_SIM710 + This is a driver for the NCR53C710 chip commonly found in Compaq and + NCR machines. If you are looking for 53C710 support for an Amiga or + some 680x0 based VME card then you probably want the other NCR53C710 + driver. + +MVME16x Ethernet support +CONFIG_MVME16x_NET + This is the driver for the Ethernet interface on the Motorola + MVME162, 166, 167, 172 and 177 boards. Say Y here to include the + driver for this chip in your kernel. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + +BVME6000 Ethernet support +CONFIG_BVME6000_NET + This is the driver for the Ethernet interface on BVME4000 and + BVME6000 VME boards. Say Y here to include the driver for this chip + in your kernel. If you want to compile it as a module, say M here + and read Documentation/modules.txt. + +CD2401 support for MVME166/7 serial ports +CONFIG_SERIAL167 + This is the driver for the serial ports on the Motorola MVME166, + 167, and 172 boards. Everyone using one of these boards should say + Y here. + +SCC support for MVME162 serial ports +CONFIG_MVME162_SCC + This is the driver for the serial ports on the Motorola MVME162 and + 172 boards. Everyone using one of these boards should say Y here. + +SCC support for BVME6000 serial ports +CONFIG_BVME6000_SCC + This is the driver for the serial ports on the BVME4000 and BVME6000 + boards from BVM Ltd. Everyone using one of these boards should say + Y here. + +Support for user-space parallel port device drivers +CONFIG_PPDEV + Saying Y to this adds support for /dev/parport device nodes. This + is needed for programs that want portable access to the parallel + port, for instance deviceid (which displays Plug-and-Play device + IDs). + + This is the parallel port equivalent of SCSI generic support (sg). + It is safe to say N to this -- it is not needed for normal printing + or parallel port CD-ROM/disk support. + + This support is also available as a module. If you want to compile + it as a module, say M here and read Documentation/modules.txt. The + module will be called ppdev.o. + + If unsure, say N. + +Kernel httpd acceleration (EXPERIMENTAL) +CONFIG_KHTTPD + The kernel httpd acceleration daemon (kHTTPd) is a (limited) + web server build into the kernel. It is limited since it can only + serve files from the filesystem. Saying "M" here builds the + kHTTPd module; this is NOT enough to have a working kHTTPd. + For safety reasons, the module has to be activated by doing a + "echo 1 > /proc/sys/net/khttpd/start" after inserting the module. + + Before using this, read the README in /usr/src/linux/net/khttpd ! + + The kHTTPd is experimental. Be careful when using it on a production + machine. Also note that kHTTPd doesn't support virtual servers yet. + +# +# A couple of things I keep forgetting: +# capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, +# Intel, IRQ, Linux, MSDOS, NetWare, NetWinder, NFS, +# PCI, SCSI, SPARC +# two words: hard drive, hard disk, sound card, home page +# other: it's safe to save; daemon; use --, not - or --- +# +# +# This is used by Emacs' spell checker ispell.el: +# +# LocalWords: CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab +# LocalWords: unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz +# LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd +# LocalWords: HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN +# LocalWords: ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt +# LocalWords: BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB +# LocalWords: netscape gcc LD CC toplevel MODVERSIONS insmod rmmod modprobe IP +# LocalWords: genksyms INET loopback gatewaying ethernet PPP ARP Arp MEMSIZE +# LocalWords: howto multicasting MULTICAST MBONE firewalling ipfw ACCT resp ip +# LocalWords: proc acct IPIP encapsulator decapsulator klogd PCTCP RARP EXT PS +# LocalWords: telnetting subnetted NAGLE rlogin NOSR ttyS TGA techinfo mbone nl +# LocalWords: Mb SKB IPX Novell dosemu Appletalk DDP ATALK vmalloc visar ehome +# LocalWords: SD CHR scsi thingy SG CD LUNs LUN jukebox Adaptec BusLogic EATA +# LocalWords: buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext +# LocalWords: QLOGIC qlogic TMC seagate Trantor ultrastor FASST wd NETDEVICES +# LocalWords: unix BBS linux CSLIP PLIP Kirch's LDP CSlip SL SCC IRQ csustan +# LocalWords: Turbo Laplink plip NCSA port's ReQuest IRQs EQL SMC AMD PCnet NE +# LocalWords: COM ELPLUS Com EtherLinkIII VLB Arcnet Cabletron DEPCA DE carlos +# LocalWords: depca EtherWorks EWRK ewrk SEEQ EtherExpress EEXPRESS NI xxx dia +# LocalWords: EtherExpress WaveLAN wavelan PCLAN HPLAN VG SK Ansel Xen de ZNET +# LocalWords: PCMCIA cb stanford LAN TEC RealTek ATP atp DLINK NetTools VISWS +# LocalWords: TR Sony CDU caddyless cdu Mitsumi MCD cd mcd XA MultiSession CDA +# LocalWords: Matsushita Panasonic SBPCD Soundblaster Longshine sbpcd Aztech +# LocalWords: Okano Wearnes AZTCD CDD SE aztcd sonycd Goldstar GSCD Philips fs +# LocalWords: LMS OPTCD Sanyo SJCD minix faqs xiafs XIA msdos mtools Cichocki +# LocalWords: std softlinks umssync NetworkFileSharing nfsd mountd CDs HPFS TI +# LocalWords: hpfs SYSV SCO iBCS Wyse WordPerfect tsx mit unixes sysv NR irisa +# LocalWords: SMB WfW Cyclades async mux Logitech busmouse MouseSystem aka AST +# LocalWords: PSMOUSE Compaq trackballs Travelmate Inport ATIXL ATI busmice ld +# LocalWords: gpm config QIC DYNCONF FTAPE Stor Ftape ftape pcsndrv manpage NT +# LocalWords: readprofile diskdrives org com masq EtherTalk tcp netrom sunacm +# LocalWords: misc AIC aic pio scc Portmaster eql GIS PhotoCDs MCDX Perell PG +# LocalWords: mcdx gscd optcd sjcd ISP hdparm Workgroups Lan samba PARIDE PCD +# LocalWords: filesystems smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI +# LocalWords: chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport +# LocalWords: Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard +# LocalWords: Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem +# LocalWords: carleton Deskstation DECstation SUNFD JENSEN Noname XXXM SLiRP +# LocalWords: pppd Zilog ZS SRM bootloader ez mainmenu rarp ipfwadm paride pcd +# LocalWords: RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff +# LocalWords: dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress +# LocalWords: ICL EtherTeam ETH IDESCSI TXC SmartRAID SmartCache httpd sjc dlp +# LocalWords: thesphere TwoServers BOOTP DHCP ncpfs BPQETHER BPQ MG HIPPI cern +# LocalWords: bsd comp SPARCstation le SunOS ie Gracilis PackeTwin PT pt LU FX +# LocalWords: FX TEAC CR LCS mS ramdisk IDETAPE cmd fperllo encis tcfs unisa +# LocalWords: Vertos Genoa Funai hsfs NCP NetWare tgz APM apm ioctls UltraLite +# LocalWords: TravelMate CDT LCD backlight VC RPC Mips AXP barlow cdrecord pg +# LocalWords: PMAX MILO Alphas Multia Tseng linuxelf endian mipsel mips drv HT +# LocalWords: kerneld callouts AdvanSys advansys Admin WDT DataStor EP verden +# LocalWords: wdt hdb hdc bugfix SiS vlb Acculogic CSA DTC dtc Holtek ht QDI +# LocalWords: QD qd UMC umc ALI ali lena fnet fr azstarnet cdr fb MDA ps esdi +# LocalWords: Avanti XL AlphaStations Jensen DECpc AXPpci UDB Cabriolet MCA RC +# LocalWords: AlphaPC mca AOUT OUTput PPro sipx gwdg lo nwe FourPort Boca unm +# LocalWords: Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT +# LocalWords: OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP +# LocalWords: NOWAYOUT behaviour dialin isdn callback BTX Teles ICN EDSS Cisco +# LocalWords: ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr +# LocalWords: ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD +# LocalWords: initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS +# LocalWords: FC DC dc PPA IOMEGA's ppa RNFS FMV Fujitsu ARPD arpd loran layes +# LocalWords: FRAD indiana framerelay DLCI DCLIs Sangoma SDLA mrouted sync sec +# LocalWords: Starmode Metricom MosquitoNet mosquitonet kbit nfsroot Digiboard +# LocalWords: DIGI Xe Xeve digiboard UMISC touchscreens mtu ethernets HBAs MEX +# LocalWords: Shifflett netcom js jshiffle WIC DECchip ELCP EtherPower dst RTC +# LocalWords: rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP +# LocalWords: Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au artoo MFB +# LocalWords: hitchcock Crynwr cnam pktdrvr NCSA's CyDROM CyCDROM FreeBSD NeXT +# LocalWords: NeXTstep disklabel disklabels SMD FFS tm AmigaOS diskfiles Un IQ +# LocalWords: Bernd informatik rwth aachen uae affs multihosting bytecode java +# LocalWords: applets applet JDK ncsa cabi SNI Alphatronix readme LANs scarab +# LocalWords: winsock RNIS caltech OSPF honour Honouring Mbit LocalTalk DEFRAG +# LocalWords: localtalk download Packetwin Baycom baycom interwork ASCII JNT +# LocalWords: Camtec proxying indyramp defragment defragmented UDP FAS FASXX +# LocalWords: FastSCSI SIO FDC qlogicfas QLogic qlogicisp setbaycom ife ee LJ +# LocalWords: ethz ch Travelmates ProAudioSpectrum ProAudio SoundMan SB SBPro +# LocalWords: Thunderboard SM OPL FM ADLIB TSR Gravis MPU PSS ADI SW DSP codec +# LocalWords: ADSP ESC ASIC daughtercard GUSMAX MSS NX AdLib Excell Ensoniq YM +# LocalWords: SoundScape Spea MediaTriX AudioTriX WSS OTI ThunderBoard VoxWare +# LocalWords: Soundscape SSCAPE TRIX MediaTrix PnP Maui dsp midixx EIA getty +# LocalWords: mgetty sendfax gert greenie muc lowlevel Lasermate LanManager io +# LocalWords: OOPSes trackball binghamton mobileip ncr IOMAPPED settags ns ser +# LocalWords: setsync NEGO MPARITY autotuning prefetch PIIX cdwrite utils rc +# LocalWords: PCWATCHDOG berkprod bitgate boldt ucsb jf kyoto jp euc Tetsuyasu +# LocalWords: YAMADA tetsu cauchy nslab ntt nevod perm su doc kaf kheops wsc +# LocalWords: traduc Bourgin dbourgin menuconfig kfill READMEs HOWTOs Virge WA +# LocalWords: IDEDISK IDEFLOPPY EIDE firewalls QMAGIC ZMAGIC LocalWords opti +# LocalWords: SVGATextMode vga svga Xkernel syr jmwobus comfaqs dhcp flakey GD +# LocalWords: IPv IPng interoperability ipng ipv radio's tapr pkthome PLP nano +# LocalWords: Ses Mhz sethdlc SOUNDMODEM WindowsSoundSystem smdiag pcf inka ES +# LocalWords: smmixer ptt circ soundmodem MKISS FDDI DEFEA DEFPA DEFXX redhat +# LocalWords: HyperNews khg mconv sed lina wuftpd MicroChannel netlink irc cum +# LocalWords: raudio RealAudio PPROP NETBIOS GUI IBMMCA ELMC Racal Interlan fi +# LocalWords: eth shapecfg src esp PCWD PREVSTAT bootparam sig bitwizard SBC +# LocalWords: downloads AFSK TCM FP Karn KA FSK RUH LinkSys cron mouseman LLC +# LocalWords: SyQuest SyQuest's CCITT MicroSolutions BPCD bpcd ESPSERIAL PROM +# LocalWords: SUNESP openprom OPENPROMIO quango themall al TT MC MMU LC RMW AA +# LocalWords: INSNS Ataris AutoConfig ZORRO OCS AMIFB Agnus Denise ECS CDTV GB +# LocalWords: AGA Cybervision CYBER GSP TMS DMI Zorro ACSI ROMs SLM BioNet GVP +# LocalWords: PAMsNet TekMagic Cyberstorm MkI CYBERSTORMII MkII BLZ onboard cx +# LocalWords: Village Tronic ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB +# LocalWords: Rhotron BioData's Multiface AMIGAMOUSE COPCON Amiga's bitplanes +# LocalWords: ATARIMOUSE MFPSER SCC's MegaSTE ESCC Atari's GVPIOEXT DMASOUND +# LocalWords: fdutils cisco univercd rpcg htm iface lapb LAPBETHER tpqic qic +# LocalWords: SYNTH xd en binfmt aout ipip terra ipx sd sr sg wic framebuffer +# LocalWords: ibmmca lapbether mkiss dlci sdla fmv eepro eexpress ni hp ne es +# LocalWords: ibmtr isofs ROMFS romfs pcxx cyclades istallion psaux msbusmouse +# LocalWords: atixlmouse sbin softdog pcwd USS Lite ACI miroSOUND PCM miroPCM +# LocalWords: microcontroller miro Voxware downloading teles acsi slm gvp ltpc +# LocalWords: atari ariadne amigamouse atarimouse builtin IPDDP maths bradford +# LocalWords: AppleTalk Farallon PhoneNet Zubkoff lnz SCCB HAPN WANs vesafb nt +# LocalWords: wanrouter WANPIPE multiprotocol Mbps wanpipe EtherWORKS nodma SC +# LocalWords: smp HiSax SiemensChipSet Siemens AVM Elsa ITK hisax PCC MICROR +# LocalWords: Mircolink EURO DSS Spellcaster BRI sc spellcast Digiboards GPIO +# LocalWords: SYMBIOS COMPAT SDMS rev ASUS Tekram HX VX API ibmmcascsi ASY asy +# LocalWords: loader's PCnetPCI automounter AUTOFS amd autofs VT Gallant's Pnp +# LocalWords: AEDSP aedsp enskip tik Sysctl sysctl PARPORT parport pnp IDs EPP +# LocalWords: Autoprobe bart patrickr HDLS READBACK AB usr DAMA DS SparQ aten +# LocalWords: Symbios PCscsi tmscsim RoamAbout GHz Hinds contrib mathematik ok +# LocalWords: darmstadt okir DIGIEPCA International's Xem digiepca epca bootup +# LocalWords: zorro CAPI AVMB capi avmb VP SYN syncookies EM em pc Ethertalk +# LocalWords: Dayna DL Daynatalk LT PhoneNET ATB Daystar queueing CMDS SCBs ls +# LocalWords: SCB STATS Thinnet ThunderLAN TLAN Netelligent NetFlex tlan james +# LocalWords: caldera Preload Preloading slowdowns schoebel uni NBD nbd prog +# LocalWords: stuttgart rdist TRANS hostnames mango jukeboxes ESS userland PD +# LocalWords: hardlinked NAMETRANS env mtab fstab umount nologin runlevel gid +# LocalWords: transname filespace adm Nodename hostname uname Kernelname bootp +# LocalWords: KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb +# LocalWords: dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS +# LocalWords: nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY +# LocalWords: Sitor Amtor Pactor GTOR hayes TX TMOUT JFdocs HIGHMEM DAC IRQ's +# LocalWords: IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu +# LocalWords: unam mx miguel koobera uic EMUL solaris pp ieee lpsg co DMAs TOS +# LocalWords: BLDCONFIG preloading jumperless BOOTINIT modutils multipath GRE +# LocalWords: misconfigured autoconfiguration IPGRE ICMP tracert ipautofw PIM +# LocalWords: netis rlynch autofw ipportfw monmouth ipsubs portforwarding pimd +# LocalWords: portfw PIMSM netweb usc pim pf EUI aggregatable PB decapsulate +# LocalWords: ipddp Decapsulation DECAP bool HAMRADIO tcpdump af CDs tx FBCON +# LocalWords: ethertap multisession PPC MMIO GDT GDTH ICP gdth hamradio bpp +# LocalWords: lmh weejock AIMSlab RadioTrack RTRACK HZP OptoSCC TRX rx TRXECHO +# LocalWords: DMASCC paccomm dmascc addr cfg oevsv oe kib picpar FDX baudrate +# LocalWords: baudrates fdx HDX hdx PSK kanren frforum QoS SCHED CBQ SCH sched +# LocalWords: sch cbq CSZ Shenker Zhang csz SFQ sfq TBF tbf PFIFO fifo PRIO RW +# LocalWords: prio Micom xIO dwmw rimi OMIRR omirr omirrd unicode ntfs cmu NIC +# LocalWords: Braam braam Schmidt's freiburg nls codepages codepage Romanian +# LocalWords: Slovak Slovenian Sorbian Nordic iso Catalan Faeroese Galician SZ +# LocalWords: Valencian Slovene Esperanto Estonian Latvian Byelorussian KOI mt +# LocalWords: charset Inuit Greenlandic Sami Lappish koi SOFTCURSOR softcursor +# LocalWords: Specialix specialix DTR RTS RTSCTS cycladesZ Exabyte ftape's inr +# LocalWords: Iomega's LBFM claus ZFTAPE VFS zftape zft William's lzrw DFLT kb +# LocalWords: MTSETBLK MTIOCTOP qft setblk zftape's tar's afio's setdrvbuffer +# LocalWords: Procfs Exabyte's THR FCD sysvinit init PSC pscwdt VMIDI Euro SAB +# LocalWords: Mostek Fastlane PowerMac PReP PMAC PowerPC Macintoshes Starmax +# LocalWords: PowerStack Starmaxes MCOMMON DEVICETREE ATY IMS IMSTT videodev +# LocalWords: BT Hauppauge STB bttv Quickcam BW BWQCAM bw qcam Mediavision PMS +# LocalWords: pms Avatar Freecom Imation Superdisk BPCK bpck COMM comm DSTR ru +# LocalWords: dstr EPAT EPEZ epat EPIA epia FreeCom FRPW frpw KingByte KBIC HW +# LocalWords: KingByte's kbic OnSpec ValuStore FASTROUTE fastroute FLOWCONTROL +# LocalWords: struct APIC realtime OSs LynxOS CNC tmp cvf HFS hfs ADFS Risc os +# LocalWords: adfs ncpmount namespace SUBDIR reexport NDS kcore FT SPX spx DAT +# LocalWords: interserver BLKSZ NUMBUFFERS apmd Tadpole ANA roestock QuickCam +# LocalWords: isapnptools Colour CQCAM colour Connectix QuickClip prive mentre +# LocalWords: KMOD kmod conformant utexas kharker UnixWare Mwave cgi cl ts ibm +# LocalWords: eXchange threepio oakland simtel pre ULTRAMCA EtherLink isa luik +# LocalWords: EtherLink OpenBSD pts DEVPTS devpts ptmx ttyp glibc readback SA +# LocalWords: mwave OLDCARD isdnloop linklevel loopctrl Eicon Diehl DIEHLDIVA +# LocalWords: ASUSCOM AsusCom TELEINT semiactiv Sedlbauer Sportster TA MIC ITH +# LocalWords: NETjet NetJet Niccy Neuhaus sparcs AOC AOCD AOCE Microlink SAA +# LocalWords: teletext WinTV saa iproute tc Quadra Performa PowerBook tor AUN +# LocalWords: setserial compsoc steve Econet econet AUNUDP psched TEQL TLE CLS +# LocalWords: teql FW Ingres TwistedPair MTRR MTRRs mtrr cfs crypto TD ktti KT +# LocalWords: PHd ICS ipchains adelaide rustcorp syslog Cumana steganography +# LocalWords: AcornSCSI EcoSCSI EESOX EESOXSCSI Powertec POWERTECSCSI dec SF +# LocalWords: RadioReveal gatekeeper aimslab aztech FMI sf fmi RTL rtl cesdis +# LocalWords: Yellowfin gsfc nasa gov yellowfin pcnet Mylex LNE lne EtherH hs +# LocalWords: EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson CT +# LocalWords: SGALAXY Waverider DSPxxx TRXPRO AudioTrix OSWF MOT CFB DSY kbps +# LocalWords: tuwien kkudielk LVD mega lun MAXTAGS Gbps arcnet Olicom SKTR SNA +# LocalWords: SysKonnect tms380tr sna etherboot ufs NetBEUI MultiSound MSNDCLAS GX +# LocalWords: MSNDINIT MSNDPERM MSNDPIN PNDSPINI PNDSPERM Ensoniq's RetinaZ SS +# LocalWords: AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner CLgen UPA +# LocalWords: swansea shtml Zoltrix zoltrix BINUTILS EGCS binutils VIDC DACs +# LocalWords: CyberVision Cirrus PowerBooks Topcat SBUS CGsix TurboGX BWtwo SS +# LocalWords: CGthree TCX unswapable vfb fbcon hicolor truecolor AFB ILBM SOC +# LocalWords: IPLAN gracilis Fibre SBus SparcSTORAGE SV jnewbigin swin QNX qnx +# LocalWords: PTY PTYS ptyxx ttyxx PTYs ssh sb Avance ALS pss pvv kerneli hd +# LocalWords: synth WaveFront MSND NONPNP AudioExcelDSP STRAM APUS CHRP MBX Nx +# LocalWords: PowerMac's BMAC radiotrack rtrack miropcm OFFBOARD HPT UDMA DVD +# LocalWords: hpt fokus gmd Cyrix DXL SLC DLC NexGen MediaGX GXm IDT WinChip +# LocalWords: MMX MII valkyrie mdacon vdolive VDOLive cuseeme CU hippi rrunner +# LocalWords: SeeMe ipmasqadm juanjox ipmarkfw markfw TNCs Microdyne rhine lib +# LocalWords: libc jsX gamepad gameport CHF FCS FPGaming MadCatz ASSASIN GrIP +# LocalWords: Assasin gamepads GamePad PDPI gamecards gamecard WingMan BSP WCS +# LocalWords: ThunderPad CyberMan SideWinder ThrustMaster DirectConnect NES XF +# LocalWords: Millenium SNES PSX Multisystem Nintendo PlayStation Amstrad CPC +# LocalWords: Sega TurboGraFX Steffen Schwenke Multiststem PDIF FIFOSIZE EPLUS +# LocalWords: PowerUP RoadRunner tahallah dos functionkey setterm imladris Woz +# LocalWords: PowerMacs Winbond Algorithmics ALGOR algor ECOFF IRIX SGI SGI's +# LocalWords: gfx virtualized Xpmac mklinux XFree FBDev Woodhouse mvhi Seeq fp +# LocalWords: SGISEEQ HIgh ADB ADBMOUSE crosscompiler CROSSCOMPILE FPE GDB gdb +# LocalWords: JOYPORT rp spoofing DawiControl NOGENSUPP EEPROM HSSI Alessandro +# LocalWords: singleprocessor tex MATHEMU FRIQ Maxell friq Alcor XLT AlphaBook +# LocalWords: AlphaPCI DP LX Miata Mikasa Noritake RPX UX BX Takara EV PRIMO +# LocalWords: TSC Matrox Productiva matroxfb matrox multihead ia linuxhq MFW +# LocalWords: mfw AAA MCS Initio XXU initio imm AutoDetect IZIP CTR usec HDLC +# LocalWords: COSA SRP muni cz kas cosa Alteon AceNIC acenic VTOC OSes GMT SAx +# LocalWords: Inspiron localtime INTS Thinkpads Ralf Brown's Flightstick NNN +# LocalWords: Xterminator Blackhawk NN mpu ioports DCA HPDCA HPLANCE DIO Corel +# LocalWords: GemTek gemtek CMDLINE IrDA PDA's irmanager irattach RR AVA DN rg +# LocalWords: uit dagb irda LSAP IrLMP RR's IrLAP IR alloc skb's kfree skb's +# LocalWords: GZIP IrLAN NetbeamIR ESI JetEye IrOBEX IrCOMM TTY's minicom dti +# LocalWords: ircomm ircomm pluto thiguchi IrTTY Linux's bps NetWinder MIR NSC +# LocalWords: ACTiSYS Dongle dongle dongles esi actisys IrMate tekram BVM MVME +# LocalWords: BVME BVME WRITETHROUGH copyback writethrough fwmark syncookie tu +# LocalWords: alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid +# LocalWords: QNXFS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia +# LocalWords: IrLPT UIRCC Tecra Strebel jstrebel suse Eichwalder ke INI INIA +# LocalWords: FCP qlogicfc sym isapnp DTLK DoubleTalk rcsys dtlk DMAP SGIVW ar +# LocalWords: dmabuf EcoRadio MUTEFREQ GIrBIL girbil tepkom vol mha diplom PQS +# LocalWords: bmac Microgate SyncLink synclink hdlc excl ioaddr Tane tanep TCQ +# LocalWords: PDS SMALLDOS charsets bigfoot kernelfr mcs cls fw rsvp SKnet sk +# LocalWords: SKMC USB UHCI OHCI intel compaq usb ohci HCD Virt Compaq's hcd +# LocalWords: VROOTHUB KBD ARRs MCRs NWBUTTON nwbutton NUM WaveArtist APNE cpu +# LocalWords: apne blackhawke PlanB lu mlan planb NWFPE FPA nwfpe unbootable +# LocalWords: FPEmulator ds vmlinux initialisation discardable pgtable PGT mdw +# LocalWords: quicklist pagetable arthur StrongARM podule podules Autodetect +# LocalWords: dodgy IrPORT irport Litelink litelink SuSE rtfm internet hda CY +# LocalWords: multmode DriveReady SeekComplete DriveStatusError miscompile AEC +# LocalWords: mainboard's Digital's alim FastTrak aec PIIXn piix Gayle Eyetech +# LocalWords: Catweasel IDEDOUBLER Powerbook Centris ICSIDE RapIDE OSM HDM IOP +# LocalWords: HDM's OSM's lan FibreChannel ECP autoprobe itg lbl ipmasq cjb IC +# LocalWords: bieringer Caulfield's dreamtime decnet SIOCFIGCONF SIOCGIFCONF +# LocalWords: rtnetlink Endnode Aironet Arlan Telxon ylenurme arlan ACB aeschi +# LocalWords: Sealevel sealevel Cyclom br wanconfig tarball conectiva cycsyn +# LocalWords: devel bazar cyclomx NetGear GA IBMOL Lanstreamer uhci eu efs CYZ +# LocalWords: olympic linuxtr usbcore acm EZUSB downloader EFS XFS INTR op IIC +# LocalWords: heine soundcore JavaStations JavaStation GemTeks TerraTec TODO +# LocalWords: ActiveRadio Standalone terratec Rolf Offermanns rolf offermanns +# LocalWords: Zoran ZR Buz LML CPQ DA cpqarray PPDEV deviceid vlp ppdev atyfb +# LocalWords: AcceleRAID eXtremeRAID NETFILTER Netfilter masqueraded netfilter +# LocalWords: kernelnotes Cardbus PCMCIA's CardBus clgenfb Permedia YAM MMAP +# LocalWords: mmapped ATM atm PVCs SVCs InARP ATMARP neighbour neighbours MPOA +# LocalWords: VCs ENI FPGA Tonga MMF MF UTP printks ZeitNet ZN ZATM uPD SAR PN +# LocalWords: approx NICStAR NICs ForeRunnerLE Madge Collage ATMizer Dxxxx VCI +# LocalWords: ServeRAID IPS ips ipslinux gzip BSDCOMP LZW RAYCS Interphase app +# LocalWords: Tachyon IPHASE Surfboard NextLevel SURFboard jacksonville Tigon +# LocalWords: fventuri adelphia siglercm linuxpower AceNICs Starfire starfire +# LocalWords: ISOC CPiA cpia uss ACPI UDF DirectCD udf CDRW's OSF Manx acpi +# LocalWords: Unixware cymru Computone IntelliPort Intelliport computone SI sx +# LocalWords: adbmouse DRI DRM dlabs GMX PLCs Applicom fieldbus applicom int +# LocalWords: VWSND eg ESSSOLO CFU CFNR scribed eiconctrl eicon hylafax KFPU +# LocalWords: EXTRAPREC fpu mainboards KHTTPD kHTTPd khttpd Xcelerator +# LocalWords: LOGIBUSMOUSE diff -urN 2.3.29pre1/Documentation/debugging.txt 2.3.29pre1-ikd/Documentation/debugging.txt --- 2.3.29pre1/Documentation/debugging.txt Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/debugging.txt Mon Nov 22 16:56:22 1999 @@ -0,0 +1,60 @@ +Debugging the kernel for fun and profit. + +Assorted tools of varying usefulness exist to debug the kernel. By far +the best debugging tool is the human brain. As Linus has said :- + + ... + I'm afraid that I've seen too many people fix bugs + by looking at debugger output, and that almost + inevitably leads to fixing the symptoms rather than + the underlying problems. + ... + "Use the Source, Luke, use the Source. Be one with + the code.". Think of Luke Skywalker discarding the + automatic firing system when closing on the deathstar, + and firing the proton torpedo (or whatever) manually. + _Then_ do you have the right mindset for fixing kernel + bugs. + ... + +Having said that, sometimes reading the source is not enough. The +following tools exist in the IKD patch :- + + Debug kernel stack overflows + Detect software lockups + Kernel tracer (show logic flow through procedures) + + Written by Ingo Molnar . Currently + maintained by Mike Galbraith . + + Print-EIP on video ram + + Improved by Andrea Arcangeli. + + Kernel stack meter + Kernel real profiling + Semaphore deadlock detector + + Developed by Andrea Arcangeli. + + kdb + Written by Scott Lurndal (SGI) + Integration into IKD by Andrea Arcangeli. + + free_pages poisoner + Written by Andrea Arcangeli + + slab posioner made a config option + Done by Andrea Arcangeli + +The original merge of debugging tools into a single patch set (IKD) +is been done by Keith Owens . +PGP 917/C817FEC9. +Fingerprint 2B 25 0A 31 02 AE CA F7 73 0C 28 69 4A 7B 65 27 + +Currently the IKD patch is maintained by Andrea Arcangeli +and is dowloadable at: + + ftp://ftp.*.kernel.org/pub/linux/kernel/people/andrea/ikd/ + +Have fun with it. diff -urN 2.3.29pre1/Documentation/kdb/kdb.mm 2.3.29pre1-ikd/Documentation/kdb/kdb.mm --- 2.3.29pre1/Documentation/kdb/kdb.mm Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/kdb/kdb.mm Mon Nov 22 16:56:22 1999 @@ -0,0 +1,97 @@ +.ND "March 10, 1999" +.TL +Built-in Kernel Debugger for Linux +.AU "Scott Lurndal" SL 8U500 OS 33158 +.AT "Member Technical Staff" +.AF "Silicon Graphics, Inc." +.MT 2 +.AS +These programmer notes describe the built-in kernel debugger +for linux. +.AE +.H 1 "Overview" +This document describes the built-in kernel debugger available +for linux. This debugger allows the programmer to interactivly +examine kernel memory, disassemble kernel functions, set breakpoints +in the kernel code and display and modify register contents. +.P +A symbol table is included in the kernel image which enables all +symbols with global scope (including static symbols) to be used +as arguments to the kernel debugger commands. +.H 1 "Getting Started" +To include the kernel debugger in a linux kernel, use a +configuration mechanism (e.g. xconfig, menuconfig, et. al.) +to enable the \fBCONFIG_KDB\fP option. Additionally, for accurate +stack tracebacks, it is recommended that the \fBCONFIG_KDB_FRAMEPTR\fP +option be enabled. \fBCONFIG_KDB_FRAMEPTR\fP changes the compiler +flags so that the frame pointer register will be used as a frame +pointer rather than a general purpose register. +.P +After linux has been configured to include the kernel debugger, +make a new kernel with the new configuration file (a make clean +is recommended before making the kernel), and install the kernel +as normal. +.P +When booting the new kernel using \fIlilo\fP(1), the 'kdb' flag +may be added after the image name on the \fBLILO\fP boot line to +force the kernel to stop in the kernel debugger early in the +kernel initialization process. If the kdb flag isn't provided, +then kdb will automatically be invoked upon system panic or +when the +\fBPAUSE\fP +key is used from the keyboard. +.P +Kdb can also be used via the serial port. Set up the system to +have a serial console (see \fIDocumentation/serial-console.txt\fP). +The \fBControl-A\fP key sequence on the serial port will cause the +kernel debugger to be entered with input from the serial port and +output to the serial console. +.H 2 "Basic Commands" +There are several categories of commands available to the +kernel debugger user including commands providing memory +display and modification, register display and modification, +instruction disassemble, breakpoints and stack tracebacks. +.P +The following table shows the currently implemented commands: +.DS +.TS +box, center; +l | l +l | l. +Command Description +_ +bc Clear Breakpoint +bd Disable Breakpoint +be Enable Breakpoint +bl Display breakpoints +bp Set or Display breakpoint +bpa Set or Display breakpoint globally +cpu Switch cpus +env Show environment +go Restart execution +help Display help message +id Disassemble Instructions +ll Follow Linked Lists +md Display memory contents +mds Display memory contents symbolically +mm Modify memory contents +reboot Reboot the machine +rd Display register contents +rm Modify register contents +set Add/change environment variable +.TE +.DE +.P +Further information on the above commands can be found in +the appropriate manual pages. Some commands can be abbreviated, such +commands are indicated by a non-zero \fIminlen\fP parameter to +\fBkdb_register\fP; the value of \fIminlen\fP being the minimum length +to which the command can be abbreviated (for example, the \fBgo\fP +command can be abbreviated legally to \fBg\fP). +.P +If an input string does not match a command in the command table, +it is treated as an address expression and the corresponding address +value and nearest symbol are shown. +.H 1 Writing new commands +.H 2 Writing a built-in command +.H 2 Writing a modular command diff -urN 2.3.29pre1/Documentation/kdb/kdb_bp.man 2.3.29pre1-ikd/Documentation/kdb/kdb_bp.man --- 2.3.29pre1/Documentation/kdb/kdb_bp.man Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/kdb/kdb_bp.man Mon Nov 22 16:56:22 1999 @@ -0,0 +1,131 @@ +.TH BD 1 "09 March 1999" +.SH NAME +bc, bd, be, bl, bp, bpa \- breakpoint commands +.SH SYNOPSIS +bp \fIaddress-expression\fP [\f(CWDATAR|DATAW|IO\fP [\fIlength\fP]] +.LP +bpa \fIaddress-expression\fP [\f(CWDATAR|DATAW|IO\fP [\fIlength\fP]] +.LP +bd \fIbreakpoint-number\fP +.LP +bc \fIbreakpoint-number\fP +.LP +be \fIbreakpoint-number\fP +.LP +bl +.SH DESCRIPTION +The +.B bp +command is used to establish a breakpoint. +The \fIaddress-expression\fP may be a numeric value (decimal or +hexidecimal), a symbol name, a register name preceeded by a +percent symbol '%', or a simple expression consisting of a +symbol name, an addition or subtraction character and a numeric +value (decimal or hexidecimal). +.P +The \fIaddress-expression\fP may also consist of a single +asterisk '*' symbol which indicates that the command should +operate on all existing breakpoints (valid only for \fBbc\fP, +\fBbd\fP and \fBbe\fP). +.P +Three different types of +breakpoints may be set: + +.TP 8 +Instruction +Causes the kernel debugger to be invoked from the debug exception +path when an instruction is fetched from the specified address. This +is the default if no other type of breakpoint is requested. + +.TP 8 +DATAR +Causes the kernel debugger to be entered when data of length +\fIlength\fP is read from or written to the specified address. +This type of breakpoint must use a processor debug register +thus placing a limit of four on the number of data and I/O +breakpoints that may be established. + +.TP 8 +DATAW +Enters the kernel debugger when data of length \fIlength\fP +is written to the specified address. \fIlength\fP defaults +to four bytes if it is not explicitly specified. Note that the +processor will have already overwritten the prior data at the +breakpoint location before the kernel debugger is invoked. The +prior data should be saved before establishing the +breakpoint, if required. + +.TP 8 +IO +Enters the kernel debugger when an \fBin\fP or \fBout\fP instruction +targets the specified I/O address. + +.P +The +.B bpa +command will establish a breakpoint on all processors in an +SMP system. This command is not available in an uniprocessor +kernel. +.P +The +.B bd +command will disable a breakpoint without removing it from +the kernel debuggers breakpoint table. This can be used to +keep more than 4 breakpoints in the breakpoint table without +exceeding the processor breakpoint register count. +.P +The +.B be +command will re-enable a disabled breakpoint. +.P +The +.B bc +command will clear a breakpoint from the breakpoint table. +.P +The +.B bl +command will list the existing set of breakpoints. +.SH LIMITATIONS +Currently the kernel debugger does not use the int 03 method +of establishing instruction breakpoints, so there may only be +four active instruction and data breakpoints at any given time. +.P +There is a compile time limit of sixteen entries in the +breakpoint table at any one time. +.SH ENVIRONMENT +The breakpoint subsystem does not currently use any environment +variables. +.SH SMP CONSIDERATIONS +Breakpoints which use the processor breakpoint registers +are only established on the processor which is +currently active. If you wish breakpoints to be universal +use the 'bpa' command. +.SH EXAMPLES +.TP 8 +bp schedule +Sets an instruction breakpoint at the begining of the +function \fBschedule\fP. + +.TP 8 +bp schedule+0x12e +Sets an instruction breakpoint at the instruction located +at \fBschedule\fP+\fI0x12e\fP. + +.TP 8 +bp ttybuffer+0x24 dataw +Sets a data write breakpoint at the location referenced by +\fBttybuffer\fP+\fI0x24\fP for a length of four bytes. + +.TP 8 +bp 0xc0254010 datar 1 +Establishes a data reference breakpoint at address \fB0xc0254010\fP +for a length of one byte. + +.TP 8 +bp +List current breakpoint table. + +.TP 8 +bd 0 +Disable breakpoint #0. + diff -urN 2.3.29pre1/Documentation/kdb/kdb_bt.man 2.3.29pre1-ikd/Documentation/kdb/kdb_bt.man --- 2.3.29pre1/Documentation/kdb/kdb_bt.man Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/kdb/kdb_bt.man Mon Nov 22 16:56:22 1999 @@ -0,0 +1,67 @@ +.TH BT 1 "15 March 1999" +.SH NAME +bt \- Stack Traceback command +.SH SYNOPSIS +bt [ ] +.LP +btp +.SH DESCRIPTION +The +.B bt +command is used to print a stack traceback. It uses the +current registers (see \fBrd\fP command) to determine +the starting context and attempts to provide a complete +stack traceback for the active thread. If \fIstack-frame-address\fP +is supplied, it is assumed to point to the start of a valid +stack frame and the stack will be traced back from that +point (e.g. on i386 architecture, \fIstack-frame-address\fP +should be the stack address of a saved \fB%eip\fP value from a \fBcall\fP +instruction). +.P +A kernel configuration option \fBCONFIG_KDB_FRAMEPTR\fP should +be enabled so that the compiler will utilize the frame pointer +register properly to maintain a stack which can be correctly +analyzed. +.P +The \fBbt\fP command will attempt to analyze the stack without +frame pointers if the \fBCONFIG_KDB_FRAMEPTR\fP option is not +enabled, but the analysis is difficult and may not produce +accurate nor complete results. +.P +The \fBbtp\fP command will analyze the stack for the given +process identification (see the \fBps\fP command). +.SH LIMITATIONS +If the kernel is compiled without frame pointers, stack tracebacks +may be incomplete. The \fBmds %esp\fP command may be useful in +attemping to determine the actual stack traceback manually. +.P +The \fBbt\fP command may print more arguments for a function +than that function accepts; this happens when the C compiler +doesn't immediately pop the arguments off the stack upon return +from a called function. When this is this case, these extra +stack words will be considered additional arguments by the \fBbt\fP +command. +.SH ENVIRONMENT +The \fBBTARGS\fP environment variable governs the maximum number +of arguments that are printed for any single function. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.nf +.na +.ft CW +[root@host /root]# cat /proc/partitions +Entering kdb on processor 0 due to Debug Exception @ 0xc01845e3 +Read/Write breakpoint #1 at 0xc024ddf4 +kdb> bt + EBP Caller Function(args) +0xc74f5f44 0xc0146166 get_partition_list(0xc74d8000) +0xc74f5f8c 0xc01463f3 get_root_array(0xc74d8000, 0x13, 0xc74f5f88, 0xf3, 0xc00) +0xc74f5fbc 0xc0126138 array_read(0xc76cd80, 0x804aef8, 0xc00, 0xc76cdf94) +0xbffffcd4 0xc0108b30 sys_read(0x3, 0x804aef8, 0x1000, 0x1000, 0x804aef8) +kdb> bp +Instruction Breakpoint #0 at 0xc0111ab8 (schedule) in dr0 is disabled on cpu 0 +Data Access Breakpoint #1 at 0xc024ddf4 (gendisk_head) in dr1 is enabled on cpu 0 +for 4 bytes +kdb> go +[root@host /root]# diff -urN 2.3.29pre1/Documentation/kdb/kdb_env.man 2.3.29pre1-ikd/Documentation/kdb/kdb_env.man --- 2.3.29pre1/Documentation/kdb/kdb_env.man Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/kdb/kdb_env.man Mon Nov 22 16:56:22 1999 @@ -0,0 +1,46 @@ +.TH ENV 1 "09 March 1999" +.SH NAME +env, set \- Environment manipulation commands +.SH SYNOPSIS +env +.LP +set \fIenvironment-variable\fP=\fIvalue\fP +.SH DESCRIPTION +The kernel debugger contains an environment which contains a series +of name-value pairs. Some environment variables are known to the +various kernel debugger commands and have specific meaning to the +command; such are enumerated on the respective reference material. +.P +Arbitrary environment variables may be created and used with +many commands (those which require an \fIaddress-expression\fP). +.P +The +.B env +command is used to display the current environment. +.P +The +.B set +command is used to alter an existing environment variable or +establish a new environment variable. +.SH LIMITATIONS +There is a compile-time limit of 33 environment variables. +.P +There is a compile-time limit of 512 bytes (\fBKDB_ENVBUFSIZE\fP) +of heap space available for new environment variables and for +environment variables changed from their compile-time values. +.SH ENVIRONMENT +These commands explicitly manipulate the environment. +.SH SMP CONSIDERATIONS +None. +.SH FUTURE +Allow compile-time initialization of customized environment +settings. +.SH EXAMPLES +.TP 8 +env +Display current environment settings. + +.TP 8 +set IDCOUNT=100 +Set the number of lines to display for the \fBid\fP command +to the value \fI100\fP. diff -urN 2.3.29pre1/Documentation/kdb/kdb_ll.man 2.3.29pre1-ikd/Documentation/kdb/kdb_ll.man --- 2.3.29pre1/Documentation/kdb/kdb_ll.man Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/kdb/kdb_ll.man Mon Nov 22 16:56:22 1999 @@ -0,0 +1,134 @@ +.TH LL 1 "19 April 1999" +.SH NAME +ll \- Linked List examination +.SH SYNOPSIS +ll +.SH DESCRIPTION +The +.B ll +command is used to execute a single command repetitively for +each element of a linked list. +.P +The command specified by will be executed with a single +argument, the address of the current element. +.SH LIMITATIONS +Be careful if using this command recursively. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.nf +.na +.ft CW +# cd modules +# insmod kdbm_vm.o +# Entering kdb on processor 0 due to PAUSE +kdb> ps +Task Addr Pid Parent cpu lcpu Tss Command +0xc03de000 0000000001 0000000000 0000 0000 0xc03de2d4 init +0xc0090000 0000000002 0000000001 0000 0000 0xc00902d4 kflushd +0xc000e000 0000000003 0000000001 0000 0000 0xc000e2d4 kpiod +0xc000c000 0000000004 0000000001 0000 0000 0xc000c2d4 kswapd +0xc7de2000 0000000056 0000000001 0000 0000 0xc7de22d4 kerneld +0xc7d3a000 0000000179 0000000001 0000 0000 0xc7d3a2d4 syslogd +0xc7a7e000 0000000188 0000000001 0000 0000 0xc7a7e2d4 klogd +0xc7a04000 0000000199 0000000001 0000 0000 0xc7a042d4 atd +0xc7b84000 0000000210 0000000001 0000 0000 0xc7b842d4 crond +0xc79d6000 0000000221 0000000001 0000 0000 0xc79d62d4 portmap +0xc798e000 0000000232 0000000001 0000 0000 0xc798e2d4 snmpd +0xc7904000 0000000244 0000000001 0000 0000 0xc79042d4 inetd +0xc78fc000 0000000255 0000000001 0000 0000 0xc78fc2d4 lpd +0xc77ec000 0000000270 0000000001 0000 0000 0xc77ec2d4 sendmail +0xc77b8000 0000000282 0000000001 0000 0000 0xc77b82d4 gpm +0xc7716000 0000000300 0000000001 0000 0000 0xc77162d4 smbd +0xc7ee2000 0000000322 0000000001 0000 0000 0xc7ee22d4 mingetty +0xc7d6e000 0000000323 0000000001 0000 0000 0xc7d6e2d4 login +0xc778c000 0000000324 0000000001 0000 0000 0xc778c2d4 mingetty +0xc78b6000 0000000325 0000000001 0000 0000 0xc78b62d4 mingetty +0xc77e8000 0000000326 0000000001 0000 0000 0xc77e82d4 mingetty +0xc7708000 0000000327 0000000001 0000 0000 0xc77082d4 mingetty +0xc770e000 0000000328 0000000001 0000 0000 0xc770e2d4 mingetty +0xc76b0000 0000000330 0000000001 0000 0000 0xc76b02d4 update +0xc7592000 0000000331 0000000323 0000 0000 0xc75922d4 ksh +0xc7546000 0000000338 0000000331 0000 0000 0xc75462d4 su +0xc74dc000 0000000339 0000000338 0000 0000 0xc74dc2d4 ksh +kdb> md 0xc74dc2d4 +c74dc2d4: 00000000 c74de000 00000018 00000000 .....`MG........ +c74dc2e4: 00000000 00000000 00000000 074de000 .............`M. +c74dc2f4: c01123ff 00000000 00000000 00000000 #.@............ +c74dc304: 00000000 00000000 c74dded0 00000000 ........P^MG.... +[omitted] +c74dc474: 00000000 00000000 00000000 00000000 ................ +c74dc484: 00000000 c7c15d00 c77b0900 c026fbe0 .....]AG..{G`{&@ +c74dc494: 00000000 c76c2000 00000000 00000000 ..... lG........ +c74dc4a4: 00000000 00000000 00000000 c74dc4ac ............,DMG +kdb> md 0xc026fbe0 +c026fbe0: c0262b60 00000000 c7594940 c74de000 @HYG....@IYG.`MG +[omitted] +kdb> md 0xc0262b60 +c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G +kdb> ll c0262b60 12 md +c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G +c7bec360: c0266660 0804c000 0804d000 c7becb20 `f&@.@...P.. K>G +c7becb20: c0266660 0804d000 08050000 c7bec3a0 `f&@.P...... C>G +c7bec3a0: c0266660 40000000 40009000 c7bec420 `f&@...@...@ D>G +c7bec420: c0266660 40009000 4000b000 c7bec4a0 `f&@...@.0.@ D>G +c7bec4a0: c0266660 4000b000 40010000 c7bec8e0 `f&@.0.@...@`H>G +c7bec8e0: c0266660 40010000 400a1000 c7becbe0 `f&@...@...@`K>G +c7becbe0: c0266660 400a1000 400a8000 c7becc60 `f&@...@...@`L>G +c7becc60: c0266660 400a8000 400b4000 c7952300 `f&@...@.@.@.#.G +c7952300: c0266660 400b5000 400bc000 c79521c0 `f&@.P.@.@.@@!.G +c79521c0: c0266660 400bc000 400bd000 c7bec6e0 `f&@.@.@.P.@`F>G +c7bec6e0: c0266660 bffff000 c0000000 00000000 `f&@.p?...@.... +kdb> +kdb> ll c0262b60 12 vm +struct vm_area_struct at 0xc0262b60 for 56 bytes +vm_start = 0x8048000 vm_end = 0x804c000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +struct vm_area_struct at 0xc7bec360 for 56 bytes +vm_start = 0x804c000 vm_end = 0x804d000 +page_prot = 0x25 avl_height = -31808 vm_offset = 0x3000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +struct vm_area_struct at 0xc7becb20 for 56 bytes +vm_start = 0x804d000 vm_end = 0x8050000 +page_prot = 0x25 avl_height = -28664 vm_offset = 0x0 +flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec3a0 for 56 bytes +vm_start = 0x40000000 vm_end = 0x40009000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE +struct vm_area_struct at 0xc7bec420 for 56 bytes +vm_start = 0x40009000 vm_end = 0x4000b000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x8000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE +struct vm_area_struct at 0xc7bec4a0 for 56 bytes +vm_start = 0x4000b000 vm_end = 0x40010000 +page_prot = 0x25 avl_height = 26853 vm_offset = 0x0 +flags: READ MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec8e0 for 56 bytes +vm_start = 0x40010000 vm_end = 0x400a1000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7becbe0 for 56 bytes +vm_start = 0x400a1000 vm_end = 0x400a8000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x90000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7becc60 for 56 bytes +vm_start = 0x400a8000 vm_end = 0x400b4000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7952300 for 56 bytes +vm_start = 0x400b5000 vm_end = 0x400bc000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc79521c0 for 56 bytes +vm_start = 0x400bc000 vm_end = 0x400bd000 +page_prot = 0x25 avl_height = -16344 vm_offset = 0x6000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec6e0 for 56 bytes +vm_start = 0xbffff000 vm_end = 0xc0000000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC GROWSDOWN +kdb> diff -urN 2.3.29pre1/Documentation/kdb/kdb_md.man 2.3.29pre1-ikd/Documentation/kdb/kdb_md.man --- 2.3.29pre1/Documentation/kdb/kdb_md.man Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/kdb/kdb_md.man Mon Nov 22 16:56:22 1999 @@ -0,0 +1,86 @@ +.TH MD 1 "09 March 1999" +.SH NAME +md, mds, mm\- Memory manipulation commands +.SH SYNOPSIS +md [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +mds [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +mm \fIaddress-expression\fP \fInew-contents\fP +.SH DESCRIPTION +The +.B md +command is used to display the contents of memory. +The \fIaddress-expression\fP may be a numeric value (decimal or +hexidecimal), a symbol name, a register name preceeded by one or more +percent symbols '%', an environment variable name preceeded by +a currency symbol '$', or a simple expression consisting of a +symbol name, an addition or subtraction character and a numeric +value (decimal or hexidecimal). +.P +If the \fIline-count\fP or \fIradix\fP arguments are omitted, +they default to the values of the \fBMDCOUNT\fP and \fBRADIX\fP +environment variables respectively. If the \fBMDCOUNT\fP or +\fBRADIX\fP environment variables are unset, the appropriate +defaults will be used [see \fBENVIRONMENT\fP below]. +.P +The +.B mds +command displays the contents of memory one word per line and +attempts to correlate the contents of each word with a symbol +in the symbol table. If no symbol is found, the ascii representation +of the word is printed, otherwise the symbol name and offset from +symbol value are printed. +.P +The +.B mm +command allows modification of memory. The word at the address +represented by \fIaddress-expression\fP is changed to +\fInew-contents\fP. \fInew-contents\fP is allowed to be an +\fIaddress-expression\fP. +.SH LIMITATIONS +None. +.SH ENVIRONMENT +.TP 8 +MDCOUNT +This environment variable (default=8) defines the number of lines +that will be displayed by each invocation of the \fBmd\fP command. + +.TP 8 +RADIX +This environment variable (default=16) defines the radix used to +print the memory contents. + +.TP 8 +BYTESPERWORD +This environment variable (default=4) selects the width of output +data when printing memory contents. Select the value two to get +16-bit word output, select the value one to get byte output. + +.TP 8 +LINES +This environment variable governs the number of lines of output +that will be presented before the kernel debugger built-in pager +pauses the output. This variable only affects the functioning +of the \fBmd\fP and \fBmds\fP if the \fBMDCOUNT\fP variable +is set to a value greater than the \fBLINES\fP variable. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.TP 8 +md %edx +Display memory starting at the address contained in register \fB%edx\fP. + +.TP 8 +mds %esp +Display stack contents symbolically. This command is quite useful +in manual stack traceback. + +.TP 8 +mm 0xc0252110 0x25 +Change the memory location at 0xc0252110 to the value 0x25. + +.TP 8 +md chrdev_table 15 +Display 15 lines (at 16 bytes per line) starting at address +represented by the symbol \fIchrdev_table\fP. diff -urN 2.3.29pre1/Documentation/kdb/kdb_rd.man 2.3.29pre1-ikd/Documentation/kdb/kdb_rd.man --- 2.3.29pre1/Documentation/kdb/kdb_rd.man Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/kdb/kdb_rd.man Mon Nov 22 16:56:22 1999 @@ -0,0 +1,54 @@ +.TH RD 1 "09 March 1999" +.SH NAME +rd, rm\- Register manipulation commands +.SH SYNOPSIS +rd [c|d|u] +.LP +rm \fIregister-name\fP \fInew-contents\fP +.SH DESCRIPTION +The +.B rd +command is used to display the contents of processor registers. +Without any arguments, the rd command displays the contents of +the general register set at the point at which the kernel debugger +was entered. With the 'c' argument, the processor control registers +%cr0, %cr1, %cr2 and %cr4 are displayed, while with the 'd' argument +the processor debug registers are displayed. If the 'u' argument +is supplied, the registers for the current task as of the last +time the current task entered the kernel are displayed. +.P +The +.B rm +command allows modification of a register. The following +register names are valid: \fB%eax\fP, \fB%ebx\fP, \fB%ecx\fP, +\fB%edx\fP, \fB%esi\fP, \fB%edi\fP, \fB%esp\fP, \fB%eip\fP, +and \fB%ebp\fP. Note that if two '%' symbols are used +consecutively, the register set displayed by the 'u' argument +to the \fBrd\fP command is modified. +.SH LIMITATIONS +Currently the 'rm' command will not allow modification of the +control or debug registers. +.P +Currently neither the 'rd' command nor the 'rm' command will +display or modify the model specific registers on the Pentium +and Pentium Pro families. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.TP 8 +rd +Display general register set. + +.TP 8 +rm %eax 0 +Set the contents of \fB%eax\fP to zero. This will be the +value of %eax when kdb returns from the condition which +invoked it. + +.TP 8 +rm %%eax 0 +Set the value of the \fB%eax\fP register to zero. This will +be the value the user-mode application will see upon returning +from the kernel. diff -urN 2.3.29pre1/Documentation/kdb/kdb_ss.man 2.3.29pre1-ikd/Documentation/kdb/kdb_ss.man --- 2.3.29pre1/Documentation/kdb/kdb_ss.man Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/kdb/kdb_ss.man Mon Nov 22 16:56:22 1999 @@ -0,0 +1,71 @@ +.TH SS 1 "29 March 1999" +.SH NAME +ss, ssb \- Single Step +.SH SYNOPSIS +ss [] +.LP +ssb +.SH DESCRIPTION +The +.B ss +command is used to execute a single instruction and return +to the kernel debugger. +.P +Both the instruction that was single-stepped and the next +instruction to execute are printed. +.P +The \fBssb\fP command will execute instructions from the +current value of the instruction pointer. Each instruction +will be printed as it is executed; execution will stop at +any instruction which would cause the flow of control to +change (e.g. branch, call, interrupt instruction, return, etc.) +.SH LIMITATIONS +None. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +Other processors will be released from the kernel debugger +when the instruction is traced, and will be brought back to +a barrier in the kernel debugger when the traced instruction +completes. +.SH EXAMPLES +.nf +.na +.ft CW +kdb> bp gendisk_head datar 4 +Data Access Breakpoint #0 at 0xc024ddf4 (gendisk_head) in dr0 is enabled on cpu 0 +for 4 bytes +kdb> go +... +[root@host /root]# cat /proc/partitions +Entering kdb on processor 0 due to Debug Exception @ 0xc01845e3 +Read/Write breakpoint #0 at 0xc024ddf4 +[0]kdb> ssb +sd_finish+0x7b: movzbl 0xc02565d4,%edx +sd_finish+0x82: leal 0xf(%edx),%eax +sd_finish+0x85: sarl $0x4,%eax +sd_finish+0x88: movl 0xc0256654,%ecx +sd_finish+0x8e: leal (%eax,%eax,4),%edx +sd_finish+0x91: leal (%eax,%edx,2),%edx +sd_finish+0x94: movl 0xc0251108,%eax +sd_finish+0x99: movl %eax,0xffffffc(%ecx,%edx,4) +sd_finish+0x9d: movl %ecx,0xc0251108 +sd_finish+0xa3: xorl %ebx,%ebx +sd_finish+0xa5: cmpb $0x0,0xc02565d4 +[0]kdb> go +[root@host /root]# + +[0]kdb> ss +sys_read: pushl %ebp +SS trap at 0xc01274c1 +sys_read+0x1: movl %esp,%ebp +[0]kdb> ss +sys_read+0x1: movl %esp,%ebp +SS trap at 0xc01274c3 +sys_read+0x3: subl $0xc,%esp +[0]kdb> ss +sys_read+0x3: subl $0xc,%esp +SS trap at 0xc01274c6 +sys_read+0x6: pushl %edi +[0]kdb> + diff -urN 2.3.29pre1/Documentation/ktrace.txt 2.3.29pre1-ikd/Documentation/ktrace.txt --- 2.3.29pre1/Documentation/ktrace.txt Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/ktrace.txt Mon Nov 22 16:56:22 1999 @@ -0,0 +1,88 @@ +ktrace - Trace logic flow through the kernel with time stamps. + + +******* Please read debugging.txt first. ******* + + +LIMITATION: nanosecond accuracy timings on x86 CPUs works only if the + CPU has the rtdsc instruction. If you have another x86 + CPU, undef the HAVE_RTDSC define in include/asm/profiler.h. + See the 'tsc' flag in the /proc/cpuinfo flags field if + unsure. + + Alpha CPU support is not yet tested. + Intel SMP is tested + + +INSTALLATION + +If you are reading this, you have probably already applied the patch to +your kernel, now set the options and rebuild. Under Kernel Hacking, +say Y to Kernel debugging support then Y to Enable kernel tracing. +Make dep clean, recompile, install the new kernel and modules, reboot. + +Expect the new kernel to be somewhat slower than the unpatched kernel. +Check out /proc/trace, if it exists then you can go on to to the +user-space part: + +In /usr/src/linux, make debug. To get the current trace on a 166 MHz +CPU: + +scripts/ktrace --speed 166 --map /usr/src/linux/System.map > output.txt + +you should get something like this in output.txt: + +MHZ: 166. +read 4420 lines from System.map. +calibration done, estimated measurement latency: 0.34 microseconds. + +c01299ca put_unused_buffer_head + (0.90) +c011232b wake_up +<13/f0> (1.48) +c0129a26 get_more_buffer_heads + (0.61) +c012880f get_hash_table +<13/c0> (1.34) +c01296ca __brelse + (97.15) +c0129345 set_writetime + (0.11) +c0129398 refile_buffer +<10/334> (0.36) +[...] + +By default, all of the kernel except for init_task and the profiler +is traced. This can lead to a very busy trace file, full of +low level routines. To turn off tracing for a directory and all its +subdirectories, add the line + + override CFLAGS := $(CFLAGS:%-pg=%-g -c) + +to the relevant Makefile, before Rules.make. Delete the *.o files you +want to recompile and make zImage/modules. + +ktrace can get an exclusive lock on /proc/trace before reading it. +This allows ktrace to be suspended until an event occurs. For example, + +* User written program gets exclusive lock on /proc/trace, waits for + event to occur. + +* After starting above program, user runs ktrace with -l or --lock + options which suspends on the lock. + +* User written program detects the desired event, releases the lock. + +* ktrace runs, the resulting trace is as close to the event as + scheduling will allow. + +Sometimes you cannot read /proc/trace directly, typically because the +system is dead and ktrace cannot be run. If it is still responding to +the Magic-SysRQ key (you did select that option didn't you?) then +SysRQ-g dumps syslog and /proc/trace to all consoles, the latter is in +hex. Capture the output via a serial console on another machine +(another useful debugging option). + +After your dead machine has been restarted, take the captured hex dump +of /proc/trace and feed it to ktrace with the option "-d filename" or +"--dump filename". The lock option is ignored when reading a dumped +ktrace. + +Have fun, mail mingo@pc5829.hil.siemens.at if problems. + +Updated by: Mike Galbraith mikeg@weiden.de + +map option, dump option and kernel integration by Keith Owens . diff -urN 2.3.29pre1/Documentation/sysrq.txt 2.3.29pre1-ikd/Documentation/sysrq.txt --- 2.3.29pre1/Documentation/sysrq.txt Sun Nov 7 17:33:35 1999 +++ 2.3.29pre1-ikd/Documentation/sysrq.txt Mon Nov 22 16:57:29 1999 @@ -1,6 +1,7 @@ MAGIC SYSRQ KEY DOCUMENTATION v1.2 ------------------------------------ [Sat May 16 01:09:21 EDT 1998] + [Fri May 22 21:33:06 EST 1998 - add dumploGs, Oops] * What is the magic SysRQ key? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -33,7 +34,7 @@ 'b' - Will immediately reboot the system without syncing or unmounting your disks. -'o' - Will shut your system off (if configured and supported). +'f' - Will shut your system off (if configured and supported). 's' - Will attempt to sync all mounted filesystems. @@ -58,6 +59,10 @@ 'l' - Send a SIGKILL to all processes, INCLUDING init. (Your system will be non-functional after this.) +'g' - Dumps log files to all registered consoles. + +'o' - Force an Oops. + * Okay, so what can I use them for? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Well, un'R'aw is very handy when your X server or a svgalib program crashes. @@ -87,6 +92,12 @@ t'E'rm and k'I'll are useful if you have some sort of runaway process you are unable to kill any other way, especially if it's spawning other processes. + +dumplo'G's is useful when the system is hung and you want to see the +log files. It is a good idea to have a serial console assigned to +capture the result. + +'O'ops forces an oops so you can get a kernel backtrace. * Sometimes SysRQ seems to get 'stuck' after using it, what can I do? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff -urN 2.3.29pre1/Documentation/sysrq.txt.orig 2.3.29pre1-ikd/Documentation/sysrq.txt.orig --- 2.3.29pre1/Documentation/sysrq.txt.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/sysrq.txt.orig Sun Nov 7 17:33:35 1999 @@ -0,0 +1,113 @@ + MAGIC SYSRQ KEY DOCUMENTATION v1.2 + ------------------------------------ + [Sat May 16 01:09:21 EDT 1998] + +* What is the magic SysRQ key? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It is a 'magical' key combo you can hit which kernel will respond to +regardless of whatever else it is doing, unless it is completely locked up. + +* How do I enable the magic SysRQ key? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when +configuring the kernel. This option is only available in 2.1.x or later +kernels. + +* How do I use the magic SysRQ key? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +On x86 - You press the key combo 'ALT-SysRQ-'. Note - Some + (older?) may not have a key labeled 'SysRQ'. The 'SysRQ' key is + also known as the 'Print Screen' key. + +On SPARC - You press 'ALT-STOP-', I believe. + +On other - If you know of the key combos for other architectures, please + let me know so I can add them to this section. + +* What are the 'command' keys? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +'r' - Turns off keyboard raw mode and sets it to XLATE. + +'k' - Kills all programs on the current virtual console. + +'b' - Will immediately reboot the system without syncing or unmounting + your disks. + +'o' - Will shut your system off (if configured and supported). + +'s' - Will attempt to sync all mounted filesystems. + +'u' - Will attempt to remount all mounted filesystems read-only. + +'p' - Will dump the current registers and flags to your console. + +'t' - Will dump a list of current tasks and their information to your + console. + +'m' - Will dump current memory info to your console. + +'0'-'9' - Sets the console log level, controlling which kernel messages + will be printed to your console. ('0', for example would make + it so that only emergency messages like PANICs or OOPSes would + make it to your console.) + +'e' - Send a SIGTERM to all processes, except for init. + +'i' - Send a SIGKILL to all processes, except for init. + +'l' - Send a SIGKILL to all processes, INCLUDING init. (Your system + will be non-functional after this.) + +* Okay, so what can I use them for? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Well, un'R'aw is very handy when your X server or a svgalib program crashes. + +sa'K' (system attention key) is useful when you want to exit a program +that will not let you switch consoles. (For example, X or a svgalib program.) + +re'B'oot is good when you're unable to shut down. But you should also 'S'ync +and 'U'mount first. + +'S'ync is great when your system is locked up, it allows you to sync your +disks and will certainly lessen the chance of data loss and fscking. Note +that the sync hasn't taken place until you see the "OK" and "Done" appear +on the screen. (If the kernel is really in strife, you may not ever get the +OK or Done message...) + +'U'mount is basically useful in the same ways as 'S'ync. I generally 'S'ync, +'U'mount, then re'B'oot when my system locks. It's saved me many a fsck. +Again, the unmount (remount read-only) hasn't taken place until you see the +"OK" and "Done" message appear on the screen. + +The loglevel'0'-'9' is useful when your console is being flooded with +kernel messages you do not want to see. Setting '0' will prevent all but +the most urgent kernel messages from reaching your console. (They will +still be logged if syslogd/klogd are alive, though.) + +t'E'rm and k'I'll are useful if you have some sort of runaway process you +are unable to kill any other way, especially if it's spawning other +processes. + +* Sometimes SysRQ seems to get 'stuck' after using it, what can I do? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +That happens to me, also. I've found that tapping shift, alt, and control +on both sides of the keyboard, and hitting an invalid sysrq sequence again +will fix the problem. (ie, something like alt-sysrq-z). Switching to another +virtual console (ALT+Fn) and then back again should also help. + +* I hit SysRQ, but nothing seems to happen, what's wrong? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There are some keyboards which do not support 'SysRQ', you can try running +'showkey -s' and pressing SysRQ or alt-SysRQ to see if it generates any +0x54 codes. If it doesn't, you may define the magic sysrq sequence to a +different key. Find the keycode with showkey, and change the define of +'#define SYSRQ_KEY 0x54' in [/usr/src/linux/]include/asm/keyboard.h to +the keycode of the key you wish to use, then recompile. Oh, and by the way, +you exit 'showkey' by not typing anything for ten seconds. + +* I have more questions, who can I ask? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +You may feel free to send email to myrdraal@deathsdoor.com, and I will +respond as soon as possible. If that email address does not work, use +myrdraal@jackalz.dyn.ml.org. + -Myrdraal diff -urN 2.3.29pre1/Documentation/sysrq.txt.rej 2.3.29pre1-ikd/Documentation/sysrq.txt.rej --- 2.3.29pre1/Documentation/sysrq.txt.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/sysrq.txt.rej Mon Nov 22 16:56:22 1999 @@ -0,0 +1,17 @@ +*************** +*** 33,39 **** + 'b' - Will immediately reboot the system without syncing or unmounting + your disks. + +- 'o' - Will shut your system off via APM (if configured and supported). + + 's' - Will attempt to sync all mounted filesystems. + +--- 34,40 ---- + 'b' - Will immediately reboot the system without syncing or unmounting + your disks. + ++ 'f' - Will shut your system off via APM (if configured and supported). + + 's' - Will attempt to sync all mounted filesystems. + diff -urN 2.3.29pre1/Documentation/sysrq.txt.~1~ 2.3.29pre1-ikd/Documentation/sysrq.txt.~1~ --- 2.3.29pre1/Documentation/sysrq.txt.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Documentation/sysrq.txt.~1~ Mon Nov 22 16:56:22 1999 @@ -0,0 +1,124 @@ + MAGIC SYSRQ KEY DOCUMENTATION v1.2 + ------------------------------------ + [Sat May 16 01:09:21 EDT 1998] + [Fri May 22 21:33:06 EST 1998 - add dumploGs, Oops] + +* What is the magic SysRQ key? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It is a 'magical' key combo you can hit which kernel will respond to +regardless of whatever else it is doing, unless it is completely locked up. + +* How do I enable the magic SysRQ key? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +You need to say "yes" to 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' when +configuring the kernel. This option is only available in 2.1.x or later +kernels. + +* How do I use the magic SysRQ key? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +On x86 - You press the key combo 'ALT-SysRQ-'. Note - Some + (older?) may not have a key labeled 'SysRQ'. The 'SysRQ' key is + also known as the 'Print Screen' key. + +On SPARC - You press 'ALT-STOP-', I believe. + +On other - If you know of the key combos for other architectures, please + let me know so I can add them to this section. + +* What are the 'command' keys? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +'r' - Turns off keyboard raw mode and sets it to XLATE. + +'k' - Kills all programs on the current virtual console. + +'b' - Will immediately reboot the system without syncing or unmounting + your disks. + +'o' - Will shut your system off (if configured and supported). + +'s' - Will attempt to sync all mounted filesystems. + +'u' - Will attempt to remount all mounted filesystems read-only. + +'p' - Will dump the current registers and flags to your console. + +'t' - Will dump a list of current tasks and their information to your + console. + +'m' - Will dump current memory info to your console. + +'0'-'9' - Sets the console log level, controlling which kernel messages + will be printed to your console. ('0', for example would make + it so that only emergency messages like PANICs or OOPSes would + make it to your console.) + +'e' - Send a SIGTERM to all processes, except for init. + +'i' - Send a SIGKILL to all processes, except for init. + +'l' - Send a SIGKILL to all processes, INCLUDING init. (Your system + will be non-functional after this.) + +'g' - Dumps log files to all registered consoles. + +'o' - Force an Oops. + +* Okay, so what can I use them for? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Well, un'R'aw is very handy when your X server or a svgalib program crashes. + +sa'K' (system attention key) is useful when you want to exit a program +that will not let you switch consoles. (For example, X or a svgalib program.) + +re'B'oot is good when you're unable to shut down. But you should also 'S'ync +and 'U'mount first. + +'S'ync is great when your system is locked up, it allows you to sync your +disks and will certainly lessen the chance of data loss and fscking. Note +that the sync hasn't taken place until you see the "OK" and "Done" appear +on the screen. (If the kernel is really in strife, you may not ever get the +OK or Done message...) + +'U'mount is basically useful in the same ways as 'S'ync. I generally 'S'ync, +'U'mount, then re'B'oot when my system locks. It's saved me many a fsck. +Again, the unmount (remount read-only) hasn't taken place until you see the +"OK" and "Done" message appear on the screen. + +The loglevel'0'-'9' is useful when your console is being flooded with +kernel messages you do not want to see. Setting '0' will prevent all but +the most urgent kernel messages from reaching your console. (They will +still be logged if syslogd/klogd are alive, though.) + +t'E'rm and k'I'll are useful if you have some sort of runaway process you +are unable to kill any other way, especially if it's spawning other +processes. + +dumplo'G's is useful when the system is hung and you want to see the +log files. It is a good idea to have a serial console assigned to +capture the result. + +'O'ops forces an oops so you can get a kernel backtrace. + +* Sometimes SysRQ seems to get 'stuck' after using it, what can I do? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +That happens to me, also. I've found that tapping shift, alt, and control +on both sides of the keyboard, and hitting an invalid sysrq sequence again +will fix the problem. (ie, something like alt-sysrq-z). Switching to another +virtual console (ALT+Fn) and then back again should also help. + +* I hit SysRQ, but nothing seems to happen, what's wrong? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +There are some keyboards which do not support 'SysRQ', you can try running +'showkey -s' and pressing SysRQ or alt-SysRQ to see if it generates any +0x54 codes. If it doesn't, you may define the magic sysrq sequence to a +different key. Find the keycode with showkey, and change the define of +'#define SYSRQ_KEY 0x54' in [/usr/src/linux/]include/asm/keyboard.h to +the keycode of the key you wish to use, then recompile. Oh, and by the way, +you exit 'showkey' by not typing anything for ten seconds. + +* I have more questions, who can I ask? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +You may feel free to send email to myrdraal@deathsdoor.com, and I will +respond as soon as possible. If that email address does not work, use +myrdraal@jackalz.dyn.ml.org. + -Myrdraal diff -urN 2.3.29pre1/Makefile 2.3.29pre1-ikd/Makefile --- 2.3.29pre1/Makefile Sun Nov 21 03:20:43 1999 +++ 2.3.29pre1-ikd/Makefile Mon Nov 22 17:16:44 1999 @@ -28,6 +28,7 @@ NM =$(CROSS_COMPILE)nm STRIP =$(CROSS_COMPILE)strip OBJDUMP =$(CROSS_COMPILE)objdump +AWK =awk MAKE =make GENKSYMS=/sbin/genksyms @@ -86,7 +87,16 @@ # standard CFLAGS # -CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +CFLAGS = -Wall -Wstrict-prototypes -O2 +ifeq ($(CONFIG_KERNEL_DEBUGGING),y) + CFLAGS += -fno-omit-frame-pointer + # Profiling is a big overhead so only turn it on if the user really wants it. + ifeq ($(CONFIG_DEBUG_MCOUNT),y) + CFLAGS += -pg + endif +else + CFLAGS += -fomit-frame-pointer +endif # use '-fno-strict-aliasing', but only if the compiler can take it CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) @@ -107,6 +117,9 @@ # CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o +ifeq ($(CONFIG_KERNEL_DEBUGGING),y) + CORE_FILES +=kernel/debug/debug.o +endif FILESYSTEMS =fs/filesystems.a NETWORKS =net/network.a DRIVERS =drivers/block/block.a \ @@ -238,6 +251,38 @@ boot: vmlinux @$(MAKE) -C arch/$(ARCH)/boot +ifeq ($(CONFIG_KDB),y) +vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs + echo "c0000000 t firstaddr\n" > System.map + rm -f map map.out + $(AWK) -f scripts/genkdbsym.awk System.map > dummy_sym.c + $(CC) -c -o dummy_sym.o dummy_sym.c + $(LD) $(LINKFLAGS) $(HEAD) -Map map init/main.o init/version.o \ + --start-group \ + $(CORE_FILES) \ + $(FILESYSTEMS) \ + $(NETWORKS) \ + $(DRIVERS) \ + $(LIBS) \ + dummy_sym.o \ + --end-group \ + -o vmlinux + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + cp System.map System.map.sv + $(AWK) -f scripts/genkdbsym.awk System.map > ksym.c + $(CC) -c -o ksym.o ksym.c > ksym.o + $(LD) $(LINKFLAGS) $(HEAD) -Map map.out init/main.o init/version.o \ + --start-group \ + $(CORE_FILES) \ + $(FILESYSTEMS) \ + $(NETWORKS) \ + $(DRIVERS) \ + $(LIBS) \ + ksym.o \ + --end-group \ + -o vmlinux + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map +else vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ --start-group \ @@ -249,6 +294,7 @@ --end-group \ -o vmlinux $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map +endif symlinks: rm -f include/asm @@ -275,6 +321,10 @@ scripts/split-include include/linux/autoconf.h include/config @ touch include/config/MARKER +debug: include/linux/version.h + $(MAKE) -C scripts ktrace + $(MAKE) -C scripts/memleak all + linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS)) $(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/config/MARKER @@ -401,6 +451,9 @@ rm -f net/khttpd/times.h rm -f submenu* rm -rf modules + $(MAKE) -C scripts clean + $(MAKE) -C scripts/memleak clean + rm -f ksym.[ch] dummy_sym.c System.map.sv map map.out mrproper: clean archmrproper rm -f include/linux/autoconf.h include/linux/version.h @@ -437,7 +490,7 @@ dep-files: scripts/mkdep archdep include/linux/version.h scripts/mkdep init/*.c > .depend scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend - $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" + $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS) scripts) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS) scripts" MODVERFILE := diff -urN 2.3.29pre1/Makefile.orig 2.3.29pre1-ikd/Makefile.orig --- 2.3.29pre1/Makefile.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Makefile.orig Sun Nov 21 03:20:43 1999 @@ -0,0 +1,487 @@ +VERSION = 2 +PATCHLEVEL = 3 +SUBLEVEL = 29 +EXTRAVERSION = + +ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) + +.EXPORT_ALL_VARIABLES: + +CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ + else if [ -x /bin/bash ]; then echo /bin/bash; \ + else echo sh; fi ; fi) +TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi) + +HPATH = $(TOPDIR)/include +FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net + +HOSTCC =gcc +HOSTCFLAGS =-Wall -Wstrict-prototypes -O2 -fomit-frame-pointer + +CROSS_COMPILE = + +AS =$(CROSS_COMPILE)as +LD =$(CROSS_COMPILE)ld +CC =$(CROSS_COMPILE)gcc -D__KERNEL__ -I$(HPATH) +CPP =$(CC) -E +AR =$(CROSS_COMPILE)ar +NM =$(CROSS_COMPILE)nm +STRIP =$(CROSS_COMPILE)strip +OBJDUMP =$(CROSS_COMPILE)objdump +MAKE =make +GENKSYMS=/sbin/genksyms + +all: do-it-all + +# +# Make "config" the default target if there is no configuration file or +# "depend" the target if there is no top-level dependency information. +# +ifeq (.config,$(wildcard .config)) +include .config +ifeq (.depend,$(wildcard .depend)) +include .depend +do-it-all: Version vmlinux +else +CONFIGURATION = depend +do-it-all: depend +endif +else +CONFIGURATION = config +do-it-all: config +endif + +# +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case +# the default of FLOPPY is used by 'build'. +# + +ROOT_DEV = CURRENT + +KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +# +# INSTALL_PATH specifies where to place the updated kernel and system map +# images. Uncomment if you want to place them anywhere other than root. + +#INSTALL_PATH=/boot + +# +# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory +# relocations required by build roots. This is not defined in the +# makefile but the arguement can be passed to make if needed. +# + +# +# If you want to preset the SVGA mode, uncomment the next line and +# set SVGA_MODE to whatever number you want. +# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. +# The number is the same as you would ordinarily press at bootup. +# + +SVGA_MODE= -DSVGA_MODE=NORMAL_VGA + +# +# standard CFLAGS +# + +CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer + +# use '-fno-strict-aliasing', but only if the compiler can take it +CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) + +ifdef CONFIG_SMP +CFLAGS += -D__SMP__ +AFLAGS += -D__SMP__ +endif + +# +# if you want the RAM disk device, define this to be the +# size in blocks. +# + +#RAMDISK = -DRAMDISK=512 + +# Include the make variables (CC, etc...) +# + +CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o +FILESYSTEMS =fs/filesystems.a +NETWORKS =net/network.a +DRIVERS =drivers/block/block.a \ + drivers/char/char.o \ + drivers/misc/misc.o \ + drivers/net/net.o \ + drivers/parport/parport.a +LIBS =$(TOPDIR)/lib/lib.a +SUBDIRS =kernel drivers mm fs net ipc lib + +ifdef CONFIG_NUBUS +DRIVERS := $(DRIVERS) drivers/nubus/nubus.a +endif + +ifeq ($(CONFIG_ISDN),y) +DRIVERS := $(DRIVERS) drivers/isdn/isdn.a +endif + +ifdef CONFIG_NET_FC +DRIVERS := $(DRIVERS) drivers/net/fc/fc.a +endif + +ifdef CONFIG_TR +DRIVERS := $(DRIVERS) drivers/net/tokenring/tr.a +endif + +ifdef CONFIG_WAN +DRIVERS := $(DRIVERS) drivers/net/wan/wan.a +endif + +ifdef CONFIG_ATM +DRIVERS := $(DRIVERS) drivers/atm/atm.a +endif + +ifeq ($(CONFIG_SCSI),y) +DRIVERS := $(DRIVERS) drivers/scsi/scsi.a +endif + +ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) +DRIVERS := $(DRIVERS) drivers/cdrom/cdrom.a +endif + +ifeq ($(CONFIG_SOUND),y) +DRIVERS := $(DRIVERS) drivers/sound/sounddrivers.o +endif + +ifdef CONFIG_PCI +DRIVERS := $(DRIVERS) drivers/pci/pci.a +endif + +ifeq ($(CONFIG_PCMCIA),y) +DRIVERS := $(DRIVERS) drivers/pcmcia/pcmcia.o +endif + +ifeq ($(CONFIG_PCMCIA_NETCARD),y) +DRIVERS := $(DRIVERS) drivers/net/pcmcia/pcmcia_net.o +endif + +ifeq ($(CONFIG_PCMCIA_CHRDEV),y) +DRIVERS := $(DRIVERS) drivers/char/pcmcia/pcmcia_char.o +endif + +ifdef CONFIG_DIO +DRIVERS := $(DRIVERS) drivers/dio/dio.a +endif + +ifdef CONFIG_SBUS +DRIVERS := $(DRIVERS) drivers/sbus/sbus.a +endif + +ifdef CONFIG_ZORRO +DRIVERS := $(DRIVERS) drivers/zorro/zorro.a +endif + +ifeq ($(CONFIG_FC4),y) +DRIVERS := $(DRIVERS) drivers/fc4/fc4.a +endif + +ifdef CONFIG_PPC +DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a +endif + +ifeq ($(CONFIG_PNP),y) +DRIVERS := $(DRIVERS) drivers/pnp/pnp.a +endif + +ifdef CONFIG_SGI +DRIVERS := $(DRIVERS) drivers/sgi/sgi.a +endif + +ifdef CONFIG_VT +DRIVERS := $(DRIVERS) drivers/video/video.a +endif + +ifeq ($(CONFIG_PARIDE),y) +DRIVERS := $(DRIVERS) drivers/block/paride/paride.a +endif + +ifdef CONFIG_HAMRADIO +DRIVERS := $(DRIVERS) drivers/net/hamradio/hamradio.o +endif + +ifeq ($(CONFIG_TC),y) +DRIVERS := $(DRIVERS) drivers/tc/tc.a +endif + +ifeq ($(CONFIG_USB),y) +DRIVERS := $(DRIVERS) drivers/usb/usb.a +endif + +ifeq ($(CONFIG_I2O),y) +DRIVERS := $(DRIVERS) drivers/i2o/i2o.a +endif + +ifeq ($(CONFIG_IRDA),y) +DRIVERS := $(DRIVERS) drivers/net/irda/irda_drivers.a +endif + +include arch/$(ARCH)/Makefile + +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< + +Version: dummy + @rm -f include/linux/compile.h + +boot: vmlinux + @$(MAKE) -C arch/$(ARCH)/boot + +vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs + $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ + --start-group \ + $(CORE_FILES) \ + $(FILESYSTEMS) \ + $(NETWORKS) \ + $(DRIVERS) \ + $(LIBS) \ + --end-group \ + -o vmlinux + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + +symlinks: + rm -f include/asm + ( cd include ; ln -sf asm-$(ARCH) asm) + @if [ ! -d include/linux/modules ]; then \ + mkdir include/linux/modules; \ + fi + +oldconfig: symlinks + $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in + +xconfig: symlinks + $(MAKE) -C scripts kconfig.tk + wish -f scripts/kconfig.tk + +menuconfig: include/linux/version.h symlinks + $(MAKE) -C scripts/lxdialog all + $(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in + +config: symlinks + $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in + +include/config/MARKER: scripts/split-include include/linux/autoconf.h + scripts/split-include include/linux/autoconf.h include/config + @ touch include/config/MARKER + +linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS)) + +$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/config/MARKER + $(MAKE) -C $(patsubst _dir_%, %, $@) + +$(TOPDIR)/include/linux/version.h: include/linux/version.h +$(TOPDIR)/include/linux/compile.h: include/linux/compile.h + +newversion: + @if [ ! -f .version ]; then \ + echo 1 > .version; \ + else \ + expr 0`cat .version` + 1 > .version; \ + fi + +include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion + @echo -n \#define UTS_VERSION \"\#`cat .version` > .ver + @if [ -n "$(CONFIG_SMP)" ] ; then echo -n " SMP" >> .ver; fi + @if [ -f .name ]; then echo -n \-`cat .name` >> .ver; fi + @echo ' '`date`'"' >> .ver + @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> .ver + @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> .ver + @echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> .ver + @if [ -x /bin/dnsdomainname ]; then \ + echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname`\"; \ + elif [ -x /bin/domainname ]; then \ + echo \#define LINUX_COMPILE_DOMAIN \"`domainname`\"; \ + else \ + echo \#define LINUX_COMPILE_DOMAIN ; \ + fi >> .ver + @echo \#define LINUX_COMPILER \"`$(CC) $(CFLAGS) -v 2>&1 | tail -1`\" >> .ver + @mv -f .ver $@ + +include/linux/version.h: ./Makefile + @echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver + @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver + @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver + @mv -f .ver $@ + +init/version.o: init/version.c include/linux/compile.h include/config/MARKER + $(CC) $(CFLAGS) -DUTS_MACHINE='"$(ARCH)"' -c -o init/version.o init/version.c + +init/main.o: init/main.c include/config/MARKER + $(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $< + +fs lib mm ipc kernel drivers net: dummy + $(MAKE) $(subst $@, _dir_$@, $@) + +MODFLAGS = -DMODULE +ifdef CONFIG_MODULES +ifdef CONFIG_MODVERSIONS +MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h +endif + +modules: $(patsubst %, _mod_%, $(SUBDIRS)) + +modules/MARKER: + mkdir -p modules + touch modules/MARKER + +$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h include/config/MARKER modules/MARKER + $(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules + +modules_install: + @( \ + MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE); \ + cd modules; \ + MODULES=""; \ + inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \ + mkdir -p $$MODLIB/$$2; cp $$These $$MODLIB/$$2; \ + echo Installing modules under $$MODLIB/$$2; \ + }; \ + mkdir -p $$MODLIB; \ + \ + if [ -f BLOCK_MODULES ]; then inst_mod BLOCK_MODULES block; fi; \ + if [ -f NET_MODULES ]; then inst_mod NET_MODULES net; fi; \ + if [ -f IPV4_MODULES ]; then inst_mod IPV4_MODULES ipv4; fi; \ + if [ -f IPV6_MODULES ]; then inst_mod IPV6_MODULES ipv6; fi; \ + if [ -f ATM_MODULES ]; then inst_mod ATM_MODULES atm; fi; \ + if [ -f SCSI_MODULES ]; then inst_mod SCSI_MODULES scsi; fi; \ + if [ -f FS_MODULES ]; then inst_mod FS_MODULES fs; fi; \ + if [ -f NLS_MODULES ]; then inst_mod NLS_MODULES fs; fi; \ + if [ -f CDROM_MODULES ]; then inst_mod CDROM_MODULES cdrom; fi; \ + if [ -f HAM_MODULES ]; then inst_mod HAM_MODULES net; fi; \ + if [ -f SOUND_MODULES ]; then inst_mod SOUND_MODULES sound; fi; \ + if [ -f VIDEO_MODULES ]; then inst_mod VIDEO_MODULES video; fi; \ + if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \ + if [ -f IRDA_MODULES ]; then inst_mod IRDA_MODULES net; fi; \ + if [ -f USB_MODULES ]; then inst_mod USB_MODULES usb; fi; \ + if [ -f PCMCIA_MODULES ]; then inst_mod PCMCIA_MODULES pcmcia; fi; \ + if [ -f PCMCIA_NET_MODULES ]; then inst_mod PCMCIA_NET_MODULES pcmcia; fi; \ + if [ -f PCMCIA_CHAR_MODULES ]; then inst_mod PCMCIA_CHAR_MODULES pcmcia; fi; \ + \ + ls *.o > $$MODLIB/.allmods; \ + echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ + if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \ + rm -f $$MODLIB/.misc $$MODLIB/.allmods; \ + ) + +# modules disabled.... + +else +modules modules_install: dummy + @echo + @echo "The present kernel configuration has modules disabled." + @echo "Type 'make config' and enable loadable module support." + @echo "Then build a kernel with module support enabled." + @echo + @exit 1 +endif + +clean: archclean + rm -f kernel/ksyms.lst include/linux/compile.h + find . -name '*.[oas]' -type f -print | grep -v lxdialog/ | xargs rm -f + rm -f core `find . -type f -name 'core' -print` + rm -f core `find . -type f -name '.*.flags' -print` + rm -f vmlinux System.map + rm -f .tmp* + rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c + rm -f drivers/char/conmakehash + rm -f drivers/pci/devlist.h drivers/pci/gen-devlist + rm -f drivers/sound/bin2hex drivers/sound/hex2hex + rm -f net/khttpd/make_times_h + rm -f net/khttpd/times.h + rm -f submenu* + rm -rf modules + +mrproper: clean archmrproper + rm -f include/linux/autoconf.h include/linux/version.h + rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h + rm -f drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h + rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h + rm -f drivers/net/hamradio/soundmodem/gentbl + rm -f drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h + rm -f drivers/sound/*_boot.h drivers/sound/.*.boot + rm -f .version .config* config.in config.old + rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp + rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog + rm -f .menuconfig.log + rm -f include/asm + rm -rf include/config + rm -f .depend `find . -type f -name .depend -print` + rm -f core `find . -type f -size 0 -print` + rm -f .hdepend scripts/mkdep scripts/split-include + rm -f $(TOPDIR)/include/linux/modversions.h + rm -rf $(TOPDIR)/include/linux/modules + +distclean: mrproper + rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ + -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ + -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS + +backup: mrproper + cd .. && tar cf - linux/ | gzip -9 > backup.gz + sync + +sums: + find . -type f -print | sort | xargs sum > .SUMS + +dep-files: scripts/mkdep archdep include/linux/version.h + scripts/mkdep init/*.c > .depend + scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend + $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" + +MODVERFILE := + +ifdef CONFIG_MODVERSIONS +MODVERFILE := $(TOPDIR)/include/linux/modversions.h +endif + +depend dep: dep-files $(MODVERFILE) + +# make checkconfig: Prune 'scripts' directory to avoid "false positives". +checkconfig: + perl -w scripts/checkconfig.pl `find * -path 'scripts' -prune -o -name '*.[hcS]' -print | sort` + +checkhelp: + perl -w scripts/checkhelp.pl `find * -name [cC]onfig.in -print` + +ifdef CONFIGURATION +..$(CONFIGURATION): + @echo + @echo "You have a bad or nonexistent" .$(CONFIGURATION) ": running 'make" $(CONFIGURATION)"'" + @echo + $(MAKE) $(CONFIGURATION) + @echo + @echo "Successful. Try re-making (ignore the error that follows)" + @echo + exit 1 + +#dummy: ..$(CONFIGURATION) +dummy: + +else + +dummy: + +endif + +include Rules.make + +# +# This generates dependencies for the .h files. +# + +scripts/mkdep: scripts/mkdep.c + $(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c + +scripts/split-include: scripts/split-include.c + $(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c diff -urN 2.3.29pre1/Makefile.rej 2.3.29pre1-ikd/Makefile.rej --- 2.3.29pre1/Makefile.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Makefile.rej Mon Nov 22 16:56:22 1999 @@ -0,0 +1,18 @@ +*************** +*** 396,401 **** + rm -f core `find modules/ -type f -print`; \ + fi + rm -f submenu* + + mrproper: clean archmrproper + rm -f include/linux/autoconf.h include/linux/version.h +--- 446,454 ---- + rm -f core `find modules/ -type f -print`; \ + fi + rm -f submenu* ++ $(MAKE) -C scripts clean ++ $(MAKE) -C scripts/memleak clean ++ rm -f ksym.[ch] dummy_sym.c System.map.sv map map.out + + mrproper: clean archmrproper + rm -f include/linux/autoconf.h include/linux/version.h diff -urN 2.3.29pre1/Makefile.~1~ 2.3.29pre1-ikd/Makefile.~1~ --- 2.3.29pre1/Makefile.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/Makefile.~1~ Mon Nov 22 16:56:22 1999 @@ -0,0 +1,537 @@ +VERSION = 2 +PATCHLEVEL = 3 +SUBLEVEL = 29 +EXTRAVERSION = + +ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) + +.EXPORT_ALL_VARIABLES: + +CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ + else if [ -x /bin/bash ]; then echo /bin/bash; \ + else echo sh; fi ; fi) +TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi) + +HPATH = $(TOPDIR)/include +FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net + +HOSTCC =gcc +HOSTCFLAGS =-Wall -Wstrict-prototypes -O2 -fomit-frame-pointer + +CROSS_COMPILE = + +AS =$(CROSS_COMPILE)as +LD =$(CROSS_COMPILE)ld +CC =$(CROSS_COMPILE)gcc -D__KERNEL__ -I$(HPATH) +CPP =$(CC) -E +AR =$(CROSS_COMPILE)ar +NM =$(CROSS_COMPILE)nm +STRIP =$(CROSS_COMPILE)strip +OBJDUMP =$(CROSS_COMPILE)objdump +AWK =awk +MAKE =make +GENKSYMS=/sbin/genksyms + +all: do-it-all + +# +# Make "config" the default target if there is no configuration file or +# "depend" the target if there is no top-level dependency information. +# +ifeq (.config,$(wildcard .config)) +include .config +ifeq (.depend,$(wildcard .depend)) +include .depend +do-it-all: Version vmlinux +else +CONFIGURATION = depend +do-it-all: depend +endif +else +CONFIGURATION = config +do-it-all: config +endif + +# +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case +# the default of FLOPPY is used by 'build'. +# + +ROOT_DEV = CURRENT + +KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +# +# INSTALL_PATH specifies where to place the updated kernel and system map +# images. Uncomment if you want to place them anywhere other than root. + +#INSTALL_PATH=/boot + +# +# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory +# relocations required by build roots. This is not defined in the +# makefile but the arguement can be passed to make if needed. +# + +# +# If you want to preset the SVGA mode, uncomment the next line and +# set SVGA_MODE to whatever number you want. +# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. +# The number is the same as you would ordinarily press at bootup. +# + +SVGA_MODE= -DSVGA_MODE=NORMAL_VGA + +# +# standard CFLAGS +# + +CFLAGS = -Wall -Wstrict-prototypes -O2 +ifeq ($(CONFIG_KERNEL_DEBUGGING),y) + CFLAGS += -fno-omit-frame-pointer + # Profiling is a big overhead so only turn it on if the user really wants it. + ifeq ($(CONFIG_DEBUG_MCOUNT),y) + CFLAGS += -pg + endif +else + CFLAGS += -fomit-frame-pointer +endif + +# use '-fno-strict-aliasing', but only if the compiler can take it +CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) + +ifdef CONFIG_SMP +CFLAGS += -D__SMP__ +AFLAGS += -D__SMP__ +endif + +# +# if you want the RAM disk device, define this to be the +# size in blocks. +# + +#RAMDISK = -DRAMDISK=512 + +# Include the make variables (CC, etc...) +# + +CORE_FILES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o +ifeq ($(CONFIG_KERNEL_DEBUGGING),y) + CORE_FILES +=kernel/debug/debug.o +endif +FILESYSTEMS =fs/filesystems.a +NETWORKS =net/network.a +DRIVERS =drivers/block/block.a \ + drivers/char/char.o \ + drivers/misc/misc.o \ + drivers/net/net.o \ + drivers/parport/parport.a +LIBS =$(TOPDIR)/lib/lib.a +SUBDIRS =kernel drivers mm fs net ipc lib + +ifdef CONFIG_NUBUS +DRIVERS := $(DRIVERS) drivers/nubus/nubus.a +endif + +ifeq ($(CONFIG_ISDN),y) +DRIVERS := $(DRIVERS) drivers/isdn/isdn.a +endif + +ifdef CONFIG_NET_FC +DRIVERS := $(DRIVERS) drivers/net/fc/fc.a +endif + +ifdef CONFIG_TR +DRIVERS := $(DRIVERS) drivers/net/tokenring/tr.a +endif + +ifdef CONFIG_WAN +DRIVERS := $(DRIVERS) drivers/net/wan/wan.a +endif + +ifdef CONFIG_ATM +DRIVERS := $(DRIVERS) drivers/atm/atm.a +endif + +ifeq ($(CONFIG_SCSI),y) +DRIVERS := $(DRIVERS) drivers/scsi/scsi.a +endif + +ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) +DRIVERS := $(DRIVERS) drivers/cdrom/cdrom.a +endif + +ifeq ($(CONFIG_SOUND),y) +DRIVERS := $(DRIVERS) drivers/sound/sounddrivers.o +endif + +ifdef CONFIG_PCI +DRIVERS := $(DRIVERS) drivers/pci/pci.a +endif + +ifeq ($(CONFIG_PCMCIA),y) +DRIVERS := $(DRIVERS) drivers/pcmcia/pcmcia.o +endif + +ifeq ($(CONFIG_PCMCIA_NETCARD),y) +DRIVERS := $(DRIVERS) drivers/net/pcmcia/pcmcia_net.o +endif + +ifeq ($(CONFIG_PCMCIA_CHRDEV),y) +DRIVERS := $(DRIVERS) drivers/char/pcmcia/pcmcia_char.o +endif + +ifdef CONFIG_DIO +DRIVERS := $(DRIVERS) drivers/dio/dio.a +endif + +ifdef CONFIG_SBUS +DRIVERS := $(DRIVERS) drivers/sbus/sbus.a +endif + +ifdef CONFIG_ZORRO +DRIVERS := $(DRIVERS) drivers/zorro/zorro.a +endif + +ifeq ($(CONFIG_FC4),y) +DRIVERS := $(DRIVERS) drivers/fc4/fc4.a +endif + +ifdef CONFIG_PPC +DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a +endif + +ifeq ($(CONFIG_PNP),y) +DRIVERS := $(DRIVERS) drivers/pnp/pnp.a +endif + +ifdef CONFIG_SGI +DRIVERS := $(DRIVERS) drivers/sgi/sgi.a +endif + +ifdef CONFIG_VT +DRIVERS := $(DRIVERS) drivers/video/video.a +endif + +ifeq ($(CONFIG_PARIDE),y) +DRIVERS := $(DRIVERS) drivers/block/paride/paride.a +endif + +ifdef CONFIG_HAMRADIO +DRIVERS := $(DRIVERS) drivers/net/hamradio/hamradio.o +endif + +ifeq ($(CONFIG_TC),y) +DRIVERS := $(DRIVERS) drivers/tc/tc.a +endif + +ifeq ($(CONFIG_USB),y) +DRIVERS := $(DRIVERS) drivers/usb/usb.a +endif + +ifeq ($(CONFIG_I2O),y) +DRIVERS := $(DRIVERS) drivers/i2o/i2o.a +endif + +ifeq ($(CONFIG_IRDA),y) +DRIVERS := $(DRIVERS) drivers/net/irda/irda_drivers.a +endif + +include arch/$(ARCH)/Makefile + +.S.s: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.s $< +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c -o $*.o $< + +Version: dummy + @rm -f include/linux/compile.h + +boot: vmlinux + @$(MAKE) -C arch/$(ARCH)/boot + +ifeq ($(CONFIG_KDB),y) +vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs + echo "c0000000 t firstaddr\n" > System.map + rm -f map map.out + $(AWK) -f scripts/genkdbsym.awk System.map > dummy_sym.c + $(CC) -c -o dummy_sym.o dummy_sym.c + $(LD) $(LINKFLAGS) $(HEAD) -Map map init/main.o init/version.o \ + --start-group \ + $(CORE_FILES) \ + $(FILESYSTEMS) \ + $(NETWORKS) \ + $(DRIVERS) \ + $(LIBS) \ + dummy_sym.o \ + --end-group \ + -o vmlinux + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + cp System.map System.map.sv + $(AWK) -f scripts/genkdbsym.awk System.map > ksym.c + $(CC) -c -o ksym.o ksym.c > ksym.o + $(LD) $(LINKFLAGS) $(HEAD) -Map map.out init/main.o init/version.o \ + --start-group \ + $(CORE_FILES) \ + $(FILESYSTEMS) \ + $(NETWORKS) \ + $(DRIVERS) \ + $(LIBS) \ + ksym.o \ + --end-group \ + -o vmlinux + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map +else +vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs + $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ + --start-group \ + $(CORE_FILES) \ + $(FILESYSTEMS) \ + $(NETWORKS) \ + $(DRIVERS) \ + $(LIBS) \ + --end-group \ + -o vmlinux + $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map +endif + +symlinks: + rm -f include/asm + ( cd include ; ln -sf asm-$(ARCH) asm) + @if [ ! -d include/linux/modules ]; then \ + mkdir include/linux/modules; \ + fi + +oldconfig: symlinks + $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in + +xconfig: symlinks + $(MAKE) -C scripts kconfig.tk + wish -f scripts/kconfig.tk + +menuconfig: include/linux/version.h symlinks + $(MAKE) -C scripts/lxdialog all + $(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in + +config: symlinks + $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in + +include/config/MARKER: scripts/split-include include/linux/autoconf.h + scripts/split-include include/linux/autoconf.h include/config + @ touch include/config/MARKER + +debug: include/linux/version.h + $(MAKE) -C scripts ktrace + $(MAKE) -C scripts/memleak all + +linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS)) + +$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/config/MARKER + $(MAKE) -C $(patsubst _dir_%, %, $@) + +$(TOPDIR)/include/linux/version.h: include/linux/version.h +$(TOPDIR)/include/linux/compile.h: include/linux/compile.h + +newversion: + @if [ ! -f .version ]; then \ + echo 1 > .version; \ + else \ + expr 0`cat .version` + 1 > .version; \ + fi + +include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion + @echo -n \#define UTS_VERSION \"\#`cat .version` > .ver + @if [ -n "$(CONFIG_SMP)" ] ; then echo -n " SMP" >> .ver; fi + @if [ -f .name ]; then echo -n \-`cat .name` >> .ver; fi + @echo ' '`date`'"' >> .ver + @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> .ver + @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> .ver + @echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> .ver + @if [ -x /bin/dnsdomainname ]; then \ + echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname`\"; \ + elif [ -x /bin/domainname ]; then \ + echo \#define LINUX_COMPILE_DOMAIN \"`domainname`\"; \ + else \ + echo \#define LINUX_COMPILE_DOMAIN ; \ + fi >> .ver + @echo \#define LINUX_COMPILER \"`$(CC) $(CFLAGS) -v 2>&1 | tail -1`\" >> .ver + @mv -f .ver $@ + +include/linux/version.h: ./Makefile + @echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver + @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver + @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver + @mv -f .ver $@ + +init/version.o: init/version.c include/linux/compile.h include/config/MARKER + $(CC) $(CFLAGS) -DUTS_MACHINE='"$(ARCH)"' -c -o init/version.o init/version.c + +init/main.o: init/main.c include/config/MARKER + $(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $< + +fs lib mm ipc kernel drivers net: dummy + $(MAKE) $(subst $@, _dir_$@, $@) + +MODFLAGS = -DMODULE +ifdef CONFIG_MODULES +ifdef CONFIG_MODVERSIONS +MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h +endif + +modules: $(patsubst %, _mod_%, $(SUBDIRS)) + +modules/MARKER: + mkdir -p modules + touch modules/MARKER + +$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h include/config/MARKER modules/MARKER + $(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules + +modules_install: + @( \ + MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE); \ + cd modules; \ + MODULES=""; \ + inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \ + mkdir -p $$MODLIB/$$2; cp $$These $$MODLIB/$$2; \ + echo Installing modules under $$MODLIB/$$2; \ + }; \ + mkdir -p $$MODLIB; \ + \ + if [ -f BLOCK_MODULES ]; then inst_mod BLOCK_MODULES block; fi; \ + if [ -f NET_MODULES ]; then inst_mod NET_MODULES net; fi; \ + if [ -f IPV4_MODULES ]; then inst_mod IPV4_MODULES ipv4; fi; \ + if [ -f IPV6_MODULES ]; then inst_mod IPV6_MODULES ipv6; fi; \ + if [ -f ATM_MODULES ]; then inst_mod ATM_MODULES atm; fi; \ + if [ -f SCSI_MODULES ]; then inst_mod SCSI_MODULES scsi; fi; \ + if [ -f FS_MODULES ]; then inst_mod FS_MODULES fs; fi; \ + if [ -f NLS_MODULES ]; then inst_mod NLS_MODULES fs; fi; \ + if [ -f CDROM_MODULES ]; then inst_mod CDROM_MODULES cdrom; fi; \ + if [ -f HAM_MODULES ]; then inst_mod HAM_MODULES net; fi; \ + if [ -f SOUND_MODULES ]; then inst_mod SOUND_MODULES sound; fi; \ + if [ -f VIDEO_MODULES ]; then inst_mod VIDEO_MODULES video; fi; \ + if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \ + if [ -f IRDA_MODULES ]; then inst_mod IRDA_MODULES net; fi; \ + if [ -f USB_MODULES ]; then inst_mod USB_MODULES usb; fi; \ + if [ -f PCMCIA_MODULES ]; then inst_mod PCMCIA_MODULES pcmcia; fi; \ + if [ -f PCMCIA_NET_MODULES ]; then inst_mod PCMCIA_NET_MODULES pcmcia; fi; \ + if [ -f PCMCIA_CHAR_MODULES ]; then inst_mod PCMCIA_CHAR_MODULES pcmcia; fi; \ + \ + ls *.o > $$MODLIB/.allmods; \ + echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ + if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \ + rm -f $$MODLIB/.misc $$MODLIB/.allmods; \ + ) + +# modules disabled.... + +else +modules modules_install: dummy + @echo + @echo "The present kernel configuration has modules disabled." + @echo "Type 'make config' and enable loadable module support." + @echo "Then build a kernel with module support enabled." + @echo + @exit 1 +endif + +clean: archclean + rm -f kernel/ksyms.lst include/linux/compile.h + find . -name '*.[oas]' -type f -print | grep -v lxdialog/ | xargs rm -f + rm -f core `find . -type f -name 'core' -print` + rm -f core `find . -type f -name '.*.flags' -print` + rm -f vmlinux System.map + rm -f .tmp* + rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c + rm -f drivers/char/conmakehash + rm -f drivers/pci/devlist.h drivers/pci/gen-devlist + rm -f drivers/sound/bin2hex drivers/sound/hex2hex + rm -f net/khttpd/make_times_h + rm -f net/khttpd/times.h + rm -f submenu* + rm -rf modules + +mrproper: clean archmrproper + rm -f include/linux/autoconf.h include/linux/version.h + rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h + rm -f drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h + rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h + rm -f drivers/net/hamradio/soundmodem/gentbl + rm -f drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h + rm -f drivers/sound/*_boot.h drivers/sound/.*.boot + rm -f .version .config* config.in config.old + rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp + rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog + rm -f .menuconfig.log + rm -f include/asm + rm -rf include/config + rm -f .depend `find . -type f -name .depend -print` + rm -f core `find . -type f -size 0 -print` + rm -f .hdepend scripts/mkdep scripts/split-include + rm -f $(TOPDIR)/include/linux/modversions.h + rm -rf $(TOPDIR)/include/linux/modules + +distclean: mrproper + rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ + -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ + -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS + +backup: mrproper + cd .. && tar cf - linux/ | gzip -9 > backup.gz + sync + +sums: + find . -type f -print | sort | xargs sum > .SUMS + +dep-files: scripts/mkdep archdep include/linux/version.h + scripts/mkdep init/*.c > .depend + scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend + $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS) scripts) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS) scripts" + +MODVERFILE := + +ifdef CONFIG_MODVERSIONS +MODVERFILE := $(TOPDIR)/include/linux/modversions.h +endif + +depend dep: dep-files $(MODVERFILE) + +# make checkconfig: Prune 'scripts' directory to avoid "false positives". +checkconfig: + perl -w scripts/checkconfig.pl `find * -path 'scripts' -prune -o -name '*.[hcS]' -print | sort` + +checkhelp: + perl -w scripts/checkhelp.pl `find * -name [cC]onfig.in -print` + +ifdef CONFIGURATION +..$(CONFIGURATION): + @echo + @echo "You have a bad or nonexistent" .$(CONFIGURATION) ": running 'make" $(CONFIGURATION)"'" + @echo + $(MAKE) $(CONFIGURATION) + @echo + @echo "Successful. Try re-making (ignore the error that follows)" + @echo + exit 1 + +#dummy: ..$(CONFIGURATION) +dummy: + +else + +dummy: + +endif + +include Rules.make + +# +# This generates dependencies for the .h files. +# + +scripts/mkdep: scripts/mkdep.c + $(HOSTCC) $(HOSTCFLAGS) -o scripts/mkdep scripts/mkdep.c + +scripts/split-include: scripts/split-include.c + $(HOSTCC) $(HOSTCFLAGS) -o scripts/split-include scripts/split-include.c diff -urN 2.3.29pre1/arch/alpha/config.in 2.3.29pre1-ikd/arch/alpha/config.in --- 2.3.29pre1/arch/alpha/config.in Sun Nov 7 17:33:35 1999 +++ 2.3.29pre1-ikd/arch/alpha/config.in Mon Nov 22 16:56:22 1999 @@ -272,4 +272,7 @@ fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ + +source kernel/debug/Config.in + endmenu diff -urN 2.3.29pre1/arch/alpha/config.in.orig 2.3.29pre1-ikd/arch/alpha/config.in.orig --- 2.3.29pre1/arch/alpha/config.in.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/alpha/config.in.orig Sun Nov 7 17:33:35 1999 @@ -0,0 +1,275 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +mainmenu_name "Kernel configuration of Linux for Alpha machines" + +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel module loader' CONFIG_KMOD +fi +endmenu + +mainmenu_option next_comment +comment 'General setup' + +choice 'Alpha system type' \ + "Generic CONFIG_ALPHA_GENERIC \ + Alcor/Alpha-XLT CONFIG_ALPHA_ALCOR \ + Alpha-XL CONFIG_ALPHA_XL \ + AlphaBook1 CONFIG_ALPHA_BOOK1 \ + Avanti CONFIG_ALPHA_AVANTI \ + Cabriolet CONFIG_ALPHA_CABRIOLET \ + DP264 CONFIG_ALPHA_DP264 \ + EB164 CONFIG_ALPHA_EB164 \ + EB64+ CONFIG_ALPHA_EB64P \ + EB66 CONFIG_ALPHA_EB66 \ + EB66+ CONFIG_ALPHA_EB66P \ + Jensen CONFIG_ALPHA_JENSEN \ + LX164 CONFIG_ALPHA_LX164 \ + Miata CONFIG_ALPHA_MIATA \ + Mikasa CONFIG_ALPHA_MIKASA \ + Noname CONFIG_ALPHA_NONAME \ + Noritake CONFIG_ALPHA_NORITAKE \ + PC164 CONFIG_ALPHA_PC164 \ + Platform2000 CONFIG_ALPHA_P2K \ + Rawhide CONFIG_ALPHA_RAWHIDE \ + Ruffian CONFIG_ALPHA_RUFFIAN \ + RX164 CONFIG_ALPHA_RX164 \ + SX164 CONFIG_ALPHA_SX164 \ + Sable CONFIG_ALPHA_SABLE \ + Takara CONFIG_ALPHA_TAKARA" Generic + +# clear all implied options (don't want default values for those): +unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 +unset CONFIG_PCI CONFIG_ALPHA_EISA +unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA +unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS +unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA + +if [ "$CONFIG_ALPHA_GENERIC" = "y" ] +then + define_bool CONFIG_PCI y +fi +if [ "$CONFIG_ALPHA_BOOK1" = "y" ] +then + define_bool CONFIG_ALPHA_NONAME y +fi +if [ "$CONFIG_ALPHA_NONAME" = "y" -o "$CONFIG_ALPHA_EB66" = "y" \ + -o "$CONFIG_ALPHA_EB66P" = "y" -o "$CONFIG_ALPHA_P2K" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV4 y + define_bool CONFIG_ALPHA_LCA y +fi +if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ + -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_XL" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV4 y + define_bool CONFIG_ALPHA_APECS y +fi +if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ + -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" \ + -o "$CONFIG_ALPHA_TAKARA" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_CIA y +fi +if [ "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ] +then + bool 'EV5 CPU daughtercard (model 5/xxx)?' CONFIG_ALPHA_PRIMO + if [ "$CONFIG_ALPHA_PRIMO" = "y" ] + then + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_CIA y + else + define_bool CONFIG_ALPHA_EV4 y + define_bool CONFIG_ALPHA_APECS y + fi + define_bool CONFIG_PCI y +fi +if [ "$CONFIG_ALPHA_SABLE" = "y" ] +then + define_bool CONFIG_PCI y + bool 'EV5 CPU(s) (model 5/xxx)?' CONFIG_ALPHA_GAMMA + if [ "$CONFIG_ALPHA_GAMMA" = "y" ] + then + define_bool CONFIG_ALPHA_EV5 y + else + define_bool CONFIG_ALPHA_EV4 y + fi + define_bool CONFIG_ALPHA_T2 y +fi +if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \ + -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_PYXIS y +fi +if [ "$CONFIG_ALPHA_DP264" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV6 y + define_bool CONFIG_ALPHA_TSUNAMI y +fi +if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_MCPCIA y +fi +if [ "$CONFIG_ALPHA_RX164" = "y" ] +then + define_bool CONFIG_PCI y + define_bool CONFIG_ALPHA_EV5 y + define_bool CONFIG_ALPHA_POLARIS y +fi +if [ "$CONFIG_ALPHA_JENSEN" = "y" ] +then + define_bool CONFIG_ALPHA_EV4 y +fi + +if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \ + -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ + -o "$CONFIG_ALPHA_TAKARA" = "y" -o "$CONFIG_ALPHA_EB164" = "y" \ + -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \ + -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ + -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ + -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" \ + -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" ] +then + bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM +fi +if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \ + -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \ + -o "$CONFIG_ALPHA_RAWHIDE" = "y" ] +then + define_bool CONFIG_ALPHA_EISA y +fi +if [ "$CONFIG_ALPHA_XL" = "y" ] +then + define_bool CONFIG_ALPHA_AVANTI y +fi + +if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ + -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ] +then + bool 'Symmetric multi-processing support' CONFIG_SMP +fi + +bool 'Networking support' CONFIG_NET +bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_PROC_FS" = "y" ]; then + choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +fi +tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86 +source drivers/parport/Config.in +endmenu + +source drivers/pnp/Config.in + +source drivers/block/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in +fi +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi + fi + endmenu +fi + +source net/ax25/Config.in + +mainmenu_option next_comment +comment 'ISDN subsystem' + +tristate 'ISDN support' CONFIG_ISDN +if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in +fi +endmenu + +mainmenu_option next_comment +comment 'Old CD-ROM drivers (not SCSI, not IDE)' + +bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI +if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in +fi +endmenu + +source drivers/char/Config.in + +source fs/Config.in + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + bool 'VGA text console' CONFIG_VGA_CONSOLE + bool 'Support for frame buffer devices' CONFIG_FB + if [ "$CONFIG_FB" = "y" ]; then + define_bool CONFIG_PCI_CONSOLE y + fi + source drivers/video/Config.in + endmenu +fi + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel FP software completion' CONFIG_MATHEMU +else + define_tristate CONFIG_MATHEMU y +fi + +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +endmenu diff -urN 2.3.29pre1/arch/alpha/kernel/entry.S 2.3.29pre1-ikd/arch/alpha/kernel/entry.S --- 2.3.29pre1/arch/alpha/kernel/entry.S Tue Sep 14 14:34:57 1999 +++ 2.3.29pre1-ikd/arch/alpha/kernel/entry.S Mon Nov 22 16:56:22 1999 @@ -115,6 +115,17 @@ ldq $28,144($30); \ addq $30,184,$30 +/* + * Conditionally do profiling + */ +#ifdef CONFIG_TRACER +#define CALL_MCOUNT \ + lda $28,_mcount; \ + jsr $28,($28),_mcount +#else +#define CALL_MCOUNT +#endif + .text .set noat #if defined(__linux__) && !defined(__ELF__) @@ -137,6 +148,8 @@ .ent entMM entMM: SAVE_ALL + ldq $8,current_set + CALL_MCOUNT /* save $9 - $15 so the inline exception code can manipulate them. */ subq $30,56,$30 stq $9,0($30) @@ -387,6 +400,11 @@ .ent entUna entUna: lda $30,-256($30) +#ifdef CONFIG_TRACER + stq $8,64($30) + ldq $8,current_set +#endif + CALL_MCOUNT stq $0,0($30) ldq $0,256($30) /* get PS */ stq $1,8($30) @@ -398,6 +416,10 @@ stq $5,40($30) stq $6,48($30) stq $7,56($30) +#ifndef CONFIG_TRACER + stq $8,64($30) + ldq $8,current_set +#endif stq $8,64($30) stq $9,72($30) stq $10,80($30) @@ -458,6 +480,9 @@ .ent entUnaUser entUnaUser: ldq $0,0($30) /* restore original $0 */ +#ifdef CONFIG_TRACER + ldq $8,64($30) +#endif lda $30,256($30) /* pop entUna's stack frame */ SAVE_ALL /* setup normal kernel stack */ lda $30,-56($30) @@ -590,6 +615,7 @@ beq $4,restore_all bne $5,signal_return restore_all: + CALL_MCOUNT RESTORE_ALL call_pal PAL_rti diff -urN 2.3.29pre1/arch/alpha/lib/Makefile 2.3.29pre1-ikd/arch/alpha/lib/Makefile --- 2.3.29pre1/arch/alpha/lib/Makefile Tue Sep 14 14:33:08 1999 +++ 2.3.29pre1-ikd/arch/alpha/lib/Makefile Mon Nov 22 16:56:22 1999 @@ -10,6 +10,10 @@ csum_ipv6_magic.o strcasecmp.o semaphore.o \ srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o +ifeq ($(CONFIG_KERNEL_DEBUGGING),y) + OBJS += _mcount.o +endif + lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff -urN 2.3.29pre1/arch/alpha/mm/fault.c 2.3.29pre1-ikd/arch/alpha/mm/fault.c --- 2.3.29pre1/arch/alpha/mm/fault.c Tue Sep 14 14:34:05 1999 +++ 2.3.29pre1-ikd/arch/alpha/mm/fault.c Mon Nov 22 16:56:22 1999 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -98,6 +99,8 @@ if (!mm || in_interrupt()) goto no_context; + prof_trap_entry(); + down(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -171,6 +174,7 @@ "virtual address %016lx\n", address); die_if_kernel("Oops", regs, cause, (unsigned long*)regs - 16); do_exit(SIGKILL); + prof_trap_exit(); /* * We ran out of memory, or some other thing happened to us that made diff -urN 2.3.29pre1/arch/i386/Makefile 2.3.29pre1-ikd/arch/i386/Makefile --- 2.3.29pre1/arch/i386/Makefile Tue Oct 26 21:30:50 1999 +++ 2.3.29pre1-ikd/arch/i386/Makefile Mon Nov 22 16:56:22 1999 @@ -69,6 +69,12 @@ CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a +ifdef CONFIG_KDB +LIBS := $(LIBS) $(TOPDIR)/arch/i386/kdb/kdb.a +CORE_FILES := $(CORE_FILES) arch/i386/kdb/kdb.o +SUBDIRS := $(SUBDIRS) arch/i386/kdb +endif + ifdef CONFIG_MATH_EMULATION SUBDIRS := $(SUBDIRS) arch/i386/math-emu DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a @@ -79,6 +85,11 @@ arch/i386/mm: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/i386/mm + +ifdef CONFIG_KDB +arch/i386/kdb: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/i386/kdb +endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot diff -urN 2.3.29pre1/arch/i386/config.in 2.3.29pre1-ikd/arch/i386/config.in --- 2.3.29pre1/arch/i386/config.in Sun Nov 7 17:33:35 1999 +++ 2.3.29pre1-ikd/arch/i386/config.in Mon Nov 22 16:56:22 1999 @@ -221,4 +221,16 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ + +source kernel/debug/Config.in + +# arch specific debugging options +if [ "$CONFIG_KERNEL_DEBUGGING" = "y" ]; then + bool ' Print %eip to resolve symbols from locks' CONFIG_PRINT_EIP n + bool ' Kernel memory leak detection support' CONFIG_MEMLEAK n + bool ' Built-in Kernel Debugger support' CONFIG_KDB n + if [ "$CONFIG_KDB" = "y" ]; then + define_bool CONFIG_KDB_FRAMEPTR y + fi +fi endmenu diff -urN 2.3.29pre1/arch/i386/config.in.orig 2.3.29pre1-ikd/arch/i386/config.in.orig --- 2.3.29pre1/arch/i386/config.in.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/config.in.orig Sun Nov 7 17:33:35 1999 @@ -0,0 +1,224 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +mainmenu_name "Linux Kernel Configuration" + +define_bool CONFIG_X86 y +define_bool CONFIG_ISA y + +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment +comment 'Processor type and features' +choice 'Processor family' \ + "386 CONFIG_M386 \ + 486/Cx486 CONFIG_M486 \ + 586/K5/5x86/6x86 CONFIG_M586 \ + Pentium/K6/TSC CONFIG_M586TSC \ + PPro/6x86MX CONFIG_M686 \ + Athlon CONFIG_MK7" PPro +# +# Define implied options from the CPU selection here +# +if [ "$CONFIG_M386" != "y" ]; then + define_bool CONFIG_X86_WP_WORKS_OK y + define_bool CONFIG_X86_INVLPG y + define_bool CONFIG_X86_BSWAP y + define_bool CONFIG_X86_POPAD_OK y +fi +if [ "$CONFIG_M686" = "y" -o "$CONFIG_M586TSC" = "y" ]; then + define_bool CONFIG_X86_TSC y +fi +if [ "$CONFIG_M686" = "y" ]; then + define_bool CONFIG_X86_GOOD_APIC y +fi +if [ "$CONFIG_MK7" = "y" ]; then + define_bool CONFIG_X86_TSC y + define_bool CONFIG_X86_GOOD_APIC y + define_bool CONFIG_X86_USE_3DNOW y +fi + +choice 'High Memory Support' \ + "off CONFIG_NOHIGHMEM \ + 4GB CONFIG_HIGHMEM4G \ + 64GB CONFIG_HIGHMEM64G" off +if [ "$CONFIG_HIGHMEM4G" = "y" ]; then + define_bool CONFIG_HIGHMEM y +fi +if [ "$CONFIG_HIGHMEM64G" = "y" ]; then + define_bool CONFIG_HIGHMEM y + define_bool CONFIG_X86_PAE y +fi + +bool 'Math emulation' CONFIG_MATH_EMULATION +bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR +bool 'Symmetric multi-processing support' CONFIG_SMP +endmenu + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool ' Set version information on all module symbols' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD +fi +endmenu + +mainmenu_option next_comment +comment 'General setup' + +bool 'Networking support' CONFIG_NET +bool 'SGI Visual Workstation support' CONFIG_VISWS +if [ "$CONFIG_VISWS" = "y" ]; then + define_bool CONFIG_X86_VISWS_APIC y + define_bool CONFIG_X86_LOCAL_APIC y + define_bool CONFIG_PCI y +else + if [ "$CONFIG_SMP" = "y" ]; then + define_bool CONFIG_X86_IO_APIC y + define_bool CONFIG_X86_LOCAL_APIC y + fi + bool 'PCI support' CONFIG_PCI + if [ "$CONFIG_PCI" = "y" ]; then + choice ' PCI access mode' \ + "BIOS CONFIG_PCI_GOBIOS \ + Direct CONFIG_PCI_GODIRECT \ + Any CONFIG_PCI_GOANY" Any + if [ "$CONFIG_PCI_GOBIOS" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then + define_bool CONFIG_PCI_BIOS y + fi + if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then + define_bool CONFIG_PCI_DIRECT y + fi + fi + bool 'MCA support' CONFIG_MCA + +fi + +source drivers/pcmcia/Config.in + +bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_PROC_FS" = "y" ]; then + choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +fi +tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC + +source drivers/parport/Config.in + +bool 'Advanced Power Management BIOS support' CONFIG_APM +if [ "$CONFIG_APM" != "n" ]; then + bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND + bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE + bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE + bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK + bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE + bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT + bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS +fi + +endmenu + + +source drivers/pnp/Config.in + +source drivers/block/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in +fi +endmenu + +source drivers/i2o/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi + fi + endmenu +fi + +source net/ax25/Config.in + +source net/irda/Config.in + +mainmenu_option next_comment +comment 'ISDN subsystem' +if [ "$CONFIG_NET" != "n" ]; then + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in + fi +fi +endmenu + +mainmenu_option next_comment +comment 'Old CD-ROM drivers (not SCSI, not IDE)' + +bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI +if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in +fi +endmenu + +source drivers/char/Config.in + +source drivers/usb/Config.in + +source drivers/misc/Config.in + +source fs/Config.in + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + bool 'VGA text console' CONFIG_VGA_CONSOLE + bool 'Video mode selection support' CONFIG_VIDEO_SELECT + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE + source drivers/video/Config.in + fi + endmenu +fi + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +endmenu diff -urN 2.3.29pre1/arch/i386/kdb/Makefile 2.3.29pre1-ikd/arch/i386/kdb/Makefile --- 2.3.29pre1/arch/i386/kdb/Makefile Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/Makefile Mon Nov 22 16:56:22 1999 @@ -0,0 +1,23 @@ +# +# Makefile for i386-specific kdb files.. +# +# Copyright 1999, Silicon Graphics Inc. +# +# Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o + +L_TARGET = kdb.a +L_OBJS = kdb.o i386-dis.o kd_id.o kdbsupport.o kdb_io.o kdb_bp.o kdb_bt.o + +MOD_SUB_DIRS += modules + +override CFLAGS := $(CFLAGS:%-pg=%-g -c) + +include $(TOPDIR)/Rules.make diff -urN 2.3.29pre1/arch/i386/kdb/dis-asm.h 2.3.29pre1-ikd/arch/i386/kdb/dis-asm.h --- 2.3.29pre1/arch/i386/kdb/dis-asm.h Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/dis-asm.h Mon Nov 22 16:56:22 1999 @@ -0,0 +1,242 @@ +/* Interface between the opcode library and its callers. + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +/* Hacked by Scott Lurndal at SGI (02/1999) for linux kernel debugger */ + +#ifndef DIS_ASM_H +#define DIS_ASM_H + + /* + * Misc definitions + */ +#define ARGS(x) x +#define UNINITIALIZED(x) x +#define PTR void * +#define FILE int +#if !defined(NULL) +#define NULL 0 +#endif + +#include + +typedef int (*fprintf_ftype) PARAMS((FILE*, const char*, ...)); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + FILE *stream; + PTR application_data; + + /* Target description. We could replace this with a pointer to the bfd, + but that would require one. There currently isn't any such requirement + so to avoid introducing one we record these explicitly. */ + /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ + enum bfd_flavour flavour; + /* The bfd_arch value. */ + enum bfd_architecture arch; + /* The bfd_mach value. */ + unsigned long mach; + /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ + enum bfd_endian endian; + /* The symbol at the start of the function being disassembled. This + is not set reliably, but if it is not NULL, it is correct. */ + asymbol *symbol; + + /* For use by the disassembler. + The top 16 bits are reserved for public use (and are documented here). + The bottom 16 bits are for the internal use of the disassembler. */ + unsigned long flags; +#define INSN_HAS_RELOC 0x80000000 + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, int length, + struct disassemble_info *info)); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info)); + + /* Function called to print ADDR. */ + void (*print_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info *info)); + + /* Function called to determine if there is a symbol at the given ADDR. + If there is, the function returns 1, otherwise it returns 0. + This is used by ports which support an overlay manager where + the overlay number is held in the top part of an address. In + some circumstances we want to include the overlay number in the + address, (normally because there is a symbol associated with + that address), but sometimes we want to mask out the overlay bits. */ + int (* symbol_at_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info * info)); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + int buffer_length; + + /* This variable may be set by the instruction decoder. It suggests + the number of bytes objdump should display on a single line. If + the instruction decoder sets this, it should always set it to + the same value in order to get reasonable looking output. */ + int bytes_per_line; + + /* the next two variables control the way objdump displays the raw data */ + /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ + /* output will look like this: + 00: 00000000 00000000 + with the chunks displayed according to "display_endian". */ + int bytes_per_chunk; + enum bfd_endian display_endian; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + +} disassemble_info; + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of bytes processed. */ +typedef int (*disassembler_ftype) + PARAMS((bfd_vma, disassemble_info *)); + +extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); +extern disassembler_ftype arc_get_disassembler PARAMS ((int, int)); +extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_shl PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); + +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler PARAMS ((bfd *)); + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + PARAMS ((bfd_vma, bfd_byte *, int, struct disassemble_info *)); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *)); + + +/* Just print the address in hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Always true. */ +extern int generic_symbol_at_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Macro to initialize a disassemble_info struct. This should be called + by all applications creating such a struct. */ +#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).flavour = bfd_target_unknown_flavour, \ + (INFO).arch = bfd_arch_unknown, \ + (INFO).mach = 0, \ + (INFO).endian = BFD_ENDIAN_UNKNOWN, \ + INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) + +/* Call this macro to initialize only the internal variables for the + disassembler. Architecture dependent things such as byte order, or machine + variant are not touched by this macro. This makes things much easier for + GDB which must initialize these things seperatly. */ + +#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).fprintf_func = (FPRINTF_FUNC), \ + (INFO).stream = (STREAM), \ + (INFO).symbol = NULL, \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).symbol_at_address_func = generic_symbol_at_address, \ + (INFO).flags = 0, \ + (INFO).bytes_per_line = 0, \ + (INFO).bytes_per_chunk = 0, \ + (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).insn_info_valid = 0 + +#endif /* ! defined (DIS_ASM_H) */ diff -urN 2.3.29pre1/arch/i386/kdb/i386-dis.c 2.3.29pre1-ikd/arch/i386/kdb/i386-dis.c --- 2.3.29pre1/arch/i386/kdb/i386-dis.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/i386-dis.c Mon Nov 22 16:56:22 1999 @@ -0,0 +1,2307 @@ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright (C) 1988, 89, 91, 93, 94, 95, 96, 1997 + Free Software Foundation, Inc. + +This file is part of GDB. + +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 +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * modified by John Hassey (hassey@dg-rtp.dg.com) + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ + +#include "dis-asm.h" +#if defined(__KERNEL__) +#include +#include +#endif + +#define MAXLEN 20 + +#if defined(STANDALONE) +#include +#endif /* STANDALONE */ + +static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); + +struct dis_private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; +#if defined(STANDALONE) + jmp_buf bailout; +#endif /* STANDALONE */ +}; + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct dis_private *)(info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (info, addr) + struct disassemble_info *info; + bfd_byte *addr; +{ + int status; + struct dis_private *priv = (struct dis_private *)info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + (*info->memory_error_func) (status, start, info); +#if defined(STANDALONE) + longjmp (priv->bailout, 1); +#else + /* XXX - what to do? */ + printk("Hmm. longjmp.\n"); +#endif + } + else + priv->max_fetched = addr; + return 1; +} + +#define Eb OP_E, b_mode +#define indirEb OP_indirE, b_mode +#define Gb OP_G, b_mode +#define Ev OP_E, v_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 +#define Mp OP_E, 0 /* ? */ +#define Gv OP_G, v_mode +#define Gw OP_G, w_mode +#define Rw OP_rm, w_mode +#define Rd OP_rm, d_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#if 0 +#define ONE OP_ONE, 0 +#endif +#define Cd OP_C, d_mode +#define Dd OP_D, d_mode +#define Td OP_T, d_mode + +#define eAX OP_REG, eAX_reg +#define eBX OP_REG, eBX_reg +#define eCX OP_REG, eCX_reg +#define eDX OP_REG, eDX_reg +#define eSP OP_REG, eSP_reg +#define eBP OP_REG, eBP_reg +#define eSI OP_REG, eSI_reg +#define eDI OP_REG, eDI_reg +#define AL OP_REG, al_reg +#define CL OP_REG, cl_reg +#define DL OP_REG, dl_reg +#define BL OP_REG, bl_reg +#define AH OP_REG, ah_reg +#define CH OP_REG, ch_reg +#define DH OP_REG, dh_reg +#define BH OP_REG, bh_reg +#define AX OP_REG, ax_reg +#define DX OP_REG, dx_reg +#define indirDX OP_REG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, lptr +#define Av OP_DIR, v_mode +#define Ob OP_OFF, b_mode +#define Ov OP_OFF, v_mode +#define Xb OP_DSSI, b_mode +#define Xv OP_DSSI, v_mode +#define Yb OP_ESDI, b_mode +#define Yv OP_ESDI, v_mode + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +#define MX OP_MMX, 0 +#define EM OP_EM, v_mode +#define MS OP_MS, b_mode + +typedef int (*op_rtn) PARAMS ((int bytemode, int aflag, int dflag)); + +static int OP_E PARAMS ((int, int, int)); +static int OP_G PARAMS ((int, int, int)); +static int OP_I PARAMS ((int, int, int)); +static int OP_indirE PARAMS ((int, int, int)); +static int OP_sI PARAMS ((int, int, int)); +static int OP_REG PARAMS ((int, int, int)); +static int OP_J PARAMS ((int, int, int)); +static int OP_DIR PARAMS ((int, int, int)); +static int OP_OFF PARAMS ((int, int, int)); +static int OP_ESDI PARAMS ((int, int, int)); +static int OP_DSSI PARAMS ((int, int, int)); +static int OP_SEG PARAMS ((int, int, int)); +static int OP_C PARAMS ((int, int, int)); +static int OP_D PARAMS ((int, int, int)); +static int OP_T PARAMS ((int, int, int)); +static int OP_rm PARAMS ((int, int, int)); +static int OP_ST PARAMS ((int, int, int)); +static int OP_STi PARAMS ((int, int, int)); +#if 0 +static int OP_ONE PARAMS ((int, int, int)); +#endif +static int OP_MMX PARAMS ((int, int, int)); +static int OP_EM PARAMS ((int, int, int)); +static int OP_MS PARAMS ((int, int, int)); + +static void append_prefix PARAMS ((void)); +static void set_op PARAMS ((int op)); +static void putop PARAMS ((char *template, int aflag, int dflag)); +static void dofloat PARAMS ((int aflag, int dflag)); +static int get16 PARAMS ((void)); +static int get32 PARAMS ((void)); +static void ckprefix PARAMS ((void)); + +#define b_mode 1 +#define v_mode 2 +#define w_mode 3 +#define d_mode 4 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 +#define eAX_reg 107 +#define eCX_reg 108 +#define eDX_reg 109 +#define eBX_reg 110 +#define eSP_reg 111 +#define eBP_reg 112 +#define eSI_reg 113 +#define eDI_reg 114 + +#define lptr 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define indir_dx_reg 150 + +#define GRP1b NULL, NULL, 0 +#define GRP1S NULL, NULL, 1 +#define GRP1Ss NULL, NULL, 2 +#define GRP2b NULL, NULL, 3 +#define GRP2S NULL, NULL, 4 +#define GRP2b_one NULL, NULL, 5 +#define GRP2S_one NULL, NULL, 6 +#define GRP2b_cl NULL, NULL, 7 +#define GRP2S_cl NULL, NULL, 8 +#define GRP3b NULL, NULL, 9 +#define GRP3S NULL, NULL, 10 +#define GRP4 NULL, NULL, 11 +#define GRP5 NULL, NULL, 12 +#define GRP6 NULL, NULL, 13 +#define GRP7 NULL, NULL, 14 +#define GRP8 NULL, NULL, 15 +#define GRP9 NULL, NULL, 16 +#define GRP10 NULL, NULL, 17 +#define GRP11 NULL, NULL, 18 +#define GRP12 NULL, NULL, 19 + +#define FLOATCODE 50 +#define FLOAT NULL, NULL, FLOATCODE + +struct dis386 { + char *name; + op_rtn op1; + int bytemode1; + op_rtn op2; + int bytemode2; + op_rtn op3; + int bytemode3; +}; + +static struct dis386 dis386[] = { + /* 00 */ + { "addb", Eb, Gb }, + { "addS", Ev, Gv }, + { "addb", Gb, Eb }, + { "addS", Gv, Ev }, + { "addb", AL, Ib }, + { "addS", eAX, Iv }, + { "pushS", es }, + { "popS", es }, + /* 08 */ + { "orb", Eb, Gb }, + { "orS", Ev, Gv }, + { "orb", Gb, Eb }, + { "orS", Gv, Ev }, + { "orb", AL, Ib }, + { "orS", eAX, Iv }, + { "pushS", cs }, + { "(bad)" }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcb", Eb, Gb }, + { "adcS", Ev, Gv }, + { "adcb", Gb, Eb }, + { "adcS", Gv, Ev }, + { "adcb", AL, Ib }, + { "adcS", eAX, Iv }, + { "pushS", ss }, + { "popS", ss }, + /* 18 */ + { "sbbb", Eb, Gb }, + { "sbbS", Ev, Gv }, + { "sbbb", Gb, Eb }, + { "sbbS", Gv, Ev }, + { "sbbb", AL, Ib }, + { "sbbS", eAX, Iv }, + { "pushS", ds }, + { "popS", ds }, + /* 20 */ + { "andb", Eb, Gb }, + { "andS", Ev, Gv }, + { "andb", Gb, Eb }, + { "andS", Gv, Ev }, + { "andb", AL, Ib }, + { "andS", eAX, Iv }, + { "(bad)" }, /* SEG ES prefix */ + { "daa" }, + /* 28 */ + { "subb", Eb, Gb }, + { "subS", Ev, Gv }, + { "subb", Gb, Eb }, + { "subS", Gv, Ev }, + { "subb", AL, Ib }, + { "subS", eAX, Iv }, + { "(bad)" }, /* SEG CS prefix */ + { "das" }, + /* 30 */ + { "xorb", Eb, Gb }, + { "xorS", Ev, Gv }, + { "xorb", Gb, Eb }, + { "xorS", Gv, Ev }, + { "xorb", AL, Ib }, + { "xorS", eAX, Iv }, + { "(bad)" }, /* SEG SS prefix */ + { "aaa" }, + /* 38 */ + { "cmpb", Eb, Gb }, + { "cmpS", Ev, Gv }, + { "cmpb", Gb, Eb }, + { "cmpS", Gv, Ev }, + { "cmpb", AL, Ib }, + { "cmpS", eAX, Iv }, + { "(bad)" }, /* SEG DS prefix */ + { "aas" }, + /* 40 */ + { "incS", eAX }, + { "incS", eCX }, + { "incS", eDX }, + { "incS", eBX }, + { "incS", eSP }, + { "incS", eBP }, + { "incS", eSI }, + { "incS", eDI }, + /* 48 */ + { "decS", eAX }, + { "decS", eCX }, + { "decS", eDX }, + { "decS", eBX }, + { "decS", eSP }, + { "decS", eBP }, + { "decS", eSI }, + { "decS", eDI }, + /* 50 */ + { "pushS", eAX }, + { "pushS", eCX }, + { "pushS", eDX }, + { "pushS", eBX }, + { "pushS", eSP }, + { "pushS", eBP }, + { "pushS", eSI }, + { "pushS", eDI }, + /* 58 */ + { "popS", eAX }, + { "popS", eCX }, + { "popS", eDX }, + { "popS", eBX }, + { "popS", eSP }, + { "popS", eBP }, + { "popS", eSI }, + { "popS", eDI }, + /* 60 */ + { "pusha" }, + { "popa" }, + { "boundS", Gv, Ma }, + { "arpl", Ew, Gw }, + { "(bad)" }, /* seg fs */ + { "(bad)" }, /* seg gs */ + { "(bad)" }, /* op size prefix */ + { "(bad)" }, /* adr size prefix */ + /* 68 */ + { "pushS", Iv }, /* 386 book wrong */ + { "imulS", Gv, Ev, Iv }, + { "pushS", sIb }, /* push of byte really pushes 2 or 4 bytes */ + { "imulS", Gv, Ev, Ib }, + { "insb", Yb, indirDX }, + { "insS", Yv, indirDX }, + { "outsb", indirDX, Xb }, + { "outsS", indirDX, Xv }, + /* 70 */ + { "jo", Jb }, + { "jno", Jb }, + { "jb", Jb }, + { "jae", Jb }, + { "je", Jb }, + { "jne", Jb }, + { "jbe", Jb }, + { "ja", Jb }, + /* 78 */ + { "js", Jb }, + { "jns", Jb }, + { "jp", Jb }, + { "jnp", Jb }, + { "jl", Jb }, + { "jnl", Jb }, + { "jle", Jb }, + { "jg", Jb }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)" }, + { GRP1Ss }, + { "testb", Eb, Gb }, + { "testS", Ev, Gv }, + { "xchgb", Eb, Gb }, + { "xchgS", Ev, Gv }, + /* 88 */ + { "movb", Eb, Gb }, + { "movS", Ev, Gv }, + { "movb", Gb, Eb }, + { "movS", Gv, Ev }, + { "movw", Ew, Sw }, + { "leaS", Gv, M }, + { "movw", Sw, Ew }, + { "popS", Ev }, + /* 90 */ + { "nop" }, + { "xchgS", eCX, eAX }, + { "xchgS", eDX, eAX }, + { "xchgS", eBX, eAX }, + { "xchgS", eSP, eAX }, + { "xchgS", eBP, eAX }, + { "xchgS", eSI, eAX }, + { "xchgS", eDI, eAX }, + /* 98 */ + { "cWtS" }, + { "cStd" }, + { "lcall", Ap }, + { "(bad)" }, /* fwait */ + { "pushf" }, + { "popf" }, + { "sahf" }, + { "lahf" }, + /* a0 */ + { "movb", AL, Ob }, + { "movS", eAX, Ov }, + { "movb", Ob, AL }, + { "movS", Ov, eAX }, + { "movsb", Yb, Xb }, + { "movsS", Yv, Xv }, + { "cmpsb", Yb, Xb }, + { "cmpsS", Yv, Xv }, + /* a8 */ + { "testb", AL, Ib }, + { "testS", eAX, Iv }, + { "stosb", Yb, AL }, + { "stosS", Yv, eAX }, + { "lodsb", AL, Xb }, + { "lodsS", eAX, Xv }, + { "scasb", AL, Yb }, + { "scasS", eAX, Yv }, + /* b0 */ + { "movb", AL, Ib }, + { "movb", CL, Ib }, + { "movb", DL, Ib }, + { "movb", BL, Ib }, + { "movb", AH, Ib }, + { "movb", CH, Ib }, + { "movb", DH, Ib }, + { "movb", BH, Ib }, + /* b8 */ + { "movS", eAX, Iv }, + { "movS", eCX, Iv }, + { "movS", eDX, Iv }, + { "movS", eBX, Iv }, + { "movS", eSP, Iv }, + { "movS", eBP, Iv }, + { "movS", eSI, Iv }, + { "movS", eDI, Iv }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "ret", Iw }, + { "ret" }, + { "lesS", Gv, Mp }, + { "ldsS", Gv, Mp }, + { "movb", Eb, Ib }, + { "movS", Ev, Iv }, + /* c8 */ + { "enter", Iw, Ib }, + { "leave" }, + { "lret", Iw }, + { "lret" }, + { "int3" }, + { "int", Ib }, + { "into" }, + { "iret" }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", Ib }, + { "aad", Ib }, + { "(bad)" }, + { "xlat" }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb }, + { "loope", Jb }, + { "loop", Jb }, + { "jCcxz", Jb }, + { "inb", AL, Ib }, + { "inS", eAX, Ib }, + { "outb", Ib, AL }, + { "outS", Ib, eAX }, + /* e8 */ + { "call", Av }, + { "jmp", Jv }, + { "ljmp", Ap }, + { "jmp", Jb }, + { "inb", AL, indirDX }, + { "inS", eAX, indirDX }, + { "outb", indirDX, AL }, + { "outS", indirDX, eAX }, + /* f0 */ + { "(bad)" }, /* lock prefix */ + { "(bad)" }, + { "(bad)" }, /* repne */ + { "(bad)" }, /* repz */ + { "hlt" }, + { "cmc" }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc" }, + { "stc" }, + { "cli" }, + { "sti" }, + { "cld" }, + { "std" }, + { GRP4 }, + { GRP5 }, +}; + +static struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew }, + { "lslS", Gv, Ew }, + { "(bad)" }, + { "(bad)" }, + { "clts" }, + { "(bad)" }, + /* 08 */ + { "invd" }, + { "wbinvd" }, + { "(bad)" }, { "ud2a" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 10 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 18 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "movl", Rd, Cd }, + { "movl", Rd, Dd }, + { "movl", Cd, Rd }, + { "movl", Dd, Rd }, + { "movl", Rd, Td }, + { "(bad)" }, + { "movl", Td, Rd }, + { "(bad)" }, + /* 28 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 30 */ + { "wrmsr" }, { "rdtsc" }, { "rdmsr" }, { "rdpmc" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 38 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 40 */ + { "cmovo", Gv,Ev }, { "cmovno", Gv,Ev }, { "cmovb", Gv,Ev }, { "cmovae", Gv,Ev }, + { "cmove", Gv,Ev }, { "cmovne", Gv,Ev }, { "cmovbe", Gv,Ev }, { "cmova", Gv,Ev }, + /* 48 */ + { "cmovs", Gv,Ev }, { "cmovns", Gv,Ev }, { "cmovp", Gv,Ev }, { "cmovnp", Gv,Ev }, + { "cmovl", Gv,Ev }, { "cmovge", Gv,Ev }, { "cmovle", Gv,Ev }, { "cmovg", Gv,Ev }, + /* 50 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 58 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 60 */ + { "punpcklbw", MX, EM }, + { "punpcklwd", MX, EM }, + { "punpckldq", MX, EM }, + { "packsswb", MX, EM }, + { "pcmpgtb", MX, EM }, + { "pcmpgtw", MX, EM }, + { "pcmpgtd", MX, EM }, + { "packuswb", MX, EM }, + /* 68 */ + { "punpckhbw", MX, EM }, + { "punpckhwd", MX, EM }, + { "punpckhdq", MX, EM }, + { "packssdw", MX, EM }, + { "(bad)" }, { "(bad)" }, + { "movd", MX, Ev }, + { "movq", MX, EM }, + /* 70 */ + { "(bad)" }, + { GRP10 }, + { GRP11 }, + { GRP12 }, + { "pcmpeqb", MX, EM }, + { "pcmpeqw", MX, EM }, + { "pcmpeqd", MX, EM }, + { "emms" }, + /* 78 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, + { "movd", Ev, MX }, + { "movq", EM, MX }, + /* 80 */ + { "jo", Jv }, + { "jno", Jv }, + { "jb", Jv }, + { "jae", Jv }, + { "je", Jv }, + { "jne", Jv }, + { "jbe", Jv }, + { "ja", Jv }, + /* 88 */ + { "js", Jv }, + { "jns", Jv }, + { "jp", Jv }, + { "jnp", Jv }, + { "jl", Jv }, + { "jge", Jv }, + { "jle", Jv }, + { "jg", Jv }, + /* 90 */ + { "seto", Eb }, + { "setno", Eb }, + { "setb", Eb }, + { "setae", Eb }, + { "sete", Eb }, + { "setne", Eb }, + { "setbe", Eb }, + { "seta", Eb }, + /* 98 */ + { "sets", Eb }, + { "setns", Eb }, + { "setp", Eb }, + { "setnp", Eb }, + { "setl", Eb }, + { "setge", Eb }, + { "setle", Eb }, + { "setg", Eb }, + /* a0 */ + { "pushS", fs }, + { "popS", fs }, + { "cpuid" }, + { "btS", Ev, Gv }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)" }, + { "(bad)" }, + /* a8 */ + { "pushS", gs }, + { "popS", gs }, + { "rsm" }, + { "btsS", Ev, Gv }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { "(bad)" }, + { "imulS", Gv, Ev }, + /* b0 */ + { "cmpxchgb", Eb, Gb }, + { "cmpxchgS", Ev, Gv }, + { "lssS", Gv, Mp }, /* 386 lists only Mp */ + { "btrS", Ev, Gv }, + { "lfsS", Gv, Mp }, /* 386 lists only Mp */ + { "lgsS", Gv, Mp }, /* 386 lists only Mp */ + { "movzbS", Gv, Eb }, + { "movzwS", Gv, Ew }, + /* b8 */ + { "ud2b" }, + { "(bad)" }, + { GRP8 }, + { "btcS", Ev, Gv }, + { "bsfS", Gv, Ev }, + { "bsrS", Gv, Ev }, + { "movsbS", Gv, Eb }, + { "movswS", Gv, Ew }, + /* c0 */ + { "xaddb", Eb, Gb }, + { "xaddS", Ev, Gv }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { GRP9 }, + /* c8 */ + { "bswap", eAX }, + { "bswap", eCX }, + { "bswap", eDX }, + { "bswap", eBX }, + { "bswap", eSP }, + { "bswap", eBP }, + { "bswap", eSI }, + { "bswap", eDI }, + /* d0 */ + { "(bad)" }, + { "psrlw", MX, EM }, + { "psrld", MX, EM }, + { "psrlq", MX, EM }, + { "(bad)" }, + { "pmullw", MX, EM }, + { "(bad)" }, { "(bad)" }, + /* d8 */ + { "psubusb", MX, EM }, + { "psubusw", MX, EM }, + { "(bad)" }, + { "pand", MX, EM }, + { "paddusb", MX, EM }, + { "paddusw", MX, EM }, + { "(bad)" }, + { "pandn", MX, EM }, + /* e0 */ + { "(bad)" }, + { "psraw", MX, EM }, + { "psrad", MX, EM }, + { "(bad)" }, + { "(bad)" }, + { "pmulhw", MX, EM }, + { "(bad)" }, { "(bad)" }, + /* e8 */ + { "psubsb", MX, EM }, + { "psubsw", MX, EM }, + { "(bad)" }, + { "por", MX, EM }, + { "paddsb", MX, EM }, + { "paddsw", MX, EM }, + { "(bad)" }, + { "pxor", MX, EM }, + /* f0 */ + { "(bad)" }, + { "psllw", MX, EM }, + { "pslld", MX, EM }, + { "psllq", MX, EM }, + { "(bad)" }, + { "pmaddwd", MX, EM }, + { "(bad)" }, { "(bad)" }, + /* f8 */ + { "psubb", MX, EM }, + { "psubw", MX, EM }, + { "psubd", MX, EM }, + { "(bad)" }, + { "paddb", MX, EM }, + { "paddw", MX, EM }, + { "paddd", MX, EM }, + { "(bad)" } +}; + +static const unsigned char onebyte_has_modrm[256] = { + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, + 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 +}; + +static const unsigned char twobyte_has_modrm[256] = { + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1, /* 6f */ + /* 70 */ 0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ + /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ + /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ + /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1, /* df */ + /* e0 */ 0,1,1,0,0,1,0,0,1,1,0,1,1,1,0,1, /* ef */ + /* f0 */ 0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,0 /* ff */ +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *codep; +static disassemble_info *the_info; +static int mod; +static int rm; +static int reg; +static void oappend PARAMS ((char *s)); + +static char *names32[]={ + "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +}; +static char *names16[] = { + "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +}; +static char *names8[] = { + "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +}; +static char *names_seg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +}; +static char *index16[] = { + "bx+si","bx+di","bp+si","bp+di","si","di","bp","bx" +}; + +static struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addb", Eb, Ib }, + { "orb", Eb, Ib }, + { "adcb", Eb, Ib }, + { "sbbb", Eb, Ib }, + { "andb", Eb, Ib }, + { "subb", Eb, Ib }, + { "xorb", Eb, Ib }, + { "cmpb", Eb, Ib } + }, + /* GRP1S */ + { + { "addS", Ev, Iv }, + { "orS", Ev, Iv }, + { "adcS", Ev, Iv }, + { "sbbS", Ev, Iv }, + { "andS", Ev, Iv }, + { "subS", Ev, Iv }, + { "xorS", Ev, Iv }, + { "cmpS", Ev, Iv } + }, + /* GRP1Ss */ + { + { "addS", Ev, sIb }, + { "orS", Ev, sIb }, + { "adcS", Ev, sIb }, + { "sbbS", Ev, sIb }, + { "andS", Ev, sIb }, + { "subS", Ev, sIb }, + { "xorS", Ev, sIb }, + { "cmpS", Ev, sIb } + }, + /* GRP2b */ + { + { "rolb", Eb, Ib }, + { "rorb", Eb, Ib }, + { "rclb", Eb, Ib }, + { "rcrb", Eb, Ib }, + { "shlb", Eb, Ib }, + { "shrb", Eb, Ib }, + { "(bad)" }, + { "sarb", Eb, Ib }, + }, + /* GRP2S */ + { + { "rolS", Ev, Ib }, + { "rorS", Ev, Ib }, + { "rclS", Ev, Ib }, + { "rcrS", Ev, Ib }, + { "shlS", Ev, Ib }, + { "shrS", Ev, Ib }, + { "(bad)" }, + { "sarS", Ev, Ib }, + }, + /* GRP2b_one */ + { + { "rolb", Eb }, + { "rorb", Eb }, + { "rclb", Eb }, + { "rcrb", Eb }, + { "shlb", Eb }, + { "shrb", Eb }, + { "(bad)" }, + { "sarb", Eb }, + }, + /* GRP2S_one */ + { + { "rolS", Ev }, + { "rorS", Ev }, + { "rclS", Ev }, + { "rcrS", Ev }, + { "shlS", Ev }, + { "shrS", Ev }, + { "(bad)" }, + { "sarS", Ev }, + }, + /* GRP2b_cl */ + { + { "rolb", Eb, CL }, + { "rorb", Eb, CL }, + { "rclb", Eb, CL }, + { "rcrb", Eb, CL }, + { "shlb", Eb, CL }, + { "shrb", Eb, CL }, + { "(bad)" }, + { "sarb", Eb, CL }, + }, + /* GRP2S_cl */ + { + { "rolS", Ev, CL }, + { "rorS", Ev, CL }, + { "rclS", Ev, CL }, + { "rcrS", Ev, CL }, + { "shlS", Ev, CL }, + { "shrS", Ev, CL }, + { "(bad)" }, + { "sarS", Ev, CL } + }, + /* GRP3b */ + { + { "testb", Eb, Ib }, + { "(bad)", Eb }, + { "notb", Eb }, + { "negb", Eb }, + { "mulb", AL, Eb }, + { "imulb", AL, Eb }, + { "divb", AL, Eb }, + { "idivb", AL, Eb } + }, + /* GRP3S */ + { + { "testS", Ev, Iv }, + { "(bad)" }, + { "notS", Ev }, + { "negS", Ev }, + { "mulS", eAX, Ev }, + { "imulS", eAX, Ev }, + { "divS", eAX, Ev }, + { "idivS", eAX, Ev }, + }, + /* GRP4 */ + { + { "incb", Eb }, + { "decb", Eb }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* GRP5 */ + { + { "incS", Ev }, + { "decS", Ev }, + { "call", indirEv }, + { "lcall", indirEv }, + { "jmp", indirEv }, + { "ljmp", indirEv }, + { "pushS", Ev }, + { "(bad)" }, + }, + /* GRP6 */ + { + { "sldt", Ew }, + { "str", Ew }, + { "lldt", Ew }, + { "ltr", Ew }, + { "verr", Ew }, + { "verw", Ew }, + { "(bad)" }, + { "(bad)" } + }, + /* GRP7 */ + { + { "sgdt", Ew }, + { "sidt", Ew }, + { "lgdt", Ew }, + { "lidt", Ew }, + { "smsw", Ew }, + { "(bad)" }, + { "lmsw", Ew }, + { "invlpg", Ew }, + }, + /* GRP8 */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "btS", Ev, Ib }, + { "btsS", Ev, Ib }, + { "btrS", Ev, Ib }, + { "btcS", Ev, Ib }, + }, + /* GRP9 */ + { + { "(bad)" }, + { "cmpxchg8b", Ev }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* GRP10 */ + { + { "(bad)" }, + { "(bad)" }, + { "psrlw", MS, Ib }, + { "(bad)" }, + { "psraw", MS, Ib }, + { "(bad)" }, + { "psllw", MS, Ib }, + { "(bad)" }, + }, + /* GRP11 */ + { + { "(bad)" }, + { "(bad)" }, + { "psrld", MS, Ib }, + { "(bad)" }, + { "psrad", MS, Ib }, + { "(bad)" }, + { "pslld", MS, Ib }, + { "(bad)" }, + }, + /* GRP12 */ + { + { "(bad)" }, + { "(bad)" }, + { "psrlq", MS, Ib }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "psllq", MS, Ib }, + { "(bad)" }, + } +}; + +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADR 0x400 +#define PREFIX_FWAIT 0x800 + +static int prefixes; + +static void +ckprefix () +{ + prefixes = 0; + while (1) + { + FETCH_DATA (the_info, codep + 1); + switch (*codep) + { + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADR; + break; + case 0x9b: + prefixes |= PREFIX_FWAIT; + break; + default: + return; + } + codep++; + } +} + +static char op1out[100], op2out[100], op3out[100]; +static int op_address[3], op_ad, op_index[3]; +static int start_pc; + + +/* + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * The function returns the length of this instruction in bytes. + */ + +int print_insn_x86 PARAMS ((bfd_vma pc, disassemble_info *info, int aflag, + int dflag)); +int +print_insn_i386 (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + if (info->mach == bfd_mach_i386_i386) + return print_insn_x86 (pc, info, 1, 1); + else if (info->mach == bfd_mach_i386_i8086) + return print_insn_x86 (pc, info, 0, 0); + else +#if defined(__KERNEL__) + printk("Bad machine type\n"); +#else + abort (); +#endif +} + +int +print_insn_x86 (pc, info, aflag, dflag) + bfd_vma pc; + disassemble_info *info; +{ + struct dis386 *dp; + int i; + int enter_instruction; + char *first, *second, *third; + int needcomma; + unsigned char need_modrm; + + struct dis_private priv; + bfd_byte *inbuf = priv.the_buffer; + + /* The output looks better if we put 5 bytes on a line, since that + puts long word instructions on a single line. */ + info->bytes_per_line = 5; + + info->private_data = (PTR) &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = pc; +#if defined(STANDALONE) + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; +#endif + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + op_index[0] = op_index[1] = op_index[2] = -1; + + the_info = info; + start_pc = pc; + start_codep = inbuf; + codep = inbuf; + + ckprefix (); + + FETCH_DATA (info, codep + 1); + if (*codep == 0xc8) + enter_instruction = 1; + else + enter_instruction = 0; + + obufp = obuf; + + if (prefixes & PREFIX_REPZ) + oappend ("repz "); + if (prefixes & PREFIX_REPNZ) + oappend ("repnz "); + if (prefixes & PREFIX_LOCK) + oappend ("lock "); + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + /* fwait not followed by floating point instruction */ + (*info->fprintf_func) (info->stream, "fwait"); + return (1); + } + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + + if (prefixes & PREFIX_ADR) + { + aflag ^= 1; + if (aflag) + oappend ("addr32 "); + else + oappend ("addr16 "); + } + + if (*codep == 0x0f) + { + FETCH_DATA (info, codep + 2); + dp = &dis386_twobyte[*++codep]; + need_modrm = twobyte_has_modrm[*codep]; + } + else + { + dp = &dis386[*codep]; + need_modrm = onebyte_has_modrm[*codep]; + } + codep++; + + if (need_modrm) + { + FETCH_DATA (info, codep + 1); + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + } + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (aflag, dflag); + } + else + { + if (dp->name == NULL) + dp = &grps[dp->bytemode1][reg]; + + putop (dp->name, aflag, dflag); + + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1)(dp->bytemode1, aflag, dflag); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2)(dp->bytemode2, aflag, dflag); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3)(dp->bytemode3, aflag, dflag); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + (*info->fprintf_func) (info->stream, "%s", obuf); + + /* enter instruction is printed with operands in the + * same order as the intel book; everything else + * is printed in reverse order + */ + if (enter_instruction) + { + first = op1out; + second = op2out; + third = op3out; + op_ad = op_index[0]; + op_index[0] = op_index[2]; + op_index[2] = op_ad; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + if (op_index[0] != -1) + (*info->print_address_func) (op_address[op_index[0]], info); + else + (*info->fprintf_func) (info->stream, "%s", first); + needcomma = 1; + } + if (*second) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[1] != -1) + (*info->print_address_func) (op_address[op_index[1]], info); + else + (*info->fprintf_func) (info->stream, "%s", second); + needcomma = 1; + } + if (*third) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[2] != -1) + (*info->print_address_func) (op_address[op_index[2]], info); + else + (*info->fprintf_func) (info->stream, "%s", third); + } + return (codep - inbuf); +} + +static char *float_mem[] = { + /* d8 */ + "fadds", + "fmuls", + "fcoms", + "fcomps", + "fsubs", + "fsubrs", + "fdivs", + "fdivrs", + /* d9 */ + "flds", + "(bad)", + "fsts", + "fstps", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiaddl", + "fimull", + "ficoml", + "ficompl", + "fisubl", + "fisubrl", + "fidivl", + "fidivrl", + /* db */ + "fildl", + "(bad)", + "fistl", + "fistpl", + "(bad)", + "fldt", + "(bad)", + "fstpt", + /* dc */ + "faddl", + "fmull", + "fcoml", + "fcompl", + "fsubl", + "fsubrl", + "fdivl", + "fdivrl", + /* dd */ + "fldl", + "(bad)", + "fstl", + "fstpl", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fildll", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 + +#define FGRPd9_2 NULL, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1 +#define FGRPd9_5 NULL, NULL, 2 +#define FGRPd9_6 NULL, NULL, 3 +#define FGRPd9_7 NULL, NULL, 4 +#define FGRPda_5 NULL, NULL, 5 +#define FGRPdb_4 NULL, NULL, 6 +#define FGRPde_3 NULL, NULL, 7 +#define FGRPdf_4 NULL, NULL, 8 + +static struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi }, + { "fmul", ST, STi }, + { "fcom", STi }, + { "fcomp", STi }, + { "fsub", ST, STi }, + { "fsubr", ST, STi }, + { "fdiv", ST, STi }, + { "fdivr", ST, STi }, + }, + /* d9 */ + { + { "fld", STi }, + { "fxch", STi }, + { FGRPd9_2 }, + { "(bad)" }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "fcmovb", ST, STi }, + { "fcmove", ST, STi }, + { "fcmovbe",ST, STi }, + { "fcmovu", ST, STi }, + { "(bad)" }, + { FGRPda_5 }, + { "(bad)" }, + { "(bad)" }, + }, + /* db */ + { + { "fcmovnb",ST, STi }, + { "fcmovne",ST, STi }, + { "fcmovnbe",ST, STi }, + { "fcmovnu",ST, STi }, + { FGRPdb_4 }, + { "fucomi", ST, STi }, + { "fcomi", ST, STi }, + { "(bad)" }, + }, + /* dc */ + { + { "fadd", STi, ST }, + { "fmul", STi, ST }, + { "(bad)" }, + { "(bad)" }, + { "fsub", STi, ST }, + { "fsubr", STi, ST }, + { "fdiv", STi, ST }, + { "fdivr", STi, ST }, + }, + /* dd */ + { + { "ffree", STi }, + { "(bad)" }, + { "fst", STi }, + { "fstp", STi }, + { "fucom", STi }, + { "fucomp", STi }, + { "(bad)" }, + { "(bad)" }, + }, + /* de */ + { + { "faddp", STi, ST }, + { "fmulp", STi, ST }, + { "(bad)" }, + { FGRPde_3 }, + { "fsubp", STi, ST }, + { "fsubrp", STi, ST }, + { "fdivp", STi, ST }, + { "fdivrp", STi, ST }, + }, + /* df */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdf_4 }, + { "fucomip",ST, STi }, + { "fcomip", ST, STi }, + { "(bad)" }, + }, +}; + + +static char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + +static void +dofloat (aflag, dflag) + int aflag; + int dflag; +{ + struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + putop (float_mem[(floatop - 0xd8) * 8 + reg], aflag, dflag); + obufp = op1out; + OP_E (v_mode, aflag, dflag); + return; + } + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm], aflag, dflag); + /* instruction fnstsw is only one with strange arg */ + if (floatop == 0xdf + && FETCH_DATA (the_info, codep + 1) + && *codep == 0xe0) + strcpy (op1out, "%eax"); + } + else + { + putop (dp->name, aflag, dflag); + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1, aflag, dflag); + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2, aflag, dflag); + } +} + +/* ARGSUSED */ +static int +OP_ST (ignore, aflag, dflag) + int ignore; + int aflag; + int dflag; +{ + oappend ("%st"); + return (0); +} + +/* ARGSUSED */ +static int +OP_STi (ignore, aflag, dflag) + int ignore; + int aflag; + int dflag; +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf); + return (0); +} + + +/* capital letters in template are macros */ +static void +putop (template, aflag, dflag) + char *template; + int aflag; + int dflag; +{ + char *p; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case 'C': /* For jcxz/jecxz */ + if (aflag) + *obufp++ = 'e'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + break; + case 'S': + /* operand size flag */ + if (dflag) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + break; + case 'W': + /* operand size flag for cwtl, cbtw */ + if (dflag) + *obufp++ = 'w'; + else + *obufp++ = 'b'; + break; + } + } + *obufp = 0; +} + +static void +oappend (s) + char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); + *obufp = 0; +} + +static void +append_prefix () +{ + if (prefixes & PREFIX_CS) + oappend ("%cs:"); + if (prefixes & PREFIX_DS) + oappend ("%ds:"); + if (prefixes & PREFIX_SS) + oappend ("%ss:"); + if (prefixes & PREFIX_ES) + oappend ("%es:"); + if (prefixes & PREFIX_FS) + oappend ("%fs:"); + if (prefixes & PREFIX_GS) + oappend ("%gs:"); +} + +static int +OP_indirE (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + oappend ("*"); + return OP_E (bytemode, aflag, dflag); +} + +static int +OP_E (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int disp; + + /* skip mod/rm byte */ + codep++; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + oappend (names8[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + case v_mode: + if (dflag) + oappend (names32[rm]); + else + oappend (names16[rm]); + break; + default: + oappend (""); + break; + } + return 0; + } + + disp = 0; + append_prefix (); + + if (aflag) /* 32 bit address mode */ + { + int havesib; + int havebase; + int base; + int index=0; + int scale=0; + + havesib = 0; + havebase = 1; + base = rm; + + if (base == 4) + { + havesib = 1; + FETCH_DATA (the_info, codep + 1); + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + codep++; + } + + switch (mod) + { + case 0: + if (base == 5) + { + havebase = 0; + disp = get32 (); + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get32 (); + break; + } + + if (mod != 0 || base == 5) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (havebase || (havesib && (index != 4 || scale != 0))) + { + oappend ("("); + if (havebase) + oappend (names32[base]); + if (havesib) + { + if (index != 4) + { + sprintf (scratchbuf, ",%s", names32[index]); + oappend (scratchbuf); + } + sprintf (scratchbuf, ",%d", 1 << scale); + oappend (scratchbuf); + } + oappend (")"); + } + } + else + { /* 16 bit address mode */ + switch (mod) + { + case 0: + if (rm == 6) + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + break; + } + + if (mod != 0 || rm == 6) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (mod != 0 || rm != 6) + { + oappend ("("); + oappend (index16[rm]); + oappend (")"); + } + } + return 0; +} + +static int +OP_G (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + switch (bytemode) + { + case b_mode: + oappend (names8[reg]); + break; + case w_mode: + oappend (names16[reg]); + break; + case d_mode: + oappend (names32[reg]); + break; + case v_mode: + if (dflag) + oappend (names32[reg]); + else + oappend (names16[reg]); + break; + default: + oappend (""); + break; + } + return (0); +} + +static int +get32 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + x |= (*codep++ & 0xff) << 16; + x |= (*codep++ & 0xff) << 24; + return (x); +} + +static int +get16 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 2); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return (x); +} + +static void +set_op (op) + int op; +{ + op_index[op_ad] = op_ad; + op_address[op_ad] = op; +} + +static int +OP_REG (code, aflag, dflag) + int code; + int aflag; + int dflag; +{ + char *s; + + switch (code) + { + case indir_dx_reg: s = "(%dx)"; break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + if (dflag) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + break; + default: + s = ""; + break; + } + oappend (s); + return (0); +} + +static int +OP_I (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++ & 0xff; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = get16 (); + break; + case w_mode: + op = get16 (); + break; + default: + oappend (""); + return (0); + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + return (0); +} + +static int +OP_sI (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + if ((op & 0x80) != 0) + op -= 0x100; + break; + case v_mode: + if (dflag) + op = get32 (); + else + { + op = get16(); + if ((op & 0x8000) != 0) + op -= 0x10000; + } + break; + case w_mode: + op = get16 (); + if ((op & 0x8000) != 0) + op -= 0x10000; + break; + default: + oappend (""); + return (0); + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + return (0); +} + +static int +OP_J (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int disp; + int mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case v_mode: + if (dflag) + disp = get32 (); + else + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + /* for some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + break; + default: + oappend (""); + return (0); + } + disp = (start_pc + codep - start_codep + disp) & mask; + set_op (disp); + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +static int +OP_SEG (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + static char *sreg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", + }; + + oappend (sreg[reg]); + return (0); +} + +static int +OP_DIR (size, aflag, dflag) + int size; + int aflag; + int dflag; +{ + int seg, offset; + + switch (size) + { + case lptr: + if (aflag) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + oappend (scratchbuf); + break; + case v_mode: + if (aflag) + offset = get32 (); + else + { + offset = get16 (); + if ((offset & 0x8000) != 0) + offset -= 0x10000; + } + + offset = start_pc + codep - start_codep + offset; + set_op (offset); + sprintf (scratchbuf, "0x%x", offset); + oappend (scratchbuf); + break; + default: + oappend (""); + break; + } + return (0); +} + +/* ARGSUSED */ +static int +OP_OFF (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + int off; + + append_prefix (); + + if (aflag) + off = get32 (); + else + off = get16 (); + + sprintf (scratchbuf, "0x%x", off); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +static int +OP_ESDI (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + oappend ("%es:("); + oappend (aflag ? "%edi" : "%di"); + oappend (")"); + return (0); +} + +/* ARGSUSED */ +static int +OP_DSSI (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + oappend ("%ds:("); + oappend (aflag ? "%esi" : "%si"); + oappend (")"); + return (0); +} + +#if 0 +/* Not used. */ + +/* ARGSUSED */ +static int +OP_ONE (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + oappend ("1"); + return (0); +} + +#endif + +/* ARGSUSED */ +static int +OP_C (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%cr%d", reg); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +static int +OP_D (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%db%d", reg); + oappend (scratchbuf); + return (0); +} + +/* ARGSUSED */ +static int +OP_T (dummy, aflag, dflag) + int dummy; + int aflag; + int dflag; +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf); + return (0); +} + +static int +OP_rm (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + switch (bytemode) + { + case d_mode: + oappend (names32[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + } + return (0); +} + +static int +OP_MMX (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + sprintf (scratchbuf, "%%mm%d", reg); + oappend (scratchbuf); + return 0; +} + +static int +OP_EM (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + if (mod != 3) + return OP_E (bytemode, aflag, dflag); + + codep++; + sprintf (scratchbuf, "%%mm%d", rm); + oappend (scratchbuf); + return 0; +} + +static int +OP_MS (bytemode, aflag, dflag) + int bytemode; + int aflag; + int dflag; +{ + ++codep; + sprintf (scratchbuf, "%%mm%d", rm); + oappend (scratchbuf); + return 0; +} diff -urN 2.3.29pre1/arch/i386/kdb/kd_id.c 2.3.29pre1-ikd/arch/i386/kdb/kd_id.c --- 2.3.29pre1/arch/i386/kdb/kd_id.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/kd_id.c Mon Nov 22 16:56:22 1999 @@ -0,0 +1,273 @@ +/* + * Kernel Debugger. + * + * This module parses the instruction disassembly (id) command + * and invokes the disassembler. + * + * Copyright 1999, Silicon Graphics, Inc. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + */ + +#if defined(STANDALONE) +#include +#include +#include +#include +#include "kdb.h" +#include "sakdbsupport.h" +#include "dis-asm.h" +#else +#include +#include +#include +#include +#include +#include "dis-asm.h" +#include "kdbsupport.h" +#endif + +static disassemble_info kdb_di; + +/* ARGSUSED */ +static int +kdbgetsym(bfd_vma addr, struct disassemble_info *dip) +{ + + return 0; +} + +/* ARGSUSED */ +static void +kdbprintintaddr(bfd_vma addr, struct disassemble_info *dip, int flag) +{ + char *sym = kdbnearsym(addr); + int offset = 0; + + if (sym) { + offset = addr - kdbgetsymval(sym); + } + + /* + * Print a symbol name or address as necessary. + */ + if (sym) { + if (offset) + dip->fprintf_func(dip->stream, "%s+0x%x", sym, offset); + else + dip->fprintf_func(dip->stream, "%s", sym); + } else { + dip->fprintf_func(dip->stream, "0x%x", addr); + } + + if (flag) + dip->fprintf_func(dip->stream, ": "); +} + +static void +kdbprintaddr(bfd_vma addr, struct disassemble_info *dip) +{ + kdbprintintaddr(addr, dip, 0); +} + +/* ARGSUSED */ +static int +kdbgetidmem(bfd_vma addr, bfd_byte *buf, int length, struct disassemble_info *dip) +{ + bfd_byte *bp = buf; + int i; + + /* + * Fill the provided buffer with bytes from + * memory, starting at address 'addr' for 'length bytes. + * + */ + + for(i=0; i + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + */ + +int +kdb_id(int argc, const char **argv, const char **envp, struct pt_regs* regs) +{ + unsigned long pc; + int icount; + int diag; + int i; + char * mode; + int nextarg; + long offset = 0; + static unsigned long lastpc=0; + + if (argc != 1) + if (lastpc == 0) + return KDB_ARGCOUNT; + else { + char lastbuf[50]; + sprintf(lastbuf, "0x%lx", lastpc); + argv[1] = lastbuf; + argc = 1; + } + + + /* + * Fetch PC. First, check to see if it is a symbol, if not, + * try address. + */ + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &pc, &offset, NULL, regs); + if (diag) + return diag; + + /* + * Number of lines to display + */ + diag = kdbgetintenv("IDCOUNT", &icount); + if (diag) + return diag; + + mode = kdbgetenv("IDMODE"); + if (mode) { + if (strcmp(mode, "x86") == 0) { + kdb_di.mach = bfd_mach_i386_i386; + } else if (strcmp(mode, "8086") == 0) { + kdb_di.mach = bfd_mach_i386_i8086; + } else { + return KDB_BADMODE; + } + } + + for(i=0; i +#include +#include +#include +#include +#if defined(__SMP__) +#include +#endif +#include +#include +#include "kdbsupport.h" + +int kdb_active = 0; +int kdb_flags = 0; +int kdb_nextline = 1; +int kdb_new_cpu = -1; + +kdb_jmp_buf kdbjmpbuf; + + /* + * Describe the command table. + */ +typedef struct _kdbtab { + char *cmd_name; /* Command name */ + kdb_func cmd_func; /* Function to execute command */ + char *cmd_usage; /* Usage String for this command */ + char *cmd_help; /* Help message for this command */ + short cmd_flags; /* Parsing flags */ + short cmd_minlen; /* Minimum legal # command chars required */ +} kdbtab_t; + + /* + * Provide space for KDB_MAX_COMMANDS commands. + */ +#define KDB_MAX_COMMANDS 100 + +static kdbtab_t kdb_commands[KDB_MAX_COMMANDS]; + + /* + * Error messages. XXX - use a macro for this... + */ +static char kdb_notfound[] = "Command Not Found"; +static char kdb_argcount[] = "Improper argument count, see usage."; +static char kdb_badwidth[] = "Illegal value for BYTESPERWORD use 1, 2 or 4"; +static char kdb_badradix[] = "Illegal value for RADIX use 8, 10 or 16"; +static char kdb_notenv[] = "Cannot find environment variable"; +static char kdb_noenvvalue[] = "Environment variable should have value"; +static char kdb_notimp[] = "Command not implemented"; +static char kdb_envfull[] = "Environment full"; +static char kdb_envbuffull[] = "Environment buffer full"; +static char kdb_toomanybpt[] = "Too many breakpoints defined"; +static char kdb_toomanydbregs[] = "More breakpoints than db registers defined"; +static char kdb_dupbpt[] = "Duplicate breakpoint address"; +static char kdb_bptnotfound[] = "Breakpoint not found"; +static char kdb_badmode[] = "IDMODE should be x86 or 8086"; +static char kdb_badint[] = "Illegal numeric value"; +static char kdb_invaddrfmt[] = "Invalid symbolic address format"; +static char kdb_badreg[] = "Invalid register name"; +static char kdb_badcpunum[] = "Invalid cpu number"; +static char kdb_badlength[] = "Invalid length field"; +static char kdb_nobp[] = "No Breakpoint exists"; + +static char *kdb_messages[] = { + (char *)0, + kdb_notfound, + (char *)0, + kdb_argcount, + kdb_badwidth, + kdb_badradix, + kdb_notenv, + kdb_noenvvalue, + kdb_notimp, + kdb_envfull, + kdb_envbuffull, + kdb_toomanybpt, + kdb_toomanydbregs, + kdb_dupbpt, + kdb_bptnotfound, + kdb_badmode, + kdb_badint, + kdb_invaddrfmt, + kdb_badreg, + (char *)0, /* KDB_CPUSWITCH */ + kdb_badcpunum, + kdb_badlength, + kdb_nobp, + (char *)0 +}; +static const int __nkdb_err = sizeof(kdb_messages) / sizeof(char *); + + +/* + * Initial environment. This is all kept static and local to + * this file. We don't want to rely on the memory allocation + * mechanisms in the kernel, so we use a very limited allocate-only + * heap for new and altered environment variables. The entire + * environment is limited to a fixed number of entries (add more + * to __env[] if required) and a fixed amount of heap (add more to + * KDB_ENVBUFSIZE if required). + */ + +#if defined(CONFIG_SMP) +static char prompt_str[] = "PROMPT=[%d]kdb> "; +static char more_str[] = "MOREPROMPT=[%d]more> "; +#else +static char prompt_str[] = "PROMPT=kdb> "; +static char more_str[] = "MOREPROMPT=more> "; +#endif +static char radix_str[] = "RADIX=16"; +static char lines_str[] = "LINES=24"; +static char columns_str[] = "COLUMNS=80"; +static char mdcount_str[] = "MDCOUNT=8"; /* lines of md output */ +static char idcount_str[] = "IDCOUNT=16"; /* lines of id output */ +static char bperword_str[] = "BYTESPERWORD=4"; /* Word size for md output */ +static char idmode_str[] = "IDMODE=x86"; /* 32-bit mode */ +static char btargs_str[] = "BTARGS=5"; /* 5 possible args in bt */ +static char sscount_str[] = "SSCOUNT=20"; /* lines of ssb output */ + +static char *__env[] = { + bperword_str, + columns_str, + idcount_str, + lines_str, + mdcount_str, + prompt_str, + radix_str, + idmode_str, + btargs_str, + sscount_str, + more_str, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0 +}; +static const int __nenv = (sizeof(__env) / sizeof(char *)); + +/* + * kdbgetenv + * + * This function will return the character string value of + * an environment variable. + * + * Parameters: + * match A character string representing an environment variable. + * Outputs: + * None. + * Returns: + * NULL No environment variable matches 'match' + * char* Pointer to string value of environment variable. + * Locking: + * No locking considerations required. + * Remarks: + */ +char * +kdbgetenv(const char *match) +{ + char **ep = __env; + int matchlen = strlen(match); + int i; + + for(i=0; i<__nenv; i++) { + char *e = *ep++; + + if (!e) continue; + + if ((strncmp(match, e, matchlen) == 0) + && ((e[matchlen] == '\0') + ||(e[matchlen] == '='))) { + char *cp = strchr(e, '='); + return (cp)?++cp:""; + } + } + return (char *)0; +} + +/* + * kdballocenv + * + * This function is used to allocate bytes for environment entries. + * + * Parameters: + * match A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of the env variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. Must be called with all + * processors halted. + * Remarks: + * We use a static environment buffer (envbuffer) to hold the values + * of dynamically generated environment variables (see kdb_set). Buffer + * space once allocated is never free'd, so over time, the amount of space + * (currently 512 bytes) will be exhausted if env variables are changed + * frequently. + */ +static char * +kdballocenv(size_t bytes) +{ +#define KDB_ENVBUFSIZE 512 + static char envbuffer[KDB_ENVBUFSIZE]; + static int envbufsize = 0; + char *ep = (char *)0; + + if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) { + ep = &envbuffer[envbufsize]; + envbufsize += bytes; + } + return ep; +} + +/* + * kdbgetulenv + * + * This function will return the value of an unsigned long-valued + * environment variable. + * + * Parameters: + * match A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of the env variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetulenv(const char *match, unsigned long *value) +{ + char *ep; + + ep = kdbgetenv(match); + if (!ep) return KDB_NOTENV; + if (strlen(ep) == 0) return KDB_NOENVVALUE; + + *value = simple_strtoul(ep, 0, 0); + + return 0; +} + +/* + * kdbgetintenv + * + * This function will return the value of an integer-valued + * environment variable. + * + * Parameters: + * match A character string representing an integer-valued env variable + * Outputs: + * *value the integer representation of the environment variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetintenv(const char *match, int *value) { + unsigned long val; + int diag; + + diag = kdbgetulenv(match, &val); + if (!diag) { + *value = (int) val; + } + return diag; +} + +/* + * kdbgetularg + * + * This function will convert a numeric string + * into an unsigned long value. + * + * Parameters: + * arg A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of arg. + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetularg(const char *arg, unsigned long *value) +{ + char *endp; + unsigned long val; + + val = simple_strtoul(arg, &endp, 0); + + if (endp == arg) { + /* + * Try base 16, for us folks too lazy to type the + * leading 0x... + */ + val = simple_strtoul(arg, &endp, 16); + if (endp == arg) + return KDB_BADINT; + } + + *value = val; + + return 0; +} + +/* + * kdbgetaddrarg + * + * This function is responsible for parsing an + * address-expression and returning the value of + * the expression, symbol name, and offset to the caller. + * + * The argument may consist of a numeric value (decimal or + * hexidecimal), a symbol name, a register name (preceeded + * by the percent sign), an environment variable with a numeric + * value (preceeded by a dollar sign) or a simple arithmetic + * expression consisting of a symbol name, +/-, and a numeric + * constant value (offset). + * + * Parameters: + * argc - count of arguments in argv + * argv - argument vector + * *nextarg - index to next unparsed argument in argv[] + * + * Outputs: + * *value - receives the value of the address-expression + * *offset - receives the offset specified, if any + * *name - receives the symbol name, if any + * *nextarg - index to next unparsed argument in argv[] + * + * Returns: + * zero is returned on success, a kdb diagnostic code is + * returned on error. + * + * Locking: + * No locking requirements. + * + * Remarks: + * + */ + +int +kdbgetaddrarg(int argc, const char **argv, int *nextarg, + unsigned long *value, long *offset, + char **name, struct pt_regs *regs) +{ + unsigned long addr; + long off = 0; + int positive; + int diag; + char *symname; + char symbol = '\0'; + char *cp; + + /* + * Process arguments which follow the following syntax: + * + * symbol | numeric-address [+/- numeric-offset] + * %register + * $environment-variable + */ + + if (*nextarg > argc) { + return KDB_ARGCOUNT; + } + + symname = (char *)argv[*nextarg]; + + /* + * If there is no whitespace between the symbol + * or address and the '+' or '-' symbols, we + * remember the character and replace it with a + * null so the symbol/value can be properly parsed + */ + if ((cp = strpbrk(symname, "+-")) != NULL) { + symbol = *cp; + *cp++ = '\0'; + } + + if (symname[0] == '$') { + diag = kdbgetulenv(&symname[1], &addr); + if (diag) + return diag; + } else if (symname[0] == '%') { + diag = kdbgetregcontents(&symname[1], regs, &addr); + if (diag) + return diag; + } else { + addr = kdbgetsymval(symname); + if (addr == 0) { + diag = kdbgetularg(argv[*nextarg], &addr); + if (diag) + return diag; + } + } + + symname = kdbnearsym(addr); + + (*nextarg)++; + + if (name) + *name = symname; + if (value) + *value = addr; + if (offset && name && *name) + *offset = addr - kdbgetsymval(*name); + + if ((*nextarg > argc) + && (symbol == '\0')) + return 0; + + /* + * check for +/- and offset + */ + + if (symbol == '\0') { + if ((argv[*nextarg][0] != '+') + && (argv[*nextarg][0] != '-')) { + /* + * Not our argument. Return. + */ + return 0; + } else { + positive = (argv[*nextarg][0] == '+'); + (*nextarg)++; + } + } else + positive = (symbol == '+'); + + /* + * Now there must be an offset! + */ + if ((*nextarg > argc) + && (symbol == '\0')) { + return KDB_INVADDRFMT; + } + + if (!symbol) { + cp = (char *)argv[*nextarg]; + (*nextarg)++; + } + + diag = kdbgetularg(cp, &off); + if (diag) + return diag; + + if (!positive) + off = -off; + + if (offset) + *offset += off; + + if (value) + *value += off; + + return 0; +} + +static void +kdb_cmderror(int diag) +{ + if (diag >= 0) { + kdb_printf("no error detected\n"); + return; + } + diag = -diag; + if (diag >= __nkdb_err) { + kdb_printf("Illegal diag %d\n", -diag); + return; + } + kdb_printf("diag: %d: %s\n", diag, kdb_messages[diag]); +} + +/* + * kdb_parse + * + * Parse the command line, search the command table for a + * matching command and invoke the command function. + * + * Parameters: + * cmdstr The input command line to be parsed. + * regs The registers at the time kdb was entered. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + * Limited to 20 tokens. + * + * Real rudimentary tokenization. Basically only whitespace + * is considered a token delimeter (but special consideration + * is taken of the '=' sign as used by the 'set' command). + * + * The algorithm used to tokenize the input string relies on + * there being at least one whitespace (or otherwise useless) + * character between tokens as the character immediately following + * the token is altered in-place to a null-byte to terminate the + * token string. + */ + +#define MAXARGC 20 + +static int +kdb_parse(char *cmdstr, struct pt_regs *regs) +{ + char *argv[MAXARGC]; + int argc=0; + char *cp; + kdbtab_t *tp; + int i; + + /* + * First tokenize the command string. + */ + cp = cmdstr; + + /* + * If a null statement is provided, do nothing. + */ + if ((*cp == '\n') || (*cp == '\0')) + return 0; + + while (*cp) { + /* skip whitespace */ + while (isspace(*cp)) cp++; + if ((*cp == '\0') || (*cp == '\n')) + break; + argv[argc++] = cp; + /* Skip to next whitespace */ + for(; *cp && (!isspace(*cp) && (*cp != '=')); cp++); + *cp++ = '\0'; /* Squash a ws or '=' character */ + } + + for(tp=kdb_commands, i=0; i < KDB_MAX_COMMANDS; i++,tp++) { + if (tp->cmd_name) { + /* + * If this command is allowed to be abbreviated, + * check to see if this is it. + */ + + if (tp->cmd_minlen + && (strlen(argv[0]) <= tp->cmd_minlen)) { + if (strncmp(argv[0], + tp->cmd_name, + tp->cmd_minlen) == 0) { + break; + } + } + + if (strcmp(argv[0], tp->cmd_name)==0) { + break; + } + } + } + + if (i < KDB_MAX_COMMANDS) { + return (*tp->cmd_func)(argc-1, + (const char**)argv, + (const char**)__env, + regs); + } + + /* + * If the input with which we were presented does not + * map to an existing command, attempt to parse it as an + * address argument and display the result. Useful for + * obtaining the address of a variable, or the nearest symbol + * to an address contained in a register. + */ + { + unsigned long value; + char *name = NULL; + long offset; + int nextarg = 0; + + if (kdbgetaddrarg(0, (const char **)argv, &nextarg, + &value, &offset, &name, regs)) { + return KDB_NOTFOUND; + } + + kdb_printf("%s = 0x%8.8x ", argv[0], value); + if (name) { + kdb_printf("(%s+0x%lx)", name, offset); + } + kdb_printf("\n"); + return 0; + } +} + +/* + * kdb + * + * This function is the entry point for the kernel debugger. It + * provides a command parser and associated support functions to + * allow examination and control of an active kernel. + * + * This function may be invoked directly from any + * point in the kernel by calling with reason == KDB_REASON_ENTER + * (XXX - note that the regs aren't set up this way - could + * use a software interrupt to enter kdb to get regs...) + * + * The breakpoint trap code should invoke this function with + * one of KDB_REASON_BREAK (int 03) or KDB_REASON_DEBUG (debug register) + * + * the panic function should invoke this function with + * KDB_REASON_PANIC. + * + * The kernel fault handler should invoke this function with + * reason == KDB_REASON_FAULT and error == trap vector #. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * regs The registers at time of fault/breakpoint + * Outputs: + * none + * Locking: + * none + * Remarks: + * No assumptions of system state. This function may be invoked + * with arbitrary locks held. It will stop all other processors + * in an SMP environment, disable all interrupts and does not use + * the operating systems keyboard driver. + */ + +int +kdb(int reason, int error, struct pt_regs *regs) +{ + char cmdbuf[255]; + char *cmd; + int diag; + unsigned long flags; + struct pt_regs func_regs; + + kdb_new_cpu = -1; + kdb_active = reason; + + /* + * Remove the breakpoints to prevent double-faults + * if kdb happens to use a function where a breakpoint + * has been enabled. + */ + + kdb_bp_remove(); + + if (reason != KDB_REASON_DEBUG) { + kdb_printf("Entering kdb "); +#if defined(__SMP__) + kdb_printf("on processor %d ", smp_processor_id()); +#endif + } + + switch (reason) { + case KDB_REASON_DEBUG: + /* + * If re-entering kdb after a single step + * command, don't print the message. + */ + diag = kdb_db_trap(regs); + if (diag == 0) { + kdb_printf("Entering kdb "); +#if defined(__SMP__) + kdb_printf("on processor %d ", smp_processor_id()); +#endif + } else if (diag == 2) { + /* + * in middle of ssb command. Just return. + */ + goto out; + } + break; + case KDB_REASON_FAULT: + break; + case KDB_REASON_INT: + kdb_printf("due to KDB_ENTER() call\n"); + break; + case KDB_REASON_KEYBOARD: + kdb_printf("due to Keyboard Entry\n"); + break; + case KDB_REASON_SWITCH: + kdb_printf("due to cpu switch\n"); + break; + case KDB_REASON_ENTER: + kdb_printf("due to function call\n"); + regs = &func_regs; + regs->xcs = 0; +#if defined(CONFIG_KDB_FRAMEPTR) + asm volatile("movl %%ebp,%0":"=m" (*(int *)®s->ebp)); +#endif + asm volatile("movl %%esp,%0":"=m" (*(int *)®s->esp)); + regs->eip = (long) &kdb; /* for traceback. */ + break; + case KDB_REASON_PANIC: + kdb_printf("due to panic @ 0x%8.8x\n", regs->eip); + kdbdumpregs(regs, NULL, NULL); + break; + case KDB_REASON_BREAK: + kdb_printf("due to Breakpoint @ 0x%8.8x\n", regs->eip); + break; + case 0: + kdb_printf("due spurious\n"); + goto out; + default: + break; + } + +#if defined(__SMP__) + /* + * If SMP, stop other processors + */ + if (smp_num_cpus > 1) { + /* + * Stop all other processors + */ + smp_kdb_stop(1); + } +#endif /* __SMP__ */ + + /* + * Disable interrupts during kdb command processing + */ + __save_flags(flags); + __cli(); + + while (1) { + /* + * Initialize pager context. + */ + kdb_nextline = 1; + + /* + * Use kdb_setjmp/kdb_longjmp to break out of + * the pager early. + */ + if (kdb_setjmp(&kdbjmpbuf)) { + /* + * Command aborted (usually in pager) + */ + + /* + * XXX - need to abort a SSB ? + */ + continue; + } + + /* + * Fetch command from keyboard + */ + cmd = kbd_getstr(cmdbuf, sizeof(cmdbuf), kdbgetenv("PROMPT")); + + diag = kdb_parse(cmd, regs); + if (diag == KDB_NOTFOUND) { + kdb_printf("Unknown kdb command: '%s'\n", cmd); + diag = 0; + } + if ((diag == KDB_GO) + || (diag == KDB_CPUSWITCH)) + break; /* Go or cpu switch command */ + + if (diag) + kdb_cmderror(diag); + } + + /* + * Set up debug registers. + */ + kdb_bp_install(); + +#if defined(__SMP__) + if ((diag == KDB_CPUSWITCH) + && (kdb_new_cpu != -1)) { + /* + * Leaving the other CPU's at the barrier, except the + * one we are switching to, we'll send ourselves a + * kdb IPI before allowing interrupts so it will get + * caught ASAP and get this CPU back waiting at the barrier. + */ + + smp_kdb_stop(0); /* Stop ourself */ + + /* + * let the new cpu go. + */ + clear_bit(kdb_new_cpu, &smp_kdb_wait); + } else { + /* + * Let the other processors continue. + */ + smp_kdb_wait = 0; + } +#endif + + kdb_flags &= ~(KDB_FLAG_SUPRESS|KDB_FLAG_FAULT); + + __restore_flags(flags); + + out: + kdb_active = 0; + return 0; +} + +/* + * kdb_md + * + * This function implements the 'md' and 'mds' commands. + * + * md|mds [ [ []]] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_md(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + char fmtchar; + char fmtstr[64]; + int radix, count, width; + unsigned long addr; + unsigned long word; + long offset = 0; + int diag; + int nextarg; + static unsigned long lastaddr = 0; + static unsigned long lastcount = 0; + static unsigned long lastradix = 0; + char lastbuf[50]; + int symbolic = 0; + + /* + * Defaults in case the relevent environment variables are unset + */ + radix = 16; + count = 8; + width = 4; + + if (argc == 0) { + if (lastaddr == 0) + return KDB_ARGCOUNT; + sprintf(lastbuf, "0x%lx", lastaddr); + argv[1] = lastbuf; + argc = 1; + count = lastcount; + radix = lastradix; + } else { + unsigned long val; + + if (argc >= 2) { + + diag = kdbgetularg(argv[2], &val); + if (!diag) + count = (int) val; + } else { + diag = kdbgetintenv("MDCOUNT", &count); + } + + if (argc >= 3) { + diag = kdbgetularg(argv[3], &val); + if (!diag) + radix = (int) val; + } else { + diag = kdbgetintenv("RADIX",&radix); + } + } + + switch (radix) { + case 10: + fmtchar = 'd'; + break; + case 16: + fmtchar = 'x'; + break; + case 8: + fmtchar = 'o'; + break; + default: + return KDB_BADRADIX; + } + + diag = kdbgetintenv("BYTESPERWORD", &width); + + if (strcmp(argv[0], "mds") == 0) { + symbolic = 1; + width = 4; + } + + switch (width) { + case 4: + sprintf(fmtstr, "%%8.8%c ", fmtchar); + break; + case 2: + sprintf(fmtstr, "%%4.4%c ", fmtchar); + break; + case 1: + sprintf(fmtstr, "%%2.2%c ", fmtchar); + break; + default: + return KDB_BADWIDTH; + } + + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + /* Round address down modulo BYTESPERWORD */ + + addr &= ~(width-1); + + /* + * Remember count and radix for next 'md' + */ + lastcount = count; + lastradix = radix; + + while (count--) { + int num = (symbolic?1 :(16 / width)); + char cbuf[32]; + char *c = cbuf; + char t; + int i; + + for(i=0; i argc) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &contents, NULL, NULL, regs); + if (diag) + return diag; + + if (nextarg != argc + 1) + return KDB_ARGCOUNT; + + /* + * To prevent modification of invalid addresses, check first. + */ + word = kdbgetword(addr, sizeof(word)); + if (kdb_flags & KDB_FLAG_SUPRESS) { + kdb_flags &= ~KDB_FLAG_SUPRESS; + return 0; + } + + *(unsigned long *)(addr) = contents; + + kdb_printf("0x%x = 0x%x\n", addr, contents); + + return 0; +} + +/* + * kdb_go + * + * This function implements the 'go' command. + * + * go [address-expression] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_go(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long addr; + int diag; + int nextarg; + long offset; + + if (argc == 1) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + regs->eip = addr; + } else if (argc) + return KDB_ARGCOUNT; + + return KDB_GO; +} + +/* + * kdb_rd + * + * This function implements the 'rd' command. + * + * rd display all general registers. + * rd c display all control registers. + * rd d display all debug registers. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_rd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + /* + */ + + if (argc == 0) { + return kdbdumpregs(regs, NULL, NULL); + } + + if (argc > 2) { + return KDB_ARGCOUNT; + } + + return kdbdumpregs(regs, argv[1], argv[2]); +} + +/* + * kdb_rm + * + * This function implements the 'rm' (register modify) command. + * + * rm register-name new-contents + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Currently doesn't allow modification of control or + * debug registers, nor does it allow modification + * of model-specific registers (MSR). + */ + +int +kdb_rm(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int ind = 0; + unsigned long contents; + + if (argc != 2) { + return KDB_ARGCOUNT; + } + + /* + * Allow presence or absence of leading '%' symbol. + */ + + if (argv[1][0] == '%') + ind = 1; + + diag = kdbgetularg(argv[2], &contents); + if (diag) + return diag; + + diag = kdbsetregcontents(&argv[1][ind], regs, contents); + if (diag) + return diag; + + return 0; +} + +/* + * kdb_ef + * + * This function implements the 'ef' (display exception frame) + * command. This command takes an address and expects to find + * an exception frame at that address, formats and prints it. + * + * ef address-expression + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Not done yet. + */ + +int +kdb_ef(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + + return KDB_NOTIMP; +} + +/* + * kdb_reboot + * + * This function implements the 'reboot' command. Reboot the system + * immediately. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Shouldn't return from this function. + */ + +int +kdb_reboot(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + machine_restart(0); + /* NOTREACHED */ + return 0; +} + +/* + * kdb_env + * + * This function implements the 'env' command. Display the current + * environment variables. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_env(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + + for(i=0; i<__nenv; i++) { + if (__env[i]) { + kdb_printf("%s\n", __env[i]); + } + } + + return 0; +} + +/* + * kdb_set + * + * This function implements the 'set' command. Alter an existing + * environment variable or create a new one. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_set(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + char *ep; + size_t varlen, vallen; + + /* + * we can be invoked two ways: + * set var=value argv[1]="var", argv[2]="value" + * set var = value argv[1]="var", argv[2]="=", argv[3]="value" + * - if the latter, shift 'em down. + */ + if (argc == 3) { + argv[2] = argv[3]; + argc--; + } + + if (argc != 2) + return KDB_ARGCOUNT; + + /* + * Tokenizer squashed the '=' sign. argv[1] is variable + * name, argv[2] = value. + */ + varlen = strlen(argv[1]); + vallen = strlen(argv[2]); + ep = kdballocenv(varlen + vallen + 2); + if (ep == (char *)0) + return KDB_ENVBUFFULL; + + sprintf(ep, "%s=%s", argv[1], argv[2]); + + ep[varlen+vallen+1]='\0'; + + for(i=0; i<__nenv; i++) { + if (__env[i] + && ((strncmp(__env[i], argv[1], varlen)==0) + && ((__env[i][varlen] == '\0') + || (__env[i][varlen] == '=')))) { + __env[i] = ep; + return 0; + } + } + + /* + * Wasn't existing variable. Fit into slot. + */ + for(i=0; i<__nenv-1; i++) { + if (__env[i] == (char *)0) { + __env[i] = ep; + return 0; + } + } + + return KDB_ENVFULL; +} + +#if defined(__SMP__) +/* + * kdb_cpu + * + * This function implements the 'cpu' command. + * + * cpu [] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_cpu(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long cpunum; + int diag; + + if (argc == 0) { + int i; + + kdb_printf("Currently on cpu %d\n", smp_processor_id()); + kdb_printf("Available cpus: "); + for (i=0; i NR_CPUS) + || !test_bit(cpunum, &cpu_online_map)) + return KDB_BADCPUNUM; + + kdb_new_cpu = cpunum; + + /* + * Switch to other cpu + */ + return KDB_CPUSWITCH; +} +#endif /* __SMP__ */ + +/* + * kdb_ps + * + * This function implements the 'ps' command which shows + * a list of the active processes. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_ps(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct task_struct *p; + + kdb_printf("Task Addr Pid Parent cpu lcpu Thread Command\n"); + for_each_task(p) { + kdb_printf("0x%8.8x %10.10d %10.10d %4.4d %4.4d 0x%8.8x %s\n", + p, p->pid, p->p_pptr->pid, p->processor, + p->last_processor, + &p->thread, + p->comm); + } + + return 0; +} + +/* + * kdb_ll + * + * This function implements the 'll' command which follows a linked + * list and executes an arbitrary command for each element. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_ll(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + unsigned long addr; + long offset = 0; + unsigned long va; + unsigned long linkoffset; + int nextarg; + + if (argc != 3) { + return KDB_ARGCOUNT; + } + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + diag = kdbgetularg(argv[2], &linkoffset); + if (diag) + return diag; + + /* + * Using the starting address as + * the first element in the list, and assuming that + * the list ends with a null pointer. + */ + + va = addr; + + while (va) { + char buf[80]; + + sprintf(buf, "%s 0x%lx\n", argv[3], va); + diag = kdb_parse(buf, regs); + if (diag) + return diag; + + addr = va + linkoffset; + va = kdbgetword(addr, sizeof(va)); + if (kdb_flags & KDB_FLAG_SUPRESS) { + kdb_flags &= ~KDB_FLAG_SUPRESS; + return 0; + } + } + + return 0; +} + +/* + * kdb_help + * + * This function implements the 'help' and '?' commands. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_help(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdbtab_t *kt; + + kdb_printf("%-15.15s %-20.20s %s\n", "Command", "Usage", "Description"); + kdb_printf("----------------------------------------------------------\n"); + for(kt=kdb_commands; kt->cmd_name; kt++) { + kdb_printf("%-15.15s %-20.20s %s\n", kt->cmd_name, + kt->cmd_usage, kt->cmd_help); + } + return 0; +} + +/* + * kdb_register + * + * This function is used to register a kernel debugger command. + * + * Inputs: + * cmd Command name + * func Function to execute the command + * usage A simple usage string showing arguments + * help A simple help string describing command + * Outputs: + * None. + * Returns: + * zero for success, one if a duplicate command. + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_register(char *cmd, + kdb_func func, + char *usage, + char *help, + short minlen) +{ + int i; + kdbtab_t *kp; + + /* + * Brute force method to determine duplicates + */ + for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { + kdb_printf("Duplicate kdb command registered: '%s'\n", + cmd); + return 1; + } + } + + /* + * Insert command into first available location in table + */ + for (i=0, kp=kdb_commands; icmd_name == NULL) { + kp->cmd_name = cmd; + kp->cmd_func = func; + kp->cmd_usage = usage; + kp->cmd_help = help; + kp->cmd_flags = 0; + kp->cmd_minlen = minlen; + break; + } + } + return 0; +} + +/* + * kdb_unregister + * + * This function is used to unregister a kernel debugger command. + * It is generally called when a module which implements kdb + * commands is unloaded. + * + * Inputs: + * cmd Command name + * Outputs: + * None. + * Returns: + * zero for success, one command not registered. + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_unregister(char *cmd) +{ + int i; + kdbtab_t *kp; + + /* + * find the command. + */ + for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { + kp->cmd_name = NULL; + return 0; + } + } + + /* + * Couldn't find it. + */ + return 1; +} + +/* + * kdb_inittab + * + * This function is called by the kdb_init function to initialize + * the kdb command table. It must be called prior to any other + * call to kdb_register. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +void +kdb_inittab(void) +{ + int i; + kdbtab_t *kp; + + for(i=0, kp=kdb_commands; i < KDB_MAX_COMMANDS; i++,kp++) { + kp->cmd_name = NULL; + } + + kdb_register("md", kdb_md, "", "Display Memory Contents", 1); + kdb_register("mds", kdb_md, "", "Display Memory Symbolically", 0); + kdb_register("mm", kdb_mm, " ", "Modify Memory Contents", 0); + kdb_register("id", kdb_id, "", "Display Instructions", 1); + kdb_register("go", kdb_go, "[]", "Continue Execution", 1); + kdb_register("rd", kdb_rd, "", "Display Registers", 1); + kdb_register("rm", kdb_rm, " ", "Modify Registers", 0); + kdb_register("ef", kdb_ef, "", "Display exception frame", 0); + kdb_register("bt", kdb_bt, "[]", "Stack traceback", 1); + kdb_register("btp", kdb_bt, "", "Display stack for process ", 0); + kdb_register("bp", kdb_bp, "[]", "Set/Display breakpoints", 0); + kdb_register("bl", kdb_bp, "[]", "Display breakpoints", 0); + kdb_register("bpa", kdb_bp, "[]", "Set/Display global breakpoints", 0); + kdb_register("bc", kdb_bc, "", "Clear Breakpoint", 0); + kdb_register("be", kdb_bc, "", "Enable Breakpoint", 0); + kdb_register("bd", kdb_bc, "", "Disable Breakpoint", 0); + kdb_register("ss", kdb_ss, "[<#steps>]", "Single Step", 1); + kdb_register("ssb", kdb_ss, "", "Single step to branch/call", 0); + kdb_register("ll", kdb_ll, " ", "Execute cmd for each element in linked list", 0); + kdb_register("env", kdb_env, "", "Show environment variables", 0); + kdb_register("set", kdb_set, "", "Set environment variables", 0); + kdb_register("help", kdb_help, "", "Display Help Message", 1); + kdb_register("?", kdb_help, "", "Display Help Message", 0); +#if defined(__SMP__) + kdb_register("cpu", kdb_cpu, "","Switch to new cpu", 0); +#endif /* __SMP__ */ + kdb_register("ps", kdb_ps, "", "Display active task list", 0); + kdb_register("reboot", kdb_reboot, "", "Reboot the machine immediately", 0); +} + diff -urN 2.3.29pre1/arch/i386/kdb/kdb_bp.c 2.3.29pre1-ikd/arch/i386/kdb/kdb_bp.c --- 2.3.29pre1/arch/i386/kdb/kdb_bp.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/kdb_bp.c Mon Nov 22 16:56:22 1999 @@ -0,0 +1,707 @@ +/* + * Kernel Debugger Breakpoint Handler + * + * Copyright 1999, Silicon Graphics, Inc. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + */ + +#include +#include +#include +#if defined(__SMP__) +#include +#include +#endif +#include +#include "kdbsupport.h" + +/* + * Table of breakpoints + */ +#define KDB_MAXBPT 16 +static kdb_bp_t breakpoints[KDB_MAXBPT]; + +static char *rwtypes[] = {"Instruction", "Data Write", "I/O", "Data Access"}; + +/* + * kdb_bp_install + * + * Install breakpoints prior to returning from the kernel debugger. + * This allows the breakpoints to be set upon functions that are + * used internally by kdb, such as printk(). + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdb_bp_install(void) +{ + int i; + + for(i=0; ieip); + if (op1 == 0x0f) + op2 = *(unsigned char *)(ef->eip+1); + if (((op1&0xf0) == 0xe0) /* short disp jumps */ + || ((op1&0xf0) == 0x70) /* Misc. jumps */ + || (op1 == 0xc2) /* ret */ + || (op1 == 0x9a) /* call */ + || ((op1&0xf8) == 0xc8) /* enter, leave, iret, int, */ + || ((op1 == 0x0f) + && ((op2&0xf0)== 0x80))) { + /* + * End the ssb command here. + */ + kdb_flags &= ~KDB_FLAG_SSB; + } else { + kdb_id1(ef->eip); + rv = 2; /* Indicate ssb - dismiss immediately */ + } + } else { + /* + * Print current insn + */ + kdb_printf("SS trap at 0x%x\n", ef->eip); + kdb_id1(ef->eip); + } + + if (rv != 2) + ef->eflags &= ~EF_TF; + } + + if (dr6 & DR6_B0) { + rw = DR7_RW0(dr7); + reg = 0; + goto handle; + } + + if (dr6 & DR6_B1) { + rw = DR7_RW1(dr7); + reg = 1; + goto handle; + } + + if (dr6 & DR6_B2) { + rw = DR7_RW2(dr7); + reg = 2; + goto handle; + } + + if (dr6 & DR6_B3) { + rw = DR7_RW3(dr7); + reg = 3; + goto handle; + } + + if (rv > 0) + goto handled; + + goto unknown; /* dismiss */ + +handle: + /* + * Set Resume Flag + */ + ef->eflags |= EF_RF; + + /* + * Determine which breakpoint was encountered. + */ + for(i=0; ieip); + } + + goto handled; + } + } + +unknown: + kdb_printf("Unknown breakpoint. Should forward. \n"); + +handled: + + /* + * Clear the pending exceptions. + */ + kdb_putdr6(0); + + return rv; +} + +/* + * kdb_printbp + * + * Internal function to format and print a breakpoint entry. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +static void +kdb_printbp(kdb_bp_t *bp, int i) +{ + char *symname; + long offset; + + kdb_printf("%s ", rwtypes[bp->bp_mode]); + + kdb_printf("BP #%d at 0x%x ", + i, bp->bp_addr); + symname = kdbnearsym(bp->bp_addr); + if (symname){ + kdb_printf("(%s", symname); + + offset = bp->bp_addr - kdbgetsymval(symname); + if (offset) { + if (offset > 0) + kdb_printf("+0x%x", offset); + else + kdb_printf("-0x%x", offset); + } + kdb_printf(") "); + } + + if (bp->bp_enabled) { + kdb_printf("\n is enabled in dr%d", bp->bp_reg); + if (bp->bp_global) + kdb_printf(" globally"); + else + kdb_printf(" on cpu %d", bp->bp_cpu); + + if (bp->bp_mode != 0) { + kdb_printf(" for %d bytes", bp->bp_length + 1); + } + } else { + kdb_printf("\n is disabled"); + } + + kdb_printf("\n"); +} + +/* + * kdb_bp + * + * Handle the bp, and bpa commands. + * + * [bp|bpa] [DATAR|DATAW|IO [length]] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + */ + +int +kdb_bp(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + kdb_bp_t *bp; + int diag; + int free, same; + k_machreg_t addr; + char *symname = NULL; + long offset = 0ul; + int nextarg; + unsigned long mode, length; +#if defined(__SMP__) + int global; +#endif + + if (argc == 0) { + /* + * Display breakpoint table + */ + for(i=0,bp=breakpoints; ibp_free) continue; + + kdb_printbp(bp, i); + } + + return 0; + } + +#if defined(__SMP__) + global = (strcmp(argv[0], "bpa") == 0); +#endif + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, &symname, regs); + if (diag) + return diag; + + mode = 0; /* Default to instruction breakpoint */ + length = 0; /* Length must be zero for insn bp */ + if ((argc + 1) != nextarg) { + if (strnicmp(argv[nextarg], "datar", sizeof("datar")) == 0) { + mode = 3; + } else if (strnicmp(argv[nextarg], "dataw", sizeof("dataw")) == 0) { + mode = 1; + } else if (strnicmp(argv[nextarg], "io", sizeof("io")) == 0) { + mode = 2; + } else { + return KDB_ARGCOUNT; + } + + length = 3; /* Default to 4 byte */ + + nextarg++; + + if ((argc + 1) != nextarg) { + diag = kdbgetularg((char *)argv[nextarg], &length); + if (diag) + return diag; + + if ((length > 4) || (length == 3)) + return KDB_BADLENGTH; + + length--; /* Normalize for debug register */ + nextarg++; + } + + if ((argc + 1) != nextarg) + return KDB_ARGCOUNT; + } + + /* + * Allocate a new bp structure + */ + free = same = KDB_MAXBPT; + for(i=0; ibp_addr = addr; + bp->bp_mode = mode; + bp->bp_length = length; + + /* + * Find a free register + */ + for(i=0; ibp_reg = i; + bp->bp_free = 0; + bp->bp_enabled = 1; +#if defined(__SMP__) + if (global) + bp->bp_global = 1; + else + bp->bp_cpu = smp_processor_id(); +#endif + + kdb_printbp(bp, free); + + break; + } + } + /* + * XXX if not enough regs, fail. Eventually replace + * first byte of instruction with int03. + */ + if (i==KDB_DBREGS) + return KDB_TOOMANYDBREGS; + + return 0; +} + +/* + * kdb_bc + * + * Handles the 'bc', 'be', and 'bd' commands + * + * [bd|bc|be] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + */ +#define KDBCMD_BC 0 +#define KDBCMD_BE 1 +#define KDBCMD_BD 2 + +int +kdb_bc(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + k_machreg_t addr; + kdb_bp_t *bp = 0; + int lowbp = KDB_MAXBPT; + int highbp = 0; + int done = 0; + int i; + int diag; + int cmd; /* KDBCMD_B? */ + + if (strcmp(argv[0], "be") == 0) { + cmd = KDBCMD_BE; + } else if (strcmp(argv[0], "bd") == 0) { + cmd = KDBCMD_BD; + } else + cmd = KDBCMD_BC; + + if (argc != 1) + return KDB_ARGCOUNT; + + if (strcmp(argv[1], "*") == 0) { + lowbp = 0; + highbp = KDB_MAXBPT; + } else { + diag = kdbgetularg(argv[1], &addr); + if (diag) + return diag; + + /* + * For addresses less than the maximum breakpoint number, + * assume that the breakpoint number is desired. + */ + if (addr < KDB_MAXBPT) { + bp = &breakpoints[addr]; + lowbp = highbp = addr; + highbp++; + } else { + for(i=0; ibp_free) + continue; + + done++; + + switch (cmd) { + case KDBCMD_BC: + kdbremovedbreg(bp->bp_reg); + dbregs[bp->bp_reg] = 0xffffffff; + kdb_printf("Breakpoint %d at 0x%x in dr%d cleared\n", + i, bp->bp_addr, bp->bp_reg); + bp->bp_free = 1; + bp->bp_addr = 0; + break; + case KDBCMD_BE: + { + int r; + + for(r=0; rbp_reg = r; + bp->bp_enabled = 1; + kdb_printf("Breakpoint %d at 0x%x in dr%d enabled\n", + i, bp->bp_addr, bp->bp_reg); + break; + } + } + if (r == KDB_DBREGS) + return KDB_TOOMANYDBREGS; + + break; + } + case KDBCMD_BD: + kdbremovedbreg(bp->bp_reg); + dbregs[bp->bp_reg] = 0xffffffff; + bp->bp_enabled = 0; + kdb_printf("Breakpoint %d at 0x%x in dr%d disabled\n", + i, bp->bp_addr, bp->bp_reg); + break; + } + } + + return (!done)?KDB_BPTNOTFOUND:0; +} + +/* + * kdb_initbptab + * + * Initialize the breakpoint table. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdb_initbptab(void) +{ + int i; + + /* + * First time initialization. + */ + for (i=0; i] + * ssb + * + * Parameters: + * argc Argument count + * argv Argument vector + * envp Environment vector + * regs Registers at time of entry to kernel debugger + * Outputs: + * None. + * Returns: + * 0 for success, a kdb error if failure. + * Locking: + * None. + * Remarks: + * + * Set the trace flag in the EFLAGS register to trigger + * a debug trap after the next instruction. Print the + * current instruction. + * + * For 'ssb', set the trace flag in the debug trap handler + * after printing the current insn and return directly without + * invoking the kdb command processor, until a branch instruction + * is encountered or SSCOUNT lines are printed. + */ + +int +kdb_ss(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int ssb = 0; + + ssb = (strcmp(argv[0], "ssb") == 0); + if ((ssb && (argc != 0)) + || (!ssb && (argc > 1))) { + return KDB_ARGCOUNT; + } + +#if 0 + /* + * Fetch provided count + */ + diag = kdbgetularg(argv[1], &sscount); + if (diag) + return diag; +#endif + + /* + * Print current insn + */ + kdb_id1(regs->eip); + + /* + * Set trace flag and go. + */ + regs->eflags |= EF_TF; + + if (ssb) + kdb_flags |= KDB_FLAG_SSB; + + return KDB_GO; +} diff -urN 2.3.29pre1/arch/i386/kdb/kdb_bt.c 2.3.29pre1-ikd/arch/i386/kdb/kdb_bt.c --- 2.3.29pre1/arch/i386/kdb/kdb_bt.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/kdb_bt.c Mon Nov 22 16:56:22 1999 @@ -0,0 +1,385 @@ + /* + * Minimalist Kernel Debugger + * + * Machine dependent stack traceback code. + * + * Copyright 1999, Silicon Graphics, Inc. + * + * Written by Scott Lurndal at Silicon Graphics, March 1999. + */ + +#include +#include +#include +#include +#include +#include +#include "kdbsupport.h" + + +#if defined(CONFIG_KDB_FRAMEPTR) +/* + * kdb_prologue + * + * This function analyzes a gcc-generated function prototype + * when frame pointers are enabled to determine the amount of + * automatic storage and register save storage is used on the + * stack of the target function. + * Parameters: + * eip Address of function to analyze + * Outputs: + * *nauto # bytes of automatic storage + * *nsave # of saved registers + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + * A prologue generally looks like: + * + * pushl %ebp (All functions) + * movl %esp, %ebp (All functions) + * subl $auto, %esp [some functions] + * pushl reg [some functions] + * pushl reg [some functions] + */ + +void +kdb_prologue(unsigned long eip, unsigned long *nauto, unsigned long *nsave) +{ + size_t insn_size = sizeof(unsigned char); + + *nauto = 0; + *nsave = 0; + + if (eip == 0) + return; + + if ((kdbgetword(eip, insn_size) != 0x55) /* pushl %ebp */ + || (kdbgetword(eip+1, insn_size) != 0x89)){/* movl esp, ebp */ + /* + * Unknown prologue type. + */ + return; + } + + if (kdbgetword(eip+3, insn_size) == 0x83) { + *nauto = kdbgetword(eip+5, sizeof(unsigned char)); + eip += 6; + } else if (kdbgetword(eip+3, insn_size) == 0x81) { + *nauto = kdbgetword(eip+5, sizeof(unsigned long)); + eip += 9; + } else + eip += 3; + + + while ((kdbgetword(eip, insn_size)&0xf8) == 0x50) + (*nsave)++, eip++; +} +#endif + +/* + * kdb_bt + * + * This function implements the 'bt' command. Print a stack + * traceback. + * + * bt [] (addr-exp is for alternate stacks) + * btp (Kernel stack for ) + * + * address expression refers to a return address on the stack. It + * is expected to be preceeded by a frame pointer. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Doing this without a frame pointer is _hard_. some simple + * things are done here, but we usually don't find more than the + * first couple of frames yet. More coming in this area. + * + * mds comes in handy when examining the stack to do a manual + * traceback. + */ + +int +kdb_bt(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int done = 0; +#if !defined(CONFIG_KDB_FRAMEPTR) + unsigned long sp; +#endif + unsigned long base, limit, esp, ebp, eip; + unsigned long start = 0; /* Start address of current function */ + unsigned long addr; + long offset = 0; + int nextarg; + int argcount=5; + char *name; + int diag; + struct pt_regs taskregs; + struct frame { + unsigned long ebp; + unsigned long eip; + } old; + unsigned long stackbase = (unsigned long)current; + + /* + * Determine how many possible arguments to print. + */ + diag = kdbgetintenv("BTARGS", &argcount); + + if (strcmp(argv[0], "btp") == 0){ + struct task_struct *p; + int pid; + + diag = kdbgetularg((char *)argv[1], (unsigned long*)&pid); + if (diag) + return diag; + + taskregs.eax = 1; + for_each_task(p) { + if (p->pid == pid) { + taskregs.eip = p->thread.eip; + taskregs.esp = p->thread.esp; + /* + * Since we don't really use the TSS + * to store register between task switches, + * attempt to locate real ebp (should be + * top of stack if task is in schedule) + */ + taskregs.ebp = *(unsigned long *)(taskregs.esp); + + taskregs.eax = 0; + stackbase = (unsigned long)p; + break; + } + } + + if (taskregs.eax == 1) { + kdb_printf("No process with pid == %d found\n", + pid); + return 0; + } + regs = &taskregs; + } else { + if (argc) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + /* + * We assume the supplied address is points to an + * EIP value on the stack, and the word pushed above + * it is an EBP value. Start as if we were in the + * middle of that frame. + */ + taskregs.eip = kdbgetword(addr, sizeof(unsigned long)); + taskregs.ebp = kdbgetword(addr-4, sizeof(unsigned long)); + taskregs.ebp = kdbgetword(taskregs.ebp, sizeof(unsigned long)); + regs = &taskregs; + } + } + + name = kdbnearsym(regs->eip); + if (name) { + start = kdbgetsymval(name); + } else { + kdb_printf("Cannot determine function for eip = 0x%x\n", + regs->eip); + return 0; + } +#if !defined(CONFIG_KDB_FRAMEPTR) + /* + * starting with %esp value, track the stack back to + * the end. + */ + + sp = (unsigned long) (1+regs); /* Point past exception frame */ + sp -= 8; /* Adjust to encompass return addr */ + if (regs->xcs & 3) { + /* User space? */ + sp = regs->esp; + } + sp -= 8; /* Adjust to encompass return addr */ + base = sp & ~0x1fff; /* XXX - use stack size constant */ + + + kdb_printf(" ESP EIP Function(args)\n"); + kdb_printf("0x%x 0x%x %s ()\n", + sp, regs->eip, name); + + while (!done) { + extern char _text, _etext; + extern char __init_begin, __init_end; + unsigned long word; + + word = *(unsigned long *)(sp); + if ( ((word >= (unsigned long)&_text) + && (word <= (unsigned long)&_etext)) + || ((word >= (unsigned long)&__init_begin) + && (word <= (unsigned long)&__init_end))) { + /* text address */ + +#if defined(NOTNOW) + kdb_printf("word %x sp %x char %x off %x\n", + word, sp, *(unsigned char *)(word - 5), + *(signed long *)(word - 4)); +#endif + /* + * If the instruction 5 bytes before the + * return instruction is a call, treat this + * entry as a probable activation record + */ + if (*(unsigned char *)(word - 5) == 0xe8) { + signed long val = *(signed long *)(word - 4); + int i; + + /* + * Is this a real activation record? + */ + /* + * Of course, this misses all the + * indirect calls, etc. XXX XXX + */ + if ((val + word) == start) { + kdb_printf("0x%x 0x%x ", + sp, word); + name = kdbnearsym(word); + if (name) { + kdb_printf("%s (", name); + } + for(i=0; i= base+0x2000) /* XXX - use stack size constant */ + done = 1; + } +#else + kdb_printf(" EBP EIP Function(args)\n"); + + base = stackbase; + + esp = regs->esp; + ebp = regs->ebp; + eip = regs->eip; + + limit = base + 0x2000; /* stack limit */ + +#if 0 + printk("stackbase = 0x%lx base = 0x%lx limit = 0x%lx ebp = 0x%lx esp = 0x%lx eip = 0x%lx\n", + stackbase, base, limit, ebp, esp, eip); +#endif + + if ((eip == start) /* Beginning of function */ + || (eip == start+1)) { /* Right after pushl %ebp */ + /* + * If at start of function, create a dummy frame + */ + old.ebp = ebp; + if (kdb_flags & KDB_FLAG_FAULT) { + if ((regs->xcs&0xffff) == 0x10) { + /* + * For instruction breakpoint on a target of a + * call instruction, we must fetch the caller's + * eip shall we say, differently. + */ + old.eip = regs->esp; /* Don't Ask */ + } else { + old.eip = *(unsigned long *)(regs+1); + } + } else { + old.eip = (eip == start) + ?kdbgetword(esp, sizeof(unsigned long)) + :kdbgetword(esp+4, sizeof(unsigned long)); + } + ebp = (unsigned long)&old; + } + + /* + * While the ebp remains within the stack, continue to + * print stack entries. + * + * XXX - this code depends on the fact that kernel + * stacks are aligned on address boundaries + * congruent to 0 modulo 8192 and are 8192 bytes + * in length and are part of the 8k bytes based + * at the process structure (e.g. current). + * + */ + + while (!done) { + unsigned long nebp, neip; + char *newname; + + kdb_printf("0x%x 0x%x ", ebp, eip); + kdb_printf("%s", name); + + if (ebp < PAGE_OFFSET) { + done++; + kdb_printf("\n"); + continue; + } + + nebp = kdbgetword(ebp, sizeof(unsigned long)); + neip = kdbgetword(ebp+4, sizeof(unsigned long)); + + if (eip != start) { + kdb_printf("+0x%x", eip - start); + } + + /* + * Get frame for caller to determine the frame size + * and argument count. + */ + newname = kdbnearsym(neip); + if (newname) { + int i; + unsigned long nauto, nsave, nargs; + + start = kdbgetsymval(newname); + name = newname; + + kdb_printf("( "); + + kdb_prologue(kdbgetsymval(newname), &nauto, &nsave); + + nargs = (nebp - ebp - 8 - nauto - (nsave * 4))/4; + if (nargs > argcount) + nargs = argcount; + for(i=0; i buffer) { + --cp, bufsize++; + printk("%c %c", 0x08, 0x08); + } + continue; + } + serial_out(kdb_port, UART_TX, ch); + if (ch == 13) { /* CR */ + *cp++ = '\n'; + *cp++ = '\0'; + serial_out(kdb_port, UART_TX, 10); + return(buffer); + } + /* + * Discard excess characters + */ + if (bufsize > 0) { + *cp++ = ch; + bufsize--; + } + } + while (((status = serial_inp(kdb_port, UART_LSR)) + & UART_LSR_DR) == 0); + } + } + + while (1) { + + /* + * Wait for a valid scancode + */ + + while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + ; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + /* + * Ignore mouse events. + */ + if (scanstatus & KBD_STAT_MOUSE_OBF) + continue; + + /* + * Ignore release, trigger on make + * (except for shift keys, where we want to + * keep the shift state so long as the key is + * held down). + */ + + if (((scancode&0x7f) == 0x2a) + || ((scancode&0x7f) == 0x36)) { + /* + * Next key may use shift table + */ + if ((scancode & 0x80) == 0) { + shift_key=1; + } else { + shift_key=0; + } + continue; + } + + if ((scancode&0x7f) == 0x1d) { + /* + * Left ctrl key + */ + if ((scancode & 0x80) == 0) { + ctrl_key = 1; + } else { + ctrl_key = 0; + } + continue; + } + + if ((scancode & 0x80) != 0) + continue; + + scancode &= 0x7f; + + /* + * Translate scancode + */ + + if (scancode == 0x3a) { + /* + * Toggle caps lock + */ + shift_lock ^= 1; + leds ^= 0x4; /* toggle caps lock led */ + + kdb_kbdsetled(leds); + continue; + } + + if (scancode == 0x0e) { + /* + * Backspace + */ + if (cp > buffer) { + --cp, bufsize++; + + /* + * XXX - erase character on screen + */ + printk("%c %c", 0x08, 0x08); + } + continue; + } + + if (scancode == 0xe0) { + continue; + } + + /* + * For Japanese 86/106 keyboards + * See comment in drivers/char/pc_keyb.c. + * - Masahiro Adegawa + */ + if (scancode == 0x73) { + scancode = 0x59; + } else if (scancode == 0x7d) { + scancode = 0x7c; + } + + if (!shift_lock && !shift_key) { + keychar = plain_map[scancode]; + } else if (shift_lock || shift_key) { + keychar = shift_map[scancode]; + } else if (ctrl_key) { + keychar = ctrl_map[scancode]; + } else { + keychar = 0x0020; + printk("Unknown state/scancode (%d)\n", scancode); + } + + if ((scancode & 0x7f) == 0x1c) { + /* + * enter key. All done. + */ + printk("\n"); + break; + } + + /* + * echo the character. + */ + printk("%c", keychar&0xff); + + if (bufsize) { + --bufsize; + *cp++ = keychar&0xff; + } else { + printk("buffer overflow\n"); + break; + } + + } + + *cp++ = '\n'; /* White space for parser */ + *cp++ = '\0'; /* String termination */ + +#if defined(NOTNOW) + cp = buffer; + while (*cp) { + printk("char 0x%x\n", *cp++); + } +#endif + + return buffer; +} diff -urN 2.3.29pre1/arch/i386/kdb/kdbsupport.c 2.3.29pre1-ikd/arch/i386/kdb/kdbsupport.c --- 2.3.29pre1/arch/i386/kdb/kdbsupport.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/kdbsupport.c Mon Nov 22 16:56:22 1999 @@ -0,0 +1,947 @@ +/* + * Kernel Debugger Breakpoint Handler + * + * Copyright 1999, Silicon Graphics, Inc. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kdbsupport.h" + +k_machreg_t dbregs[KDB_DBREGS]; + +void +kdb_init(void) +{ + extern void kdb_inittab(void); + + kdb_inittab(); + kdb_initbptab(); + kdb_disinit(); + kdb_printf("kdb version %d.%d by Scott Lurndal. "\ + "Copyright SGI, All Rights Reserved\n", + KDB_MAJOR_VERSION, KDB_MINOR_VERSION); +} + +module_init(kdb_init) + +static void +kdb_setup(void) +{ + kdb_flags = KDB_FLAG_EARLYKDB; +} + +__setup("kdb", kdb_setup); + +/* + * kdbprintf + * kdbgetword + * kdb_getstr + */ + +char * +kbd_getstr(char *buffer, size_t bufsize, char *prompt) +{ + extern char* kdb_getscancode(char *, size_t); + +#if defined(CONFIG_SMP) + kdb_printf(prompt, smp_processor_id()); +#else + kdb_printf("%s", prompt); +#endif + + return kdb_getscancode(buffer, bufsize); + +} + +int +kdb_printf(const char *fmt, ...) +{ + char buffer[256]; + va_list ap; + int diag; + int linecount; + + diag = kdbgetintenv("LINES", &linecount); + if (diag) + linecount = 22; + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + va_end(ap); + + printk("%s", buffer); + + if (strchr(buffer, '\n') != NULL) { + kdb_nextline++; + } + + if (kdb_nextline == linecount) { + char buf1[16]; + char buf2[32]; + extern char* kdb_getscancode(char *, size_t); + char *moreprompt; + + /* + * Pause until cr. + */ + moreprompt = kdbgetenv("MOREPROMPT"); + if (moreprompt == NULL) { + moreprompt = "more> "; + } + +#if defined(CONFIG_SMP) + if (strchr(moreprompt, '%')) { + sprintf(buf2, moreprompt, smp_processor_id()); + moreprompt = buf2; + } +#endif + + printk(moreprompt); + (void) kdb_getscancode(buf1, sizeof(buf1)); + + kdb_nextline = 1; + + if ((buf1[0] == 'q') + || (buf1[0] == 'Q')) { + kdb_longjmp(&kdbjmpbuf, 1); + } + } + + return 0; +} + +unsigned long +kdbgetword(unsigned long addr, int width) +{ + /* + * This function checks the address for validity. Any address + * in the range PAGE_OFFSET to high_memory is legal, any address + * which maps to a vmalloc region is legal, and any address which + * is a user address, we use get_user() to verify validity. + */ + + if (addr < PAGE_OFFSET) { + /* + * Usermode address. + */ + unsigned long diag; + unsigned long ulval; + + switch (width) { + case 4: + { unsigned long *lp; + + lp = (unsigned long *) addr; + diag = get_user(ulval, lp); + break; + } + case 2: + { unsigned short *sp; + + sp = (unsigned short *) addr; + diag = get_user(ulval, sp); + break; + } + case 1: + { unsigned char *cp; + + cp = (unsigned char *) addr; + diag = get_user(ulval, cp); + break; + } + default: + printk("kdbgetword: Bad width\n"); + return 0L; + } + + if (diag) { + if ((kdb_flags & KDB_FLAG_SUPRESS) == 0) { + printk("kdb: Bad user address 0x%lx\n", addr); + kdb_flags |= KDB_FLAG_SUPRESS; + } + return 0L; + } + kdb_flags &= ~KDB_FLAG_SUPRESS; + return ulval; + } + + if (addr > (unsigned long)high_memory) { + extern int kdb_vmlist_check(unsigned long, unsigned long); + + if (!kdb_vmlist_check(addr, addr+width)) { + /* + * Would appear to be an illegal kernel address; + * Print a message once, and don't print again until + * a legal address is used. + */ + if ((kdb_flags & KDB_FLAG_SUPRESS) == 0) { + printk("kdb: Bad kernel address 0x%lx\n", addr); + kdb_flags |= KDB_FLAG_SUPRESS; + } + return 0L; + } + } + + /* + * A good address. Reset error flag. + */ + kdb_flags &= ~KDB_FLAG_SUPRESS; + + switch (width) { + case 4: + { unsigned long *lp; + + lp = (unsigned long *)(addr); + return *lp; + } + case 2: + { unsigned short *sp; + + sp = (unsigned short *)(addr); + return *sp; + } + case 1: + { unsigned char *cp; + + cp = (unsigned char *)(addr); + return *cp; + } + } + + printk("kdbgetword: Bad width\n"); + return 0L; +} + +int +kdbinstalltrap(int type, handler_t newh, handler_t *oldh) +{ + /* + * Usurp INTn. XXX - TBD. + */ + + return 0; +} + +int +kdbinstalldbreg(kdb_bp_t *bp) +{ + k_machreg_t dr7; + + dr7 = kdb_getdr7(); + + kdb_putdr(bp->bp_reg, bp->bp_addr); + + dr7 |= DR7_GE; + + switch (bp->bp_reg){ + case 0: + DR7_RW0SET(dr7,bp->bp_mode); + DR7_LEN0SET(dr7,bp->bp_length); + DR7_G0SET(dr7); + break; + case 1: + DR7_RW1SET(dr7,bp->bp_mode); + DR7_LEN1SET(dr7,bp->bp_length); + DR7_G1SET(dr7); + break; + case 2: + DR7_RW2SET(dr7,bp->bp_mode); + DR7_LEN2SET(dr7,bp->bp_length); + DR7_G2SET(dr7); + break; + case 3: + DR7_RW3SET(dr7,bp->bp_mode); + DR7_LEN3SET(dr7,bp->bp_length); + DR7_G3SET(dr7); + break; + default: + kdb_printf("Bad debug register!! %d\n", bp->bp_reg); + break; + } + + kdb_putdr7(dr7); + return 0; +} + +void +kdbremovedbreg(int regnum) +{ + k_machreg_t dr7; + + dr7 = kdb_getdr7(); + + kdb_putdr(regnum, 0); + + switch (regnum) { + case 0: + DR7_G0CLR(dr7); + DR7_L0CLR(dr7); + break; + case 1: + DR7_G1CLR(dr7); + DR7_L1CLR(dr7); + break; + case 2: + DR7_G2CLR(dr7); + DR7_L2CLR(dr7); + break; + case 3: + DR7_G3CLR(dr7); + DR7_L3CLR(dr7); + break; + default: + kdb_printf("Bad debug register!! %d\n", regnum); + break; + } + + kdb_putdr7(dr7); +} + +k_machreg_t +kdb_getdr6(void) +{ + return kdb_getdr(6); +} + +k_machreg_t +kdb_getdr7(void) +{ + return kdb_getdr(7); +} + +k_machreg_t +kdb_getdr(int regnum) +{ + k_machreg_t contents = 0; +#if defined(__GNUC__) + switch(regnum) { + case 0: + __asm__ ("movl %%db0,%0\n\t":"=r"(contents)); + break; + case 1: + __asm__ ("movl %%db1,%0\n\t":"=r"(contents)); + break; + case 2: + __asm__ ("movl %%db2,%0\n\t":"=r"(contents)); + break; + case 3: + __asm__ ("movl %%db3,%0\n\t":"=r"(contents)); + break; + case 4: + case 5: + break; + case 6: + __asm__ ("movl %%db6,%0\n\t":"=r"(contents)); + break; + case 7: + __asm__ ("movl %%db7,%0\n\t":"=r"(contents)); + break; + default: + break; + } + +#endif /* __GNUC__ */ + return contents; +} + + +k_machreg_t +kdb_getcr(int regnum) +{ + k_machreg_t contents = 0; +#if defined(__GNUC__) + switch(regnum) { + case 0: + __asm__ ("movl %%cr0,%0\n\t":"=r"(contents)); + break; + case 1: + break; + case 2: + __asm__ ("movl %%cr2,%0\n\t":"=r"(contents)); + break; + case 3: + __asm__ ("movl %%cr3,%0\n\t":"=r"(contents)); + break; + case 4: + __asm__ ("movl %%cr4,%0\n\t":"=r"(contents)); + break; + default: + break; + } + +#endif /* __GNUC__ */ + return contents; +} + +void +kdb_putdr6(k_machreg_t contents) +{ + kdb_putdr(6, contents); +} + +void +kdb_putdr7(k_machreg_t contents) +{ + kdb_putdr(7, contents); +} + +void +kdb_putdr(int regnum, k_machreg_t contents) +{ +#if defined(__GNUC__) + switch(regnum) { + case 0: + __asm__ ("movl %0,%%db0\n\t"::"r"(contents)); + break; + case 1: + __asm__ ("movl %0,%%db1\n\t"::"r"(contents)); + break; + case 2: + __asm__ ("movl %0,%%db2\n\t"::"r"(contents)); + break; + case 3: + __asm__ ("movl %0,%%db3\n\t"::"r"(contents)); + break; + case 4: + case 5: + break; + case 6: + __asm__ ("movl %0,%%db6\n\t"::"r"(contents)); + break; + case 7: + __asm__ ("movl %0,%%db7\n\t"::"r"(contents)); + break; + default: + break; + } +#endif +} + +/* + * Symbol table functions. + */ + +/* + * kdbgetsym + * + * Return the symbol table entry for the given symbol + * + * Parameters: + * symname Character string containing symbol name + * Outputs: + * Returns: + * NULL Symbol doesn't exist + * ksp Pointer to symbol table entry + * Locking: + * None. + * Remarks: + */ + +__ksymtab_t * +kdbgetsym(const char *symname) +{ + __ksymtab_t *ksp = __kdbsymtab; + int i; + + if (symname == NULL) + return NULL; + + for (i=0; i<__kdbsymtabsize; i++, ksp++) { + if (ksp->name && (strcmp(ksp->name, symname)==0)) { + return ksp; + } + } + + return NULL; +} + +/* + * kdbgetsymval + * + * Return the address of the given symbol. + * + * Parameters: + * symname Character string containing symbol name + * Outputs: + * Returns: + * 0 Symbol name is NULL + * addr Address corresponding to symname + * Locking: + * None. + * Remarks: + */ + +unsigned long +kdbgetsymval(const char *symname) +{ + __ksymtab_t *ksp = kdbgetsym(symname); + + return (ksp?ksp->value:0); +} + +/* + * kdbaddmodsym + * + * Add a symbol to the kernel debugger symbol table. Called when + * a new module is loaded into the kernel. + * + * Parameters: + * symname Character string containing symbol name + * value Value of symbol + * Outputs: + * Returns: + * 0 Successfully added to table. + * 1 Duplicate symbol + * 2 Symbol table full + * Locking: + * None. + * Remarks: + */ + +int +kdbaddmodsym(char *symname, unsigned long value) +{ + + /* + * Check for duplicate symbols. + */ + if (kdbgetsym(symname)) { + printk("kdb: Attempt to register duplicate symbol '%s' @ 0x%lx\n", + symname, value); + return 1; + } + + if (__kdbsymtabsize < __kdbmaxsymtabsize) { + __ksymtab_t *ksp = &__kdbsymtab[__kdbsymtabsize++]; + + ksp->name = symname; + ksp->value = value; + return 0; + } + + /* + * No room left in kernel symbol table. + */ + { + static int __kdbwarn = 0; + + if (__kdbwarn == 0) { + __kdbwarn++; + printk("kdb: Exceeded symbol table size. Increase KDBMAXSYMTABSIZE in scripts/genkdbsym.awk\n"); + } + } + + return 2; +} + +/* + * kdbdelmodsym + * + * Add a symbol to the kernel debugger symbol table. Called when + * a new module is loaded into the kernel. + * + * Parameters: + * symname Character string containing symbol name + * value Value of symbol + * Outputs: + * Returns: + * 0 Successfully added to table. + * 1 Symbol not found + * Locking: + * None. + * Remarks: + */ + +int +kdbdelmodsym(const char *symname) +{ + __ksymtab_t *ksp, *endksp; + + if (symname == NULL) + return 1; + + /* + * Search for the symbol. If found, move + * all successive symbols down one position + * in the symbol table to avoid leaving holes. + */ + endksp = &__kdbsymtab[__kdbsymtabsize]; + for (ksp = __kdbsymtab; ksp < endksp; ksp++) { + if (ksp->name && (strcmp(ksp->name, symname) == 0)) { + endksp--; + for ( ; ksp < endksp; ksp++) { + *ksp = *(ksp + 1); + } + __kdbsymtabsize--; + return 0; + } + } + + return 1; +} + +/* + * kdbnearsym + * + * Return the name of the symbol with the nearest address + * less than 'addr'. + * + * Parameters: + * addr Address to check for symbol near + * Outputs: + * Returns: + * NULL No symbol with address less than 'addr' + * symbol Returns the actual name of the symbol. + * Locking: + * None. + * Remarks: + */ + +char * +kdbnearsym(unsigned long addr) +{ + __ksymtab_t *ksp = __kdbsymtab; + __ksymtab_t *kpp = NULL; + int i; + + for(i=0; i<__kdbsymtabsize; i++, ksp++) { + if (!ksp->name) + continue; + + if (addr == ksp->value) { + kpp = ksp; + break; + } + if (addr > ksp->value) { + if ((kpp == NULL) + || (ksp->value > kpp->value)) { + kpp = ksp; + } + } + } + + /* + * If more than 128k away, don't bother. + */ + if ((kpp == NULL) + || ((addr - kpp->value) > 0x20000)) { + return NULL; + } + + return kpp->name; +} + +/* + * kdbgetregcontents + * + * Return the contents of the register specified by the + * input string argument. Return an error if the string + * does not match a machine register. + * + * The following pseudo register names are supported: + * ®s - Prints address of exception frame + * kesp - Prints kernel stack pointer at time of fault + * % - Uses the value of the registers at the + * last time the user process entered kernel + * mode, instead of the registers at the time + * kdb was entered. + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * Outputs: + * *contents Pointer to unsigned long to recieve register contents + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + * + * Note that this function is really machine independent. The kdb + * register list is not, however. + */ + +static struct kdbregs { + char *reg_name; + size_t reg_offset; +} kdbreglist[] = { + { "eax", offsetof(struct pt_regs, eax) }, + { "ebx", offsetof(struct pt_regs, ebx) }, + { "ecx", offsetof(struct pt_regs, ecx) }, + { "edx", offsetof(struct pt_regs, edx) }, + + { "esi", offsetof(struct pt_regs, esi) }, + { "edi", offsetof(struct pt_regs, edi) }, + { "esp", offsetof(struct pt_regs, esp) }, + { "eip", offsetof(struct pt_regs, eip) }, + + { "ebp", offsetof(struct pt_regs, ebp) }, + { " ss", offsetof(struct pt_regs, xss) }, + { " cs", offsetof(struct pt_regs, xcs) }, + { "eflags", offsetof(struct pt_regs, eflags) }, + + { " ds", offsetof(struct pt_regs, xds) }, + { " es", offsetof(struct pt_regs, xes) }, + { "origeax", offsetof(struct pt_regs, orig_eax) }, + +}; + +static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs); + +int +kdbgetregcontents(const char *regname, + struct pt_regs *regs, + unsigned long *contents) +{ + int i; + + if (strcmp(regname, "®s") == 0) { + *contents = (unsigned long)regs; + return 0; + } + + if (strcmp(regname, "kesp") == 0) { + *contents = (unsigned long)regs + sizeof(struct pt_regs); + return 0; + } + + if (regname[0] == '%') { + /* User registers: %%e[a-c]x, etc */ + regname++; + regs = (struct pt_regs *) + (current->thread.esp0 - sizeof(struct pt_regs)); + } + + for (i=0; i + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * contents Unsigned long containing new register contents + * Outputs: + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + */ + +int +kdbsetregcontents(const char *regname, + struct pt_regs *regs, + unsigned long contents) +{ + int i; + + if (regname[0] == '%') { + regname++; + regs = (struct pt_regs *) + (current->thread.esp0 - sizeof(struct pt_regs)); + } + + for (i=0; ithread.esp0 - sizeof(struct pt_regs)); + } + + if (type == NULL) { + for (i=0; i + + /* + * This file provides definitions for functions that + * are dependent upon the product into which kdb is + * linked. + * + * This version is for linux. + */ +typedef void (*handler_t)(struct pt_regs *); +typedef unsigned long k_machreg_t; + +extern char* kbd_getstr(char *, size_t, char *); +extern int kdbinstalltrap(int, handler_t, handler_t*); +extern int kdbinstalldbreg(kdb_bp_t*); +extern void kdbremovedbreg(int); +extern void kdb_initbptab(void); +extern int kdbgetregcontents(const char *, struct pt_regs *, unsigned long *); +extern int kdbsetregcontents(const char *, struct pt_regs *, unsigned long); +extern int kdbdumpregs(struct pt_regs *, const char *, const char *); + + +/* + * kdb_db_trap is a processor dependent routine invoked + * from kdb() via the #db trap handler. It handles breakpoints involving + * the processor debug registers and handles single step traps + * using the processor trace flag. + */ + +#define KDB_DB_BPT 0 /* Straight breakpoint */ +#define KDB_DB_SS 1 /* Single Step trap */ +#define KDB_DB_SSB 2 /* Single Step, caller should continue */ + +extern int kdb_db_trap(struct pt_regs *); + + + /* + * Support for ia32 architecture debug registers. + */ +#define KDB_DBREGS 4 +extern k_machreg_t dbregs[]; + +#define DR6_BT 0x00008000 +#define DR6_BS 0x00004000 +#define DR6_BD 0x00002000 + +#define DR6_B3 0x00000008 +#define DR6_B2 0x00000004 +#define DR6_B1 0x00000002 +#define DR6_B0 0x00000001 + +#define DR7_RW_VAL(dr, drnum) \ + (((dr) >> (16 + (4 * (drnum)))) & 0x3) + +#define DR7_RW_SET(dr, drnum, rw) \ + do { \ + (dr) &= ~(0x3 << (16 + (4 * (drnum)))); \ + (dr) |= (((rw) & 0x3) << (16 + (4 * (drnum)))); \ + } while (0) + +#define DR7_RW0(dr) DR7_RW_VAL(dr, 0) +#define DR7_RW0SET(dr,rw) DR7_RW_SET(dr, 0, rw) +#define DR7_RW1(dr) DR7_RW_VAL(dr, 1) +#define DR7_RW1SET(dr,rw) DR7_RW_SET(dr, 1, rw) +#define DR7_RW2(dr) DR7_RW_VAL(dr, 2) +#define DR7_RW2SET(dr,rw) DR7_RW_SET(dr, 2, rw) +#define DR7_RW3(dr) DR7_RW_VAL(dr, 3) +#define DR7_RW3SET(dr,rw) DR7_RW_SET(dr, 3, rw) + + +#define DR7_LEN_VAL(dr, drnum) \ + (((dr) >> (18 + (4 * (drnum)))) & 0x3) + +#define DR7_LEN_SET(dr, drnum, rw) \ + do { \ + (dr) &= ~(0x3 << (18 + (4 * (drnum)))); \ + (dr) |= (((rw) & 0x3) << (18 + (4 * (drnum)))); \ + } while (0) + +#define DR7_LEN0(dr) DR7_LEN_VAL(dr, 0) +#define DR7_LEN0SET(dr,len) DR7_LEN_SET(dr, 0, len) +#define DR7_LEN1(dr) DR7_LEN_VAL(dr, 1) +#define DR7_LEN1SET(dr,len) DR7_LEN_SET(dr, 1, len) +#define DR7_LEN2(dr) DR7_LEN_VAL(dr, 2) +#define DR7_LEN2SET(dr,len) DR7_LEN_SET(dr, 2, len) +#define DR7_LEN3(dr) DR7_LEN_VAL(dr, 3) +#define DR7_LEN3SET(dr,len) DR7_LEN_SET(dr, 3, len) + +#define DR7_G0(dr) (((dr)>>1)&0x1) +#define DR7_G0SET(dr) ((dr) |= 0x2) +#define DR7_G0CLR(dr) ((dr) &= ~0x2) +#define DR7_G1(dr) (((dr)>>3)&0x1) +#define DR7_G1SET(dr) ((dr) |= 0x8) +#define DR7_G1CLR(dr) ((dr) &= ~0x8) +#define DR7_G2(dr) (((dr)>>5)&0x1) +#define DR7_G2SET(dr) ((dr) |= 0x20) +#define DR7_G2CLR(dr) ((dr) &= ~0x20) +#define DR7_G3(dr) (((dr)>>7)&0x1) +#define DR7_G3SET(dr) ((dr) |= 0x80) +#define DR7_G3CLR(dr) ((dr) &= ~0x80) + +#define DR7_L0(dr) (((dr))&0x1) +#define DR7_L0SET(dr) ((dr) |= 0x1) +#define DR7_L0CLR(dr) ((dr) &= ~0x1) +#define DR7_L1(dr) (((dr)>>2)&0x1) +#define DR7_L1SET(dr) ((dr) |= 0x4) +#define DR7_L1CLR(dr) ((dr) &= ~0x4) +#define DR7_L2(dr) (((dr)>>4)&0x1) +#define DR7_L2SET(dr) ((dr) |= 0x10) +#define DR7_L2CLR(dr) ((dr) &= ~0x10) +#define DR7_L3(dr) (((dr)>>6)&0x1) +#define DR7_L3SET(dr) ((dr) |= 0x40) +#define DR7_L3CLR(dr) ((dr) &= ~0x40) + +#define DR7_GD 0x00002000 /* General Detect Enable */ +#define DR7_GE 0x00000200 /* Global exact */ +#define DR7_LE 0x00000100 /* Local exact */ + +extern k_machreg_t kdb_getdr6(void); +extern void kdb_putdr6(k_machreg_t); + +extern k_machreg_t kdb_getdr7(void); +extern void kdb_putdr7(k_machreg_t); + +extern k_machreg_t kdb_getdr(int); +extern void kdb_putdr(int, k_machreg_t); + +extern k_machreg_t kdb_getcr(int); + +extern void kdb_bp_install(void); +extern void kdb_bp_remove(void); + +/* + * Support for setjmp/longjmp + */ +#define JB_BX 0 +#define JB_SI 1 +#define JB_DI 2 +#define JB_BP 3 +#define JB_SP 4 +#define JB_PC 5 + +typedef struct __kdb_jmp_buf { + unsigned long regs[6]; +} kdb_jmp_buf; + +extern int kdb_setjmp(kdb_jmp_buf *); +extern void kdb_longjmp(kdb_jmp_buf *, int); + +extern kdb_jmp_buf kdbjmpbuf; + +#endif /* KDSUPPORT */ diff -urN 2.3.29pre1/arch/i386/kdb/modules/Makefile 2.3.29pre1-ikd/arch/i386/kdb/modules/Makefile --- 2.3.29pre1/arch/i386/kdb/modules/Makefile Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/modules/Makefile Mon Nov 22 16:56:22 1999 @@ -0,0 +1,19 @@ +# +# Makefile for i386-specific kdb files.. +# +# Copyright 1999, Silicon Graphics Inc. +# +# Written April 1999 by Scott Lurndal at Silicon Graphics, Inc. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +#O_TARGET := kdbm_vm.o + +M_OBJS := kdbm_vm.o + +override CFLAGS := $(CFLAGS:%-pg=%-g -c) + +include $(TOPDIR)/Rules.make diff -urN 2.3.29pre1/arch/i386/kdb/modules/kdbm_vm.c 2.3.29pre1-ikd/arch/i386/kdb/modules/kdbm_vm.c --- 2.3.29pre1/arch/i386/kdb/modules/kdbm_vm.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/modules/kdbm_vm.c Mon Nov 22 16:56:22 1999 @@ -0,0 +1,81 @@ +#include +#include +#include + +struct __vmflags { + unsigned long mask; + char *name; +} vmflags[] = { + { VM_READ, "READ" }, + { VM_WRITE, "WRITE" }, + { VM_EXEC, "EXEC" }, + { VM_SHARED, "SHARED" }, + { VM_MAYREAD, "MAYREAD" }, + { VM_MAYWRITE, "MAYWRITE" }, + { VM_MAYEXEC, "MAYEXEC" }, + { VM_MAYSHARE, "MAYSHARE" }, + { VM_GROWSDOWN, "GROWSDOWN" }, + { VM_GROWSUP, "GROWSUP" }, + { VM_SHM, "SHM" }, + { VM_DENYWRITE, "DENYWRITE" }, + { VM_EXECUTABLE, "EXECUTABLE" }, + { VM_LOCKED, "LOCKED" }, + { VM_IO , "IO " }, + { 0, "" } +}; + +int +kdbm_vm(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct vm_area_struct vp; + unsigned char *bp = (unsigned char *)&vp; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + struct __vmflags *tp; + int i; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + addr += offset; + + for (i=0; imask; tp++) { + if (vp.vm_flags & tp->mask) { + printk("%s ", tp->name); + } + } + printk("\n"); + + return 0; +} + +int +init_module(void) +{ + kdb_register("vm", kdbm_vm, "", "Display vm_area_struct", 0); + + return 0; +} + +void +cleanup_module(void) +{ + kdb_unregister("vm"); +} diff -urN 2.3.29pre1/arch/i386/kdb/pc_keyb.h 2.3.29pre1-ikd/arch/i386/kdb/pc_keyb.h --- 2.3.29pre1/arch/i386/kdb/pc_keyb.h Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kdb/pc_keyb.h Mon Nov 22 16:56:22 1999 @@ -0,0 +1,126 @@ +/* + * linux/drivers/char/pc_keyb.h + * + * PC Keyboard And Keyboard Controller + * + * (c) 1997 Martin Mares + */ + +/* + * Configuration Switches + */ + +#undef KBD_REPORT_ERR /* Report keyboard errors */ +#define KBD_REPORT_UNKN /* Report unknown scan codes */ +#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ +#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ +#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ + + + +#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ +#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ +#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */ + +/* + * Internal variables of the driver + */ + +extern unsigned char pckbd_read_mask; +extern unsigned char aux_device_present; + +/* + * Keyboard Controller Registers + */ + +#define KBD_STATUS_REG 0x64 /* Status register (R) */ +#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ +#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ + +/* + * Keyboard Controller Commands + */ + +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if + initiated by the auxiliary device */ +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ + +/* + * Keyboard Commands + */ + +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_DISABLE 0xF5 /* Disable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* + * Keyboard Replies + */ + +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* + * Status Register Bits + */ + +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ +#define KBD_STAT_PERR 0x80 /* Parity error */ + +#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF) + +/* + * Controller Mode Register Bits + */ + +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ +#define KBD_MODE_RFU 0x80 + +/* + * Mouse Commands + */ + +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_RESET 0xFF /* Reset aux device */ + +#define AUX_BUF_SIZE 2048 + +struct aux_queue { + unsigned long head; + unsigned long tail; + struct wait_queue *proc_list; + struct fasync_struct *fasync; + unsigned char buf[AUX_BUF_SIZE]; +}; diff -urN 2.3.29pre1/arch/i386/kernel/Makefile 2.3.29pre1-ikd/arch/i386/kernel/Makefile --- 2.3.29pre1/arch/i386/kernel/Makefile Sun Nov 21 03:20:16 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/Makefile Mon Nov 22 16:56:22 1999 @@ -59,4 +59,10 @@ O_OBJS += visws_apic.o endif +# Not safe to have tracing turned on in the init_task. That way lies deadlock. +ifeq ($(CONFIG_KERNEL_DEBUGGING),y) +init_task.o: init_task.c $(TOPDIR)/include/linux/sched.h + $(CC) $(CFLAGS:%-pg=%-g -c) $(EXTRA_CFLAGS) -c -o $@ $< +endif + include $(TOPDIR)/Rules.make diff -urN 2.3.29pre1/arch/i386/kernel/Makefile.orig 2.3.29pre1-ikd/arch/i386/kernel/Makefile.orig --- 2.3.29pre1/arch/i386/kernel/Makefile.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kernel/Makefile.orig Sun Nov 21 03:20:16 1999 @@ -0,0 +1,62 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o + +all: kernel.o head.o init_task.o + +O_TARGET := kernel.o +O_OBJS := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ + ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o +OX_OBJS := i386_ksyms.o +MX_OBJS := + +ifdef CONFIG_PCI +O_OBJS += pci-i386.o +ifdef CONFIG_VISWS +O_OBJS += pci-visws.o +else +O_OBJS += pci-pc.o +endif +endif + +ifdef CONFIG_MCA +O_OBJS += mca.o +endif + +ifeq ($(CONFIG_MTRR),y) +OX_OBJS += mtrr.o +else + ifeq ($(CONFIG_MTRR),m) + MX_OBJS += mtrr.o + endif +endif + +ifeq ($(CONFIG_APM),y) +OX_OBJS += apm.o +else + ifeq ($(CONFIG_APM),m) + MX_OBJS += apm.o + endif +endif + +ifdef CONFIG_SMP +O_OBJS += smp.o smpboot.o trampoline.o +endif + +ifdef CONFIG_X86_IO_APIC +O_OBJS += io_apic.o +endif + +ifdef CONFIG_X86_VISWS_APIC +O_OBJS += visws_apic.o +endif + +include $(TOPDIR)/Rules.make diff -urN 2.3.29pre1/arch/i386/kernel/entry.S 2.3.29pre1-ikd/arch/i386/kernel/entry.S --- 2.3.29pre1/arch/i386/kernel/entry.S Tue Nov 2 12:06:23 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/entry.S Mon Nov 22 16:56:22 1999 @@ -42,6 +42,7 @@ #include #include +#include #include #define ASSEMBLY #include @@ -182,6 +183,19 @@ GET_CURRENT(%ebx) jmp ret_from_sys_call +#if defined(CONFIG_KDB) +ENTRY(kdb_call) + pushl %eax # save orig EAX + SAVE_ALL + pushl %esp # struct pt_regs + pushl $0 # error_code + pushl $7 # KDB_REASON_INT + call kdb + addl $12,%esp # remove args + RESTORE_ALL + +#endif + /* * Return to user mode is not as complex as all this looks, * but we want the default path for a system call return to @@ -193,6 +207,13 @@ pushl %eax # save orig_eax SAVE_ALL GET_CURRENT(%ebx) +#ifdef CONFIG_DEBUG_MCOUNT + pushl %eax + pushl %ebx + call SYMBOL_NAME(mcount) + popl %ebx + popl %eax +#endif cmpl $(NR_syscalls),%eax jae badsys testb $0x20,flags(%ebx) # PF_TRACESYS @@ -203,6 +224,11 @@ .globl ret_from_sys_call .globl ret_from_intr ret_from_sys_call: +#ifdef CONFIG_DEBUG_MCOUNT + pushl %eax + call SYMBOL_NAME(mcount) + popl %eax +#endif movl SYMBOL_NAME(bh_mask),%eax andl SYMBOL_NAME(bh_active),%eax jne handle_bottom_half @@ -220,16 +246,35 @@ testl $(VM_MASK),EFLAGS(%esp) movl %esp,%eax jne v86_signal_return +#ifndef CONFIG_KERNEL_DEBUGGING xorl %edx,%edx +#else + pushl $0 + pushl %eax +#endif call SYMBOL_NAME(do_signal) +#ifdef CONFIG_KERNEL_DEBUGGING + addl $8,%esp +#endif jmp restore_all ALIGN v86_signal_return: +#ifdef CONFIG_KERNEL_DEBUGGING + pushl %eax +#endif call SYMBOL_NAME(save_v86_state) movl %eax,%esp +#ifndef CONFIG_KERNEL_DEBUGGING xorl %edx,%edx +#else + pushl $0 + pushl %eax +#endif call SYMBOL_NAME(do_signal) +#ifdef CONFIG_KERNEL_DEBUGGING + addl $8,%esp +#endif jmp restore_all ALIGN diff -urN 2.3.29pre1/arch/i386/kernel/i386_ksyms.c 2.3.29pre1-ikd/arch/i386/kernel/i386_ksyms.c --- 2.3.29pre1/arch/i386/kernel/i386_ksyms.c Sun Nov 21 03:20:16 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/i386_ksyms.c Mon Nov 22 16:56:22 1999 @@ -19,6 +19,9 @@ #include #include #include +#if defined(CONFIG_KDB) +#include +#endif extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -127,6 +130,20 @@ #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); +#endif + +#if defined(CONFIG_KDB) +EXPORT_SYMBOL(kdb_register); +EXPORT_SYMBOL(kdb_unregister); +EXPORT_SYMBOL(kdbgetword); +EXPORT_SYMBOL(kdbgetularg); +EXPORT_SYMBOL(kdbgetenv); +EXPORT_SYMBOL(kdbgetintenv); +EXPORT_SYMBOL(kdbgetaddrarg); +EXPORT_SYMBOL(kdb); +EXPORT_SYMBOL(kdbgetsymval); +EXPORT_SYMBOL(kdbnearsym); +EXPORT_SYMBOL(kdb_printf); #endif EXPORT_SYMBOL(get_wchan); diff -urN 2.3.29pre1/arch/i386/kernel/i386_ksyms.c.orig 2.3.29pre1-ikd/arch/i386/kernel/i386_ksyms.c.orig --- 2.3.29pre1/arch/i386/kernel/i386_ksyms.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kernel/i386_ksyms.c.orig Sun Nov 21 03:20:16 1999 @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void dump_thread(struct pt_regs *, struct user *); +extern int dump_fpu(elf_fpregset_t *); + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) +extern struct drive_info_struct drive_info; +EXPORT_SYMBOL(drive_info); +#endif + +/* platform dependent support */ +EXPORT_SYMBOL(boot_cpu_data); +EXPORT_SYMBOL(EISA_bus); +EXPORT_SYMBOL(MCA_bus); +EXPORT_SYMBOL(__verify_write); +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(__io_virt_debug); +EXPORT_SYMBOL(local_bh_count); +EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(acpi_idle); +EXPORT_SYMBOL(acpi_power_off); + +EXPORT_SYMBOL_NOVERS(__down_failed); +EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); +EXPORT_SYMBOL_NOVERS(__down_failed_trylock); +EXPORT_SYMBOL_NOVERS(__up_wakeup); +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); +EXPORT_SYMBOL(csum_partial_copy_generic); +/* Delay loops */ +EXPORT_SYMBOL(__udelay); +EXPORT_SYMBOL(__delay); +EXPORT_SYMBOL(__const_udelay); + +EXPORT_SYMBOL_NOVERS(__get_user_1); +EXPORT_SYMBOL_NOVERS(__get_user_2); +EXPORT_SYMBOL_NOVERS(__get_user_4); +EXPORT_SYMBOL_NOVERS(__put_user_1); +EXPORT_SYMBOL_NOVERS(__put_user_2); +EXPORT_SYMBOL_NOVERS(__put_user_4); + +EXPORT_SYMBOL(strtok); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strstr); + +EXPORT_SYMBOL(strncpy_from_user); +EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(clear_user); +EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(__generic_copy_from_user); +EXPORT_SYMBOL(__generic_copy_to_user); +EXPORT_SYMBOL(strnlen_user); + +#ifdef CONFIG_X86_USE_3DNOW +EXPORT_SYMBOL(_mmx_memcpy); +EXPORT_SYMBOL(mmx_clear_page); +EXPORT_SYMBOL(mmx_copy_page); +#endif + +#ifdef __SMP__ +EXPORT_SYMBOL(cpu_data); +EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(cpu_number_map); +EXPORT_SYMBOL(__cpu_logical_map); +EXPORT_SYMBOL(smp_num_cpus); +EXPORT_SYMBOL(cpu_present_map); +EXPORT_SYMBOL(cpu_online_map); + +/* Global SMP irq stuff */ +EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(synchronize_bh); +EXPORT_SYMBOL(global_bh_count); +EXPORT_SYMBOL(global_bh_lock); +EXPORT_SYMBOL(global_irq_holder); +EXPORT_SYMBOL(i386_bh_lock); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(smp_call_function); +#endif + +#ifdef CONFIG_MCA +/* Adapter probing and info methods. */ +EXPORT_SYMBOL(machine_id); +EXPORT_SYMBOL(mca_find_adapter); +EXPORT_SYMBOL(mca_write_pos); +EXPORT_SYMBOL(mca_read_pos); +EXPORT_SYMBOL(mca_read_stored_pos); +EXPORT_SYMBOL(mca_set_adapter_name); +EXPORT_SYMBOL(mca_get_adapter_name); +EXPORT_SYMBOL(mca_set_adapter_procfn); +EXPORT_SYMBOL(mca_isenabled); +EXPORT_SYMBOL(mca_isadapter); +EXPORT_SYMBOL(mca_mark_as_used); +EXPORT_SYMBOL(mca_mark_as_unused); +EXPORT_SYMBOL(mca_find_unused_adapter); +EXPORT_SYMBOL(mca_is_adapter_used); +#endif + +#ifdef CONFIG_VT +EXPORT_SYMBOL(screen_info); +#endif + +EXPORT_SYMBOL(get_wchan); diff -urN 2.3.29pre1/arch/i386/kernel/i8259.c 2.3.29pre1-ikd/arch/i386/kernel/i8259.c --- 2.3.29pre1/arch/i386/kernel/i8259.c Tue Oct 12 02:40:34 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/i8259.c Mon Nov 22 16:56:22 1999 @@ -80,6 +80,9 @@ BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) +#if defined(CONFIG_KDB) +BUILD_SMP_INTERRUPT(kdb_interrupt,KDB_VECTOR) +#endif BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) @@ -424,7 +427,11 @@ */ for (i = 0; i < NR_IRQS; i++) { int vector = FIRST_EXTERNAL_VECTOR + i; - if (vector != SYSCALL_VECTOR) + if ((vector != SYSCALL_VECTOR) +#if defined(CONFIG_KDB) + && (vector != KDBENTER_VECTOR) +#endif + ) set_intr_gate(vector, interrupt[i]); } @@ -454,6 +461,11 @@ /* IPI vectors for APIC spurious and error interrupts */ set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt); set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); + +#if defined(CONFIG_KDB) + /* IPI vector for Kernel Debugger */ + set_intr_gate(KDB_VECTOR, kdb_interrupt); +#endif #endif /* diff -urN 2.3.29pre1/arch/i386/kernel/irq.c 2.3.29pre1-ikd/arch/i386/kernel/irq.c --- 2.3.29pre1/arch/i386/kernel/irq.c Sun Nov 21 03:20:16 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/irq.c Mon Nov 22 16:56:22 1999 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -638,6 +639,7 @@ if (bh_active & bh_mask) do_bottom_half(); } + MCOUNT(); return 1; } @@ -831,6 +833,8 @@ */ rand_initialize_irq(irq); } + + MCOUNT(); /* * The following block of code has to be executed atomically diff -urN 2.3.29pre1/arch/i386/kernel/irq.c.orig 2.3.29pre1-ikd/arch/i386/kernel/irq.c.orig --- 2.3.29pre1/arch/i386/kernel/irq.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kernel/irq.c.orig Sun Nov 21 03:20:16 1999 @@ -0,0 +1,865 @@ +/* mostly architecture independent + some moved to i8259.c + the beautiful visws architecture code needs to be updated too. + and, finally, the BUILD_IRQ and SMP_BUILD macros in irq.h need fixed. + */ +/* + * linux/arch/i386/kernel/irq.c + * + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + */ + +/* + * IRQs are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; + +extern atomic_t nmi_counter[NR_CPUS]; + +/* + * Linux has a controller-independent x86 interrupt architecture. + * every controller has a 'controller-template', that is used + * by the main code to do the right thing. Each driver-visible + * interrupt source is transparently wired to the apropriate + * controller. Thus drivers need not be aware of the + * interrupt-controller. + * + * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC, + * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC. + * (IO-APICs assumed to be messaging to Pentium local-APICs) + * + * the code is designed to be easily extended with new/different + * interrupt controllers, without having to do assembly magic. + */ + +/* + * Micro-access to controllers is serialized over the whole + * system. We never hold this lock when we call the actual + * IRQ handler. + */ +spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; +/* + * Controller mappings for all interrupt sources: + */ +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = + { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; + +/* + * Special irq handlers. + */ + +void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } + +/* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ +/* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesnt deserve + * a generic callback i think. + */ +#if CONFIG_X86 + printk("unexpected IRQ trap at vector %02x\n", irq); +#ifdef __SMP__ + /* + * Currently unexpected vectors happen only on SMP and APIC. + * We _must_ ack these because every local APIC has only N + * irq slots per priority level, and a 'hanging, unacked' IRQ + * holds up an irq slot - in excessive cases (when multiple + * unexpected vectors occur) that might lock up the APIC + * completely. + */ + ack_APIC_irq(); +#endif +#endif +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +volatile unsigned long irq_err_count; + +/* + * Generic, controller-independent functions: + */ + +int get_irq_list(char *buf) +{ + int i, j; + struct irqaction * action; + char *p = buf; + + p += sprintf(p, " "); + for (j=0; jtypename); + p += sprintf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + p += sprintf(p, ", %s", action->name); + *p++ = '\n'; + } + p += sprintf(p, "NMI: "); + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + atomic_read(nmi_counter+cpu_logical_map(j))); + p += sprintf(p, "\n"); +#if CONFIG_SMP + p += sprintf(p, "LOC: "); + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + apic_timer_irqs[cpu_logical_map(j)]); + p += sprintf(p, "\n"); +#endif + p += sprintf(p, "ERR: %10lu\n", irq_err_count); + return p - buf; +} + + +/* + * Global interrupt locks for SMP. Allow interrupts to come in on any + * CPU, yet make cli/sti act globally to protect critical regions.. + */ +spinlock_t i386_bh_lock = SPIN_LOCK_UNLOCKED; + +#ifdef __SMP__ +unsigned char global_irq_holder = NO_PROC_ID; +unsigned volatile int global_irq_lock; +atomic_t global_irq_count; + +atomic_t global_bh_count; +atomic_t global_bh_lock; + +/* + * "global_cli()" is a special case, in that it can hold the + * interrupts disabled for a longish time, and also because + * we may be doing TLB invalidates when holding the global + * IRQ lock for historical reasons. Thus we may need to check + * SMP invalidate events specially by hand here (but not in + * any normal spinlocks) + */ +static inline void check_smp_invalidate(int cpu) +{ + if (test_bit(cpu, &smp_invalidate_needed)) { + struct mm_struct *mm = current->mm; + clear_bit(cpu, &smp_invalidate_needed); + if (mm) + atomic_set_mask(1 << cpu, &mm->cpu_vm_mask); + local_flush_tlb(); + } +} + +static void show(char * str) +{ + int i; + unsigned long *stack; + int cpu = smp_processor_id(); + + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [%d %d]\n", + atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); + printk("bh: %d [%d %d]\n", + atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]); + stack = (unsigned long *) &stack; + for (i = 40; i ; i--) { + unsigned long x = *++stack; + if (x > (unsigned long) &get_option && x < (unsigned long) &vsprintf) { + printk("<[%08lx]> ", x); + } + } +} + +#define MAXCOUNT 100000000 + +static inline void wait_on_bh(void) +{ + int count = MAXCOUNT; + do { + if (!--count) { + show("wait_on_bh"); + count = ~0; + } + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 0); +} + +/* + * I had a lockup scenario where a tight loop doing + * spin_unlock()/spin_lock() on CPU#1 was racing with + * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but + * apparently the spin_unlock() information did not make it + * through to CPU#0 ... nasty, is this by design, do we have to limit + * 'memory update oscillation frequency' artificially like here? + * + * Such 'high frequency update' races can be avoided by careful design, but + * some of our major constructs like spinlocks use similar techniques, + * it would be nice to clarify this issue. Set this define to 0 if you + * want to check whether your system freezes. I suspect the delay done + * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but + * i thought that such things are guaranteed by design, since we use + * the 'LOCK' prefix. + */ +#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 1 + +#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND +# define SYNC_OTHER_CORES(x) udelay(x+1) +#else +/* + * We have to allow irqs to arrive between __sti and __cli + */ +# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") +#endif + +static inline void wait_on_irq(int cpu) +{ + int count = MAXCOUNT; + + for (;;) { + + /* + * Wait until all interrupts are gone. Wait + * for bottom half handlers unless we're + * already executing in one.. + */ + if (!atomic_read(&global_irq_count)) { + if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) + break; + } + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + clear_bit(0,&global_irq_lock); + + for (;;) { + if (!--count) { + show("wait_on_irq"); + count = ~0; + } + __sti(); + SYNC_OTHER_CORES(cpu); + __cli(); + check_smp_invalidate(cpu); + if (atomic_read(&global_irq_count)) + continue; + if (global_irq_lock) + continue; + if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + continue; + if (!test_and_set_bit(0,&global_irq_lock)) + break; + } + } +} + +/* + * This is called when we want to synchronize with + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +void synchronize_bh(void) +{ + if (atomic_read(&global_bh_count) && !in_interrupt()) + wait_on_bh(); +} + +/* + * This is called when we want to synchronize with + * interrupts. We may for example tell a device to + * stop sending interrupts: but to make sure there + * are no interrupts that are executing on another + * CPU we need to call this function. + */ +void synchronize_irq(void) +{ + if (atomic_read(&global_irq_count)) { + /* Stupid approach */ + cli(); + sti(); + } +} + +static inline void get_irqlock(int cpu) +{ + if (test_and_set_bit(0,&global_irq_lock)) { + /* do we already hold the lock? */ + if ((unsigned char) cpu == global_irq_holder) + return; + /* Uhhuh.. Somebody else got it. Wait.. */ + do { + do { + check_smp_invalidate(cpu); + } while (test_bit(0,&global_irq_lock)); + } while (test_and_set_bit(0,&global_irq_lock)); + } + /* + * We also to make sure that nobody else is running + * in an interrupt context. + */ + wait_on_irq(cpu); + + /* + * Ok, finally.. + */ + global_irq_holder = cpu; +} + +#define EFLAGS_IF_SHIFT 9 + +/* + * A global "cli()" while in an interrupt context + * turns into just a local cli(). Interrupts + * should use spinlocks for the (very unlikely) + * case that they ever want to protect against + * each other. + * + * If we already have local interrupts disabled, + * this will not turn a local disable into a + * global one (problems with spinlocks: this makes + * save_flags+cli+sti usable inside a spinlock). + */ +void __global_cli(void) +{ + unsigned int flags; + + __save_flags(flags); + if (flags & (1 << EFLAGS_IF_SHIFT)) { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count[cpu]) + get_irqlock(cpu); + } +} + +void __global_sti(void) +{ + int cpu = smp_processor_id(); + + if (!local_irq_count[cpu]) + release_irqlock(cpu); + __sti(); +} + +/* + * SMP flags value to restore to: + * 0 - global cli + * 1 - global sti + * 2 - local cli + * 3 - local sti + */ +unsigned long __global_save_flags(void) +{ + int retval; + int local_enabled; + unsigned long flags; + + __save_flags(flags); + local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; + /* default to local */ + retval = 2 + local_enabled; + + /* check for global flags if we're not in an interrupt */ + if (!local_irq_count[smp_processor_id()]) { + if (local_enabled) + retval = 1; + if (global_irq_holder == (unsigned char) smp_processor_id()) + retval = 0; + } + return retval; +} + +void __global_restore_flags(unsigned long flags) +{ + switch (flags) { + case 0: + __global_cli(); + break; + case 1: + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); + break; + default: + printk("global_restore_flags: %08lx (%08lx)\n", + flags, (&flags)[-1]); + } +} + +#endif + +/* + * This should really return information about whether + * we should do bottom half handling etc. Right now we + * end up _always_ checking the bottom half, which is a + * waste of time and is not what some drivers would + * prefer. + */ +int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) +{ + int status; + int cpu = smp_processor_id(); + + irq_enter(cpu, irq); + + status = 1; /* Force the "do bottom halves" bit */ + + if (!(action->flags & SA_INTERRUPT)) + __sti(); + + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); + + irq_exit(cpu, irq); + + return status; +} + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ +void disable_irq_nosync(unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&irq_controller_lock, flags); + if (!irq_desc[irq].depth++) { + irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].handler->disable(irq); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +/* + * Synchronous version of the above, making sure the IRQ is + * no longer running on any other IRQ.. + */ +void disable_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + + if (!local_irq_count[smp_processor_id()]) { + do { + barrier(); + } while (irq_desc[irq].status & IRQ_INPROGRESS); + } +} + +void enable_irq(unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&irq_controller_lock, flags); + switch (irq_desc[irq].depth) { + case 1: { + unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED; + irq_desc[irq].status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + irq_desc[irq].status = status | IRQ_REPLAY; + hw_resend_irq(irq_desc[irq].handler,irq); + } + irq_desc[irq].handler->enable(irq); + /* fall-through */ + } + default: + irq_desc[irq].depth--; + break; + case 0: + printk("enable_irq() unbalanced from %p\n", + __builtin_return_address(0)); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ +asmlinkage unsigned int do_IRQ(struct pt_regs regs) +{ + /* + * We ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + * + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ + int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code */ + int cpu = smp_processor_id(); + irq_desc_t *desc; + struct irqaction * action; + unsigned int status; + + kstat.irqs[cpu][irq]++; + desc = irq_desc + irq; + spin_lock(&irq_controller_lock); + desc->handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + spin_unlock(&irq_controller_lock); + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (!action) + return 1; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + handle_IRQ_event(irq, ®s, action); + spin_lock(&irq_controller_lock); + + if (!(desc->status & IRQ_PENDING)) + break; + desc->status &= ~IRQ_PENDING; + spin_unlock(&irq_controller_lock); + } + desc->status &= ~IRQ_INPROGRESS; + if (!(desc->status & IRQ_DISABLED)) + desc->handler->end(irq); + spin_unlock(&irq_controller_lock); + + /* + * This should be conditional: we should really get + * a return code from the irq handler to tell us + * whether the handler wants us to do software bottom + * half handling or not.. + */ + if (1) { + if (bh_active & bh_mask) + do_bottom_half(); + } + return 1; +} + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + +#if 1 + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if (irqflags & SA_SHIRQ) { + if (!dev_id) + printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + } +#endif + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + spin_lock_irqsave(&irq_controller_lock,flags); + p = &irq_desc[irq].action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!irq_desc[irq].action) { + irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].handler->shutdown(irq); + } + spin_unlock_irqrestore(&irq_controller_lock,flags); + + /* Wait to make sure it's not being used on another CPU */ + while (irq_desc[irq].status & IRQ_INPROGRESS) + barrier(); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&irq_controller_lock,flags); + return; + } +} + +/* + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. + */ +unsigned long probe_irq_on(void) +{ + unsigned int i; + unsigned long delay; + + /* + * first, enable any unassigned irqs + */ + spin_lock_irq(&irq_controller_lock); + for (i = NR_IRQS-1; i > 0; i--) { + if (!irq_desc[i].action) { + irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING; + if(irq_desc[i].handler->startup(i)) + irq_desc[i].status |= IRQ_PENDING; + } + } + spin_unlock_irq(&irq_controller_lock); + + /* + * Wait for spurious interrupts to trigger + */ + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ synchronize_irq(); + + /* + * Now filter out any obviously spurious interrupts + */ + spin_lock_irq(&irq_controller_lock); + for (i=0; ishutdown(i); + } + } + spin_unlock_irq(&irq_controller_lock); + + return 0x12345678; +} + +int probe_irq_off(unsigned long unused) +{ + int i, irq_found, nr_irqs; + + if (unused != 0x12345678) + printk("Bad IRQ probe from %lx\n", (&unused)[-1]); + + nr_irqs = 0; + irq_found = 0; + spin_lock_irq(&irq_controller_lock); + for (i=0; ishutdown(i); + } + spin_unlock_irq(&irq_controller_lock); + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; +} + +/* this was setup_x86_irq but it seems pretty generic */ +int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&irq_controller_lock,flags); + p = &irq_desc[irq].action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&irq_controller_lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + irq_desc[irq].depth = 0; + irq_desc[irq].status &= ~IRQ_DISABLED; + irq_desc[irq].handler->startup(irq); + } + spin_unlock_irqrestore(&irq_controller_lock,flags); + return 0; +} + diff -urN 2.3.29pre1/arch/i386/kernel/process.c 2.3.29pre1-ikd/arch/i386/kernel/process.c --- 2.3.29pre1/arch/i386/kernel/process.c Sun Nov 21 03:20:17 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/process.c Mon Nov 22 16:56:22 1999 @@ -569,7 +569,7 @@ * more flexibility. */ extern int cpus_initialized; -void __switch_to(struct task_struct *prev_p, struct task_struct *next_p) +void STDCALL(__switch_to(struct task_struct *prev_p, struct task_struct *next_p)) { struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; diff -urN 2.3.29pre1/arch/i386/kernel/process.c.orig 2.3.29pre1-ikd/arch/i386/kernel/process.c.orig --- 2.3.29pre1/arch/i386/kernel/process.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kernel/process.c.orig Sun Nov 21 03:20:17 1999 @@ -0,0 +1,721 @@ +/* + * linux/arch/i386/kernel/process.c + * + * Copyright (C) 1995 Linus Torvalds + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MATH_EMULATION +#include +#endif + +#include + +asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + +int hlt_counter=0; + +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + +/* + * Powermanagement idle function, if any.. + */ +void (*acpi_idle)(void) = NULL; + +/* + * Power off function, if any + */ +void (*acpi_power_off)(void) = NULL; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + init_idle(); + current->priority = 0; + current->counter = -100; + + while (1) { + while (!current->need_resched) { + if (!current_cpu_data.hlt_works_ok) + continue; + if (hlt_counter) + continue; + asm volatile("sti ; hlt" : : : "memory"); + } + schedule(); + check_pgt_cache(); + if (acpi_idle) + acpi_idle(); + } +} + +/* + * This routine reboots the machine by asking the keyboard + * controller to pulse the reset-line low. We try that for a while, + * and if it doesn't work, we do some other stupid things. + */ + +static long no_idt[2] = {0, 0}; +static int reboot_mode = 0; +static int reboot_thru_bios = 0; + +static int __init reboot_setup(char *str) +{ + while(1) { + switch (*str) { + case 'w': /* "warm" reboot (no memory testing etc) */ + reboot_mode = 0x1234; + break; + case 'c': /* "cold" reboot (with memory testing etc) */ + reboot_mode = 0x0; + break; + case 'b': /* "bios" reboot by jumping through the BIOS */ + reboot_thru_bios = 1; + break; + case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ + reboot_thru_bios = 0; + break; + } + if((str = strchr(str,',')) != NULL) + str++; + else + break; + } + return 1; +} + +__setup("reboot=", reboot_setup); + +/* The following code and data reboots the machine by switching to real + mode and jumping to the BIOS reset entry point, as if the CPU has + really been reset. The previous version asked the keyboard + controller to pulse the CPU reset line, which is more thorough, but + doesn't work with at least one type of 486 motherboard. It is easy + to stop this code working; hence the copious comments. */ + +static unsigned long long +real_mode_gdt_entries [3] = +{ + 0x0000000000000000ULL, /* Null descriptor */ + 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ +}; + +static struct +{ + unsigned short size __attribute__ ((packed)); + unsigned long long * base __attribute__ ((packed)); +} +real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, +real_mode_idt = { 0x3ff, 0 }; + +/* This is 16-bit protected mode code to disable paging and the cache, + switch to real mode and jump to the BIOS reset code. + + The instruction that switches to real mode by writing to CR0 must be + followed immediately by a far jump instruction, which set CS to a + valid value for real mode, and flushes the prefetch queue to avoid + running instructions that have already been decoded in protected + mode. + + Clears all the flags except ET, especially PG (paging), PE + (protected-mode enable) and TS (task switch for coprocessor state + save). Flushes the TLB after paging has been disabled. Sets CD and + NW, to disable the cache on a 486, and invalidates the cache. This + is more like the state of a 486 after reset. I don't know if + something else should be done for other chips. + + More could be done here to set up the registers as if a CPU reset had + occurred; hopefully real BIOSs don't assume much. */ + +static unsigned char real_mode_switch [] = +{ + 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ + 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ + 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ + 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ + 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ + 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ + 0x74, 0x02, /* jz f */ + 0x0f, 0x08, /* invd */ + 0x24, 0x10, /* f: andb $0x10,al */ + 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ +}; + +static inline void kb_wait(void) +{ + int i; + + for (i=0; i<0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +void machine_restart(char * __unused) +{ +#if __SMP__ + /* + * turn off the IO-APIC, so we can do a clean reboot + */ + init_pic_mode(); +#endif + + if(!reboot_thru_bios) { + /* rebooting needs to touch the page at absolute addr 0 */ + *((unsigned short *)__va(0x472)) = reboot_mode; + for (;;) { + int i; + for (i=0; i<100; i++) { + kb_wait(); + udelay(50); + outb(0xfe,0x64); /* pulse reset low */ + udelay(50); + } + /* That didn't work - force a triple fault.. */ + __asm__ __volatile__("lidt %0": :"m" (no_idt)); + __asm__ __volatile__("int3"); + } + } + + cli(); + + /* Write zero to CMOS register number 0x0f, which the BIOS POST + routine will recognize as telling it to do a proper reboot. (Well + that's what this book in front of me says -- it may only apply to + the Phoenix BIOS though, it's not clear). At the same time, + disable NMIs by setting the top bit in the CMOS address register, + as we're about to do peculiar things to the CPU. I'm not sure if + `outb_p' is needed instead of just `outb'. Use it to be on the + safe side. */ + + outb_p (0x8f, 0x70); + outb_p (0x00, 0x71); + + /* Remap the kernel at virtual address zero, as well as offset zero + from the kernel segment. This assumes the kernel segment starts at + virtual address PAGE_OFFSET. */ + + memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, + sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + + /* Make sure the first page is mapped to the start of physical memory. + It is normally not mapped, to trap kernel NULL pointer dereferences. */ + + pg0[0] = _PAGE_RW | _PAGE_PRESENT; + + /* + * Use `swapper_pg_dir' as our page directory. + */ + asm volatile("movl %0,%%cr3": :"r" (__pa(swapper_pg_dir))); + + /* Write 0x1234 to absolute memory location 0x472. The BIOS reads + this on booting to tell it to "Bypass memory test (also warm + boot)". This seems like a fairly standard thing that gets set by + REBOOT.COM programs, and the previous reset routine did this + too. */ + + *((unsigned short *)0x472) = reboot_mode; + + /* For the switch to real mode, copy some code to low memory. It has + to be in the first 64k because it is running in 16-bit mode, and it + has to have the same physical and virtual address, because it turns + off paging. Copy it near the end of the first page, out of the way + of BIOS variables. */ + + memcpy ((void *) (0x1000 - sizeof (real_mode_switch)), + real_mode_switch, sizeof (real_mode_switch)); + + /* Set up the IDT for real mode. */ + + __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); + + /* Set up a GDT from which we can load segment descriptors for real + mode. The GDT is not used in real mode; it is just needed here to + prepare the descriptors. */ + + __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt)); + + /* Load the data segment registers, and thus the descriptors ready for + real mode. The base address of each segment is 0x100, 16 times the + selector value being loaded here. This is so that the segment + registers don't have to be reloaded after switching to real mode: + the values are consistent for real mode operation already. */ + + __asm__ __volatile__ ("movl $0x0010,%%eax\n" + "\tmovl %%ax,%%ds\n" + "\tmovl %%ax,%%es\n" + "\tmovl %%ax,%%fs\n" + "\tmovl %%ax,%%gs\n" + "\tmovl %%ax,%%ss" : : : "eax"); + + /* Jump to the 16-bit code that we copied earlier. It disables paging + and the cache, switches to real mode, and jumps to the BIOS reset + entry point. */ + + __asm__ __volatile__ ("ljmp $0x0008,%0" + : + : "i" ((void *) (0x1000 - sizeof (real_mode_switch)))); +} + +void machine_halt(void) +{ +} + +void machine_power_off(void) +{ + if (acpi_power_off) + acpi_power_off(); +} + + +void show_regs(struct pt_regs * regs) +{ + long cr0 = 0L, cr2 = 0L, cr3 = 0L; + + printk("\n"); + printk("EIP: %04x:[<%08lx>]",0xffff & regs->xcs,regs->eip); + if (regs->xcs & 3) + printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); + printk(" EFLAGS: %08lx\n",regs->eflags); + printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", + regs->eax,regs->ebx,regs->ecx,regs->edx); + printk("ESI: %08lx EDI: %08lx EBP: %08lx", + regs->esi, regs->edi, regs->ebp); + printk(" DS: %04x ES: %04x\n", + 0xffff & regs->xds,0xffff & regs->xes); + + __asm__("movl %%cr0, %0": "=r" (cr0)); + __asm__("movl %%cr2, %0": "=r" (cr2)); + __asm__("movl %%cr3, %0": "=r" (cr3)); + printk("CR0: %08lx CR2: %08lx CR3: %08lx\n", cr0, cr2, cr3); +} + +/* + * No need to lock the MM as we are the last user + */ +void release_segments(struct mm_struct *mm) +{ + void * ldt = mm->segments; + + /* + * free the LDT + */ + if (ldt) { + mm->segments = NULL; + clear_LDT(); + vfree(ldt); + } +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval, d0; + + __asm__ __volatile__( + "movl %%esp,%%esi\n\t" + "int $0x80\n\t" /* Linux/i386 system call */ + "cmpl %%esp,%%esi\n\t" /* child or parent? */ + "je 1f\n\t" /* parent - jump */ + /* Load the argument into eax, and push it. That way, it does + * not matter whether the called function is compiled with + * -mregparm or not. */ + "movl %4,%%eax\n\t" + "pushl %%eax\n\t" + "call *%5\n\t" /* call fn */ + "movl %3,%0\n\t" /* exit */ + "int $0x80\n" + "1:\t" + :"=&a" (retval), "=&S" (d0) + :"0" (__NR_clone), "i" (__NR_exit), + "r" (arg), "r" (fn), + "b" (flags | CLONE_VM) + : "memory"); + return retval; +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ + /* nothing to do ... */ +} + +void flush_thread(void) +{ + struct task_struct *tsk = current; + + memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); + /* + * Forget coprocessor state.. + */ + clear_fpu(tsk); + tsk->used_math = 0; +} + +void release_thread(struct task_struct *dead_task) +{ + if (dead_task->mm) { + void * ldt = dead_task->mm->segments; + + // temporary debugging check + if (ldt) { + printk("WARNING: dead process %8s still has LDT? <%p>\n", + dead_task->comm, ldt); + BUG(); + } + } +} + +/* + * we do not have to muck with descriptors here, that is + * done in switch_mm() as needed. + */ +void copy_segments(struct task_struct *p, struct mm_struct *new_mm) +{ + struct mm_struct * old_mm = current->mm; + void * old_ldt = old_mm->segments, * ldt = old_ldt; + + if (!old_mm->segments) { + /* + * default LDT - use the one from init_task + */ + new_mm->segments = NULL; + return; + } + + /* + * Completely new LDT, we initialize it from the parent: + */ + ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); + if (!ldt) + printk(KERN_WARNING "ldt allocation failed\n"); + else + memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); + new_mm->segments = ldt; + return; +} + +/* + * Save a segment. + */ +#define savesegment(seg,value) \ + asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value))) + +int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + + childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1; + *childregs = *regs; + childregs->eax = 0; + childregs->esp = esp; + + p->thread.esp = (unsigned long) childregs; + p->thread.esp0 = (unsigned long) (childregs+1); + + p->thread.eip = (unsigned long) ret_from_fork; + + savesegment(fs,p->thread.fs); + savesegment(gs,p->thread.gs); + + unlazy_fpu(current); + p->thread.i387 = current->thread.i387; + + return 0; +} + +/* + * fill in the FPU structure for a core dump. + */ +int dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu) +{ + int fpvalid; + struct task_struct *tsk = current; + + fpvalid = tsk->used_math; + if (fpvalid) { + unlazy_fpu(tsk); + memcpy(fpu,&tsk->thread.i387.hard,sizeof(*fpu)); + } + + return fpvalid; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + int i; + +/* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + for (i = 0; i < 8; i++) + dump->u_debugreg[i] = current->thread.debugreg[i]; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->regs.ebx = regs->ebx; + dump->regs.ecx = regs->ecx; + dump->regs.edx = regs->edx; + dump->regs.esi = regs->esi; + dump->regs.edi = regs->edi; + dump->regs.ebp = regs->ebp; + dump->regs.eax = regs->eax; + dump->regs.ds = regs->xds; + dump->regs.es = regs->xes; + savesegment(fs,dump->regs.fs); + savesegment(gs,dump->regs.gs); + dump->regs.orig_eax = regs->orig_eax; + dump->regs.eip = regs->eip; + dump->regs.cs = regs->xcs; + dump->regs.eflags = regs->eflags; + dump->regs.esp = regs->esp; + dump->regs.ss = regs->xss; + + dump->u_fpvalid = dump_fpu (regs, &dump->i387); +} + +/* + * This special macro can be used to load a debugging register + */ +#define loaddebug(thread,register) \ + __asm__("movl %0,%%db" #register \ + : /* no output */ \ + :"r" (thread->debugreg[register])) + +/* + * switch_to(x,yn) should switch tasks from x to y. + * + * We fsave/fwait so that an exception goes off at the right time + * (as a call from the fsave or fwait in effect) rather than to + * the wrong process. Lazy FP saving no longer makes any sense + * with modern CPU's, and this simplifies a lot of things (SMP + * and UP become the same). + * + * NOTE! We used to use the x86 hardware context switching. The + * reason for not using it any more becomes apparent when you + * try to recover gracefully from saved state that is no longer + * valid (stale segment register values in particular). With the + * hardware task-switch, there is no way to fix up bad state in + * a reasonable manner. + * + * The fact that Intel documents the hardware task-switching to + * be slow is a fairly red herring - this code is not noticeably + * faster. However, there _is_ some room for improvement here, + * so the performance issues may eventually be a valid point. + * More important, however, is the fact that this allows us much + * more flexibility. + */ +extern int cpus_initialized; +void __switch_to(struct task_struct *prev_p, struct task_struct *next_p) +{ + struct thread_struct *prev = &prev_p->thread, + *next = &next_p->thread; + struct tss_struct *tss = init_tss + smp_processor_id(); + + unlazy_fpu(prev_p); + + /* + * Reload esp0, LDT and the page table pointer: + */ + tss->esp0 = next->esp0; + + /* + * Save away %fs and %gs. No need to save %es and %ds, as + * those are always kernel segments while inside the kernel. + */ + asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs)); + asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs)); + + /* + * Restore %fs and %gs. + */ + loadsegment(fs, next->fs); + loadsegment(gs, next->gs); + + /* + * Now maybe reload the debug registers + */ + if (next->debugreg[7]){ + loaddebug(next, 0); + loaddebug(next, 1); + loaddebug(next, 2); + loaddebug(next, 3); + /* no 4 and 5 */ + loaddebug(next, 6); + loaddebug(next, 7); + } + + if (prev->ioperm || next->ioperm) { + if (next->ioperm) { + /* + * 4 cachelines copy ... not good, but not that + * bad either. Anyone got something better? + * This only affects processes which use ioperm(). + * [Putting the TSSs into 4k-tlb mapped regions + * and playing VM tricks to switch the IO bitmap + * is not really acceptable.] + */ + memcpy(tss->io_bitmap, next->io_bitmap, + IO_BITMAP_SIZE*sizeof(unsigned long)); + tss->bitmap = IO_BITMAP_OFFSET; + } else + /* + * a bitmap offset pointing outside of the TSS limit + * causes a nicely controllable SIGSEGV if a process + * tries to use a port IO instruction. The first + * sys_ioperm() call sets up the bitmap properly. + */ + tss->bitmap = INVALID_IO_BITMAP_OFFSET; + } +} + +asmlinkage int sys_fork(struct pt_regs regs) +{ + return do_fork(SIGCHLD, regs.esp, ®s); +} + +asmlinkage int sys_clone(struct pt_regs regs) +{ + unsigned long clone_flags; + unsigned long newsp; + + clone_flags = regs.ebx; + newsp = regs.ecx; + if (!newsp) + newsp = regs.esp; + return do_fork(clone_flags, newsp, ®s); +} + +/* + * This is trivial, and on the face of it looks like it + * could equally well be done in user mode. + * + * Not so, for quite unobvious reasons - register pressure. + * In user mode vfork() cannot have a stack frame, and if + * done by calling the "clone()" system call directly, you + * do not have enough call-clobbered registers to hold all + * the information you need. + */ +asmlinkage int sys_vfork(struct pt_regs regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(struct pt_regs regs) +{ + int error; + char * filename; + + lock_kernel(); + filename = getname((char *) regs.ebx); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s); + if (error == 0) + current->flags &= ~PF_DTRACE; + putname(filename); +out: + unlock_kernel(); + return error; +} + +/* + * These bracket the sleeping functions.. + */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long ebp, esp, eip; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = (unsigned long)p; + esp = p->thread.esp; + if (!stack_page || esp < stack_page || esp > 8188+stack_page) + return 0; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + ebp = *(unsigned long *) esp; + do { + if (ebp < stack_page || ebp > 8184+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if (eip < first_sched || eip >= last_sched) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); + return 0; +} +#undef last_sched +#undef first_sched diff -urN 2.3.29pre1/arch/i386/kernel/semaphore.c 2.3.29pre1-ikd/arch/i386/kernel/semaphore.c --- 2.3.29pre1/arch/i386/kernel/semaphore.c Tue Sep 14 14:34:58 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/semaphore.c Mon Nov 22 16:56:22 1999 @@ -38,6 +38,10 @@ * we cannot lose wakeup events. */ +/* + * Semaphore deadlock detector. Copyright (C) 1999 Andrea Arcangeli + */ + void __up(struct semaphore *sem) { wake_up(&sem->wait); @@ -45,13 +49,30 @@ static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_SEMAPHORE_DEADLOCK +static void generate_oops (struct semaphore *sem) +{ + atomic_set (&sem->count, 9876); + wake_up (&sem->wait); +} +#endif + void __down(struct semaphore * sem) { +#ifdef CONFIG_SEMAPHORE_DEADLOCK + struct timer_list timer; +#endif struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE; add_wait_queue_exclusive(&sem->wait, &wait); +#ifdef CONFIG_SEMAPHORE_DEADLOCK + init_timer (&timer); + timer.expires = jiffies + HZ*20; + timer.data = (unsigned long) sem; + timer.function = (void (*)(unsigned long)) generate_oops; +#endif spin_lock_irq(&semaphore_lock); sem->sleepers++; for (;;) { @@ -68,7 +89,15 @@ sem->sleepers = 1; /* us - see -1 above */ spin_unlock_irq(&semaphore_lock); +#ifdef CONFIG_SEMAPHORE_DEADLOCK + add_timer (&timer); +#endif schedule(); +#ifdef CONFIG_SEMAPHORE_DEADLOCK + if (atomic_read (&sem->count) == 9876) + BUG(); + del_timer (&timer); +#endif tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE; spin_lock_irq(&semaphore_lock); } diff -urN 2.3.29pre1/arch/i386/kernel/smp.c 2.3.29pre1-ikd/arch/i386/kernel/smp.c --- 2.3.29pre1/arch/i386/kernel/smp.c Sun Nov 21 03:20:23 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/smp.c Mon Nov 22 16:56:22 1999 @@ -19,6 +19,10 @@ #include #include +#if defined(CONFIG_KDB) +#include +#endif + /* * Some notes on processor bugs: * @@ -112,6 +116,10 @@ static unsigned int cached_APIC_ICR; static unsigned int cached_APIC_ICR2; +#if defined(CONFIG_KDB) +unsigned long smp_kdb_wait = 0; /* Bitmask of waiters */ +#endif + /* * Caches reserved bits, APIC reads are (mildly) expensive * and force otherwise unnecessary CPU synchronization. @@ -860,8 +868,10 @@ * updated with atomic operations). This is especially * useful with a profiling multiplier != 1 */ +#ifndef CONFIG_PROFILE_GCC if (!user) x86_do_profile(regs->eip); +#endif if (--prof_counter[cpu] <= 0) { int system = 1 - user; @@ -922,6 +932,21 @@ */ } + +#if defined(CONFIG_KDB) +void smp_kdb_stop(int all) +{ + if (all) { + smp_kdb_wait = 0xffffffff; + clear_bit(smp_processor_id(), &smp_kdb_wait); + send_IPI_allbutself(KDB_VECTOR); + } else { + set_bit(smp_processor_id(), &smp_kdb_wait); + send_IPI_self(KDB_VECTOR); + } +} +#endif + /* * Local APIC timer interrupt. This is the most natural way for doing * local interrupts, but local timer interrupts can be emulated by @@ -946,4 +971,49 @@ ack_APIC_irq(); smp_local_timer_interrupt(regs); } + +#if defined(CONFIG_KDB) +asmlinkage void smp_kdb_interrupt(int a) +{ + /* + * The stub function which calls this routine pushes + * the register context on the stack prior to calling + * this routine. No arguments are pushed on the stack, + * so taking the address of a non-existant first argument + * will obtain the address of the preserved register context + * + * This is a gross hack, but it works and doesn't require + * changes to BUILD_SMP_INTERRUPT. + */ + struct pt_regs *regs = &a; + extern unsigned long smp_kdb_wait; + extern int kdb_new_cpu; + ack_APIC_irq(); + + /* + * Wait for kdb to set us free. + */ +#if 0 + printk("stopping cpu %d for kdb\n", smp_processor_id()); +#endif + + while (test_bit(smp_processor_id(), &smp_kdb_wait)) + ; +#if 0 + printk("restarting cpu %d for kdb\n", smp_processor_id()); +#endif + + /* + * If we are the new CPU, call the kernel debugger here. + */ + if (kdb_new_cpu == smp_processor_id()) { + kdb(KDB_REASON_SWITCH, 0, regs); + } + + /* + * Re-establish any global breakpoint state + */ + kdb_global(smp_processor_id()); +} +#endif /* CONFIG_KDB */ diff -urN 2.3.29pre1/arch/i386/kernel/smp.c.orig 2.3.29pre1-ikd/arch/i386/kernel/smp.c.orig --- 2.3.29pre1/arch/i386/kernel/smp.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kernel/smp.c.orig Sun Nov 21 03:20:23 1999 @@ -0,0 +1,949 @@ +/* + * Intel SMP support routines. + * + * (c) 1995 Alan Cox, Building #3 + * (c) 1998-99 Ingo Molnar + * + * This code is released under the GNU public license version 2 or + * later. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +/* + * Some notes on processor bugs: + * + * Pentium, Pentium Pro, II, III (and all CPUs) have bugs. + * The Linux implications for SMP are handled as follows: + * + * Pentium III / [Xeon] + * None of the E1AP-E3AP erratas are visible to the user. + * + * E1AP. see PII A1AP + * E2AP. see PII A2AP + * E3AP. see PII A3AP + * + * Pentium II / [Xeon] + * None of the A1AP-A3AP erratas are visible to the user. + * + * A1AP. see PPro 1AP + * A2AP. see PPro 2AP + * A3AP. see PPro 7AP + * + * Pentium Pro + * None of 1AP-9AP erratas are visible to the normal user, + * except occasional delivery of 'spurious interrupt' as trap #15. + * This is very rare and a non-problem. + * + * 1AP. Linux maps APIC as non-cacheable + * 2AP. worked around in hardware + * 3AP. fixed in C0 and above steppings microcode update. + * Linux does not use excessive STARTUP_IPIs. + * 4AP. worked around in hardware + * 5AP. symmetric IO mode (normal Linux operation) not affected. + * 'noapic' mode has vector 0xf filled out properly. + * 6AP. 'noapic' mode might be affected - fixed in later steppings + * 7AP. We do not assume writes to the LVT deassering IRQs + * 8AP. We do not enable low power mode (deep sleep) during MP bootup + * 9AP. We do not use mixed mode + * + * Pentium + * There is a marginal case where REP MOVS on 100MHz SMP + * machines with B stepping processors can fail. XXX should provide + * an L1cache=Writethrough or L1cache=off option. + * + * B stepping CPUs may hang. There are hardware work arounds + * for this. We warn about it in case your board doesnt have the work + * arounds. Basically thats so I can tell anyone with a B stepping + * CPU and SMP problems "tough". + * + * Specific items [From Pentium Processor Specification Update] + * + * 1AP. Linux doesn't use remote read + * 2AP. Linux doesn't trust APIC errors + * 3AP. We work around this + * 4AP. Linux never generated 3 interrupts of the same priority + * to cause a lost local interrupt. + * 5AP. Remote read is never used + * 6AP. not affected - worked around in hardware + * 7AP. not affected - worked around in hardware + * 8AP. worked around in hardware - we get explicit CS errors if not + * 9AP. only 'noapic' mode affected. Might generate spurious + * interrupts, we log only the first one and count the + * rest silently. + * 10AP. not affected - worked around in hardware + * 11AP. Linux reads the APIC between writes to avoid this, as per + * the documentation. Make sure you preserve this as it affects + * the C stepping chips too. + * 12AP. not affected - worked around in hardware + * 13AP. not affected - worked around in hardware + * 14AP. we always deassert INIT during bootup + * 15AP. not affected - worked around in hardware + * 16AP. not affected - worked around in hardware + * 17AP. not affected - worked around in hardware + * 18AP. not affected - worked around in hardware + * 19AP. not affected - worked around in BIOS + * + * If this sounds worrying believe me these bugs are either ___RARE___, + * or are signal timing bugs worked around in hardware and there's + * about nothing of note with C stepping upwards. + */ + +/* The 'big kernel lock' */ +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; + +volatile unsigned long smp_invalidate_needed; + +/* + * the following functions deal with sending IPIs between CPUs. + * + * We use 'broadcast', CPU->CPU IPIs and self-IPIs too. + */ + +static unsigned int cached_APIC_ICR; +static unsigned int cached_APIC_ICR2; + +/* + * Caches reserved bits, APIC reads are (mildly) expensive + * and force otherwise unnecessary CPU synchronization. + * + * (We could cache other APIC registers too, but these are the + * main ones used in RL.) + */ +#define slow_ICR (apic_read(APIC_ICR) & ~0xFDFFF) +#define slow_ICR2 (apic_read(APIC_ICR2) & 0x00FFFFFF) + +void cache_APIC_registers (void) +{ + cached_APIC_ICR = slow_ICR; + cached_APIC_ICR2 = slow_ICR2; + mb(); +} + +static inline unsigned int __get_ICR (void) +{ +#if FORCE_READ_AROUND_WRITE + /* + * Wait for the APIC to become ready - this should never occur. It's + * a debugging check really. + */ + int count = 0; + unsigned int cfg; + + while (count < 1000) + { + cfg = slow_ICR; + if (!(cfg&(1<<12))) + return cfg; + printk("CPU #%d: ICR still busy [%08x]\n", + smp_processor_id(), cfg); + irq_err_count++; + count++; + udelay(10); + } + printk("CPU #%d: previous IPI still not cleared after 10mS\n", + smp_processor_id()); + return cfg; +#else + return cached_APIC_ICR; +#endif +} + +static inline unsigned int __get_ICR2 (void) +{ +#if FORCE_READ_AROUND_WRITE + return slow_ICR2; +#else + return cached_APIC_ICR2; +#endif +} + +#define LOGICAL_DELIVERY 1 + +static inline int __prepare_ICR (unsigned int shortcut, int vector) +{ + unsigned int cfg; + + cfg = __get_ICR(); + cfg |= APIC_DEST_DM_FIXED|shortcut|vector +#if LOGICAL_DELIVERY + |APIC_DEST_LOGICAL +#endif + ; + + return cfg; +} + +static inline int __prepare_ICR2 (unsigned int dest) +{ + unsigned int cfg; + + cfg = __get_ICR2(); +#if LOGICAL_DELIVERY + cfg |= SET_APIC_DEST_FIELD((1< 1) + __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); +} + +static inline void send_IPI_all(int vector) +{ + __send_IPI_shortcut(APIC_DEST_ALLINC, vector); +} + +void send_IPI_self(int vector) +{ + __send_IPI_shortcut(APIC_DEST_SELF, vector); +} + +static inline void send_IPI_single(int dest, int vector) +{ + unsigned long cfg; +#if FORCE_READ_AROUND_WRITE + unsigned long flags; + + __save_flags(flags); + __cli(); +#endif + + /* + * prepare target chip field + */ + + cfg = __prepare_ICR2(dest); + apic_write(APIC_ICR2, cfg); + + /* + * program the ICR + */ + cfg = __prepare_ICR(0, vector); + + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ + apic_write(APIC_ICR, cfg); +#if FORCE_READ_AROUND_WRITE + __restore_flags(flags); +#endif +} + +/* + * This is fraught with deadlocks. Probably the situation is not that + * bad as in the early days of SMP, so we might ease some of the + * paranoia here. + */ +static void flush_tlb_others(unsigned int cpumask) +{ + int cpu = smp_processor_id(); + int stuck; + unsigned long flags; + + /* + * it's important that we do not generate any APIC traffic + * until the AP CPUs have booted up! + */ + cpumask &= cpu_online_map; + if (cpumask) { + atomic_set_mask(cpumask, &smp_invalidate_needed); + + /* + * Processors spinning on some lock with IRQs disabled + * will see this IRQ late. The smp_invalidate_needed + * map will ensure they don't do a spurious flush tlb + * or miss one. + */ + + __save_flags(flags); + __cli(); + + send_IPI_allbutself(INVALIDATE_TLB_VECTOR); + + /* + * Spin waiting for completion + */ + + stuck = 50000000; + while (smp_invalidate_needed) { + /* + * Take care of "crossing" invalidates + */ + if (test_bit(cpu, &smp_invalidate_needed)) { + struct mm_struct *mm = current->mm; + clear_bit(cpu, &smp_invalidate_needed); + if (mm) + atomic_set_mask(1 << cpu, &mm->cpu_vm_mask); + local_flush_tlb(); + } + --stuck; + if (!stuck) { + printk("stuck on TLB IPI wait (CPU#%d)\n",cpu); + break; + } + } + __restore_flags(flags); + } +} + +/* + * Smarter SMP flushing macros. + * c/o Linus Torvalds. + * + * These mean you can really definitely utterly forget about + * writing to user space from interrupts. (Its not allowed anyway). + */ +void flush_tlb_current_task(void) +{ + unsigned long vm_mask = 1 << current->processor; + struct mm_struct *mm = current->mm; + unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; + + mm->cpu_vm_mask = vm_mask; + flush_tlb_others(cpu_mask); + local_flush_tlb(); +} + +void flush_tlb_mm(struct mm_struct * mm) +{ + unsigned long vm_mask = 1 << current->processor; + unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; + + mm->cpu_vm_mask = 0; + if (current->active_mm == mm) { + mm->cpu_vm_mask = vm_mask; + local_flush_tlb(); + } + flush_tlb_others(cpu_mask); +} + +void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) +{ + unsigned long vm_mask = 1 << current->processor; + struct mm_struct *mm = vma->vm_mm; + unsigned long cpu_mask = mm->cpu_vm_mask & ~vm_mask; + + mm->cpu_vm_mask = 0; + if (current->active_mm == mm) { + __flush_tlb_one(va); + mm->cpu_vm_mask = vm_mask; + } + flush_tlb_others(cpu_mask); +} + +void flush_tlb_all(void) +{ + flush_tlb_others(~(1 << current->processor)); + local_flush_tlb(); +} + + +/* + * this function sends a 'reschedule' IPI to another CPU. + * it goes straight through and wastes no time serializing + * anything. Worst case is that we lose a reschedule ... + */ + +void smp_send_reschedule(int cpu) +{ + send_IPI_single(cpu, RESCHEDULE_VECTOR); +} + +/* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. + */ +static volatile struct call_data_struct { + void (*func) (void *info); + void *info; + atomic_t started; + atomic_t finished; + int wait; +} *call_data = NULL; + +/* + * this function sends a 'generic call function' IPI to all other CPUs + * in the system. + */ + +int smp_call_function (void (*func) (void *info), void *info, int nonatomic, + int wait) +/* + * [SUMMARY] Run a function on all other CPUs. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * If true, we might schedule away to lock the mutex + * If true, wait (atomically) until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. Does not return until + * remote CPUs are nearly ready to execute <> or are or have executed. + */ +{ + struct call_data_struct data; + int ret, cpus = smp_num_cpus-1; + static DECLARE_MUTEX(lock); + unsigned long timeout; + + if (nonatomic) + down(&lock); + else + if (down_trylock(&lock)) + return -EBUSY; + + if (call_data) // temporary debugging check + BUG(); + + call_data = &data; + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + mb(); + + /* Send a message to all other CPUs and wait for them to respond */ + send_IPI_allbutself(CALL_FUNCTION_VECTOR); + + /* Wait for response */ + timeout = jiffies + HZ; + while ((atomic_read(&data.started) != cpus) + && time_before(jiffies, timeout)) + barrier(); + ret = -ETIMEDOUT; + if (atomic_read(&data.started) != cpus) + goto out; + ret = 0; + if (wait) + while (atomic_read(&data.finished) != cpus) + barrier(); +out: + call_data = NULL; + up(&lock); + return 0; +} + +static void stop_this_cpu (void * dummy) +{ + /* + * Remove this CPU: + */ + clear_bit(smp_processor_id(), &cpu_online_map); + + if (cpu_data[smp_processor_id()].hlt_works_ok) + for(;;) __asm__("hlt"); + for (;;); +} + +/* + * this function calls the 'stop' function on all other CPUs in the system. + */ + +void smp_send_stop(void) +{ + smp_call_function(stop_this_cpu, NULL, 1, 0); +} + +/* + * Reschedule call back. Nothing to do, + * all the work is done automatically when + * we return from the interrupt. + */ +asmlinkage void smp_reschedule_interrupt(void) +{ + ack_APIC_irq(); +} + +/* + * Invalidate call-back. + * + * Mark the CPU as a VM user if there is a active + * thread holding on to an mm at this time. This + * allows us to optimize CPU cross-calls even in the + * presense of lazy TLB handling. + */ +asmlinkage void smp_invalidate_interrupt(void) +{ + struct task_struct *tsk = current; + unsigned int cpu = tsk->processor; + + if (test_and_clear_bit(cpu, &smp_invalidate_needed)) { + struct mm_struct *mm = tsk->mm; + if (mm) + atomic_set_mask(1 << cpu, &mm->cpu_vm_mask); + local_flush_tlb(); + } + ack_APIC_irq(); + +} + +asmlinkage void smp_call_function_interrupt(void) +{ + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int wait = call_data->wait; + + ack_APIC_irq(); + /* + * Notify initiating CPU that I've grabbed the data and am + * about to execute the function + */ + atomic_inc(&call_data->started); + /* + * At this point the structure may be out of scope unless wait==1 + */ + (*func)(info); + if (wait) + atomic_inc(&call_data->finished); +} + +/* + * This interrupt should _never_ happen with our APIC/SMP architecture + */ +asmlinkage void smp_spurious_interrupt(void) +{ + ack_APIC_irq(); + /* see sw-dev-man vol 3, chapter 7.4.13.5 */ + printk("spurious APIC interrupt on CPU#%d, should never happen.\n", + smp_processor_id()); +} + +/* + * This interrupt should never happen with our APIC/SMP architecture + */ + +static spinlock_t err_lock; + +asmlinkage void smp_error_interrupt(void) +{ + unsigned long v; + + spin_lock(&err_lock); + + v = apic_read(APIC_ESR); + printk("APIC error interrupt on CPU#%d, should never happen.\n", + smp_processor_id()); + printk("... APIC ESR0: %08lx\n", v); + + apic_write(APIC_ESR, 0); + v = apic_read(APIC_ESR); + printk("... APIC ESR1: %08lx\n", v); + + ack_APIC_irq(); + + irq_err_count++; + + spin_unlock(&err_lock); +} + +/* + * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts + * per second. We assume that the caller has already set up the local + * APIC. + * + * The APIC timer is not exactly sync with the external timer chip, it + * closely follows bus clocks. + */ + +int prof_multiplier[NR_CPUS] = { 1, }; +int prof_old_multiplier[NR_CPUS] = { 1, }; +int prof_counter[NR_CPUS] = { 1, }; + +/* + * The timer chip is already set up at HZ interrupts per second here, + * but we do not accept timer interrupts yet. We only allow the BP + * to calibrate. + */ +static unsigned int __init get_8254_timer_count(void) +{ + unsigned int count; + + outb_p(0x00, 0x43); + count = inb_p(0x40); + count |= inb_p(0x40) << 8; + + return count; +} + +void __init wait_8254_wraparound(void) +{ + unsigned int curr_count, prev_count=~0; + int delta; + + curr_count = get_8254_timer_count(); + + do { + prev_count = curr_count; + curr_count = get_8254_timer_count(); + delta = curr_count-prev_count; + + /* + * This limit for delta seems arbitrary, but it isn't, it's + * slightly above the level of error a buggy Mercury/Neptune + * chipset timer can cause. + */ + + } while (delta<300); +} + +/* + * This function sets up the local APIC timer, with a timeout of + * 'clocks' APIC bus clock. During calibration we actually call + * this function twice on the boot CPU, once with a bogus timeout + * value, second time for real. The other (noncalibrating) CPUs + * call this function only once, with the real, calibrated value. + * + * We do reads before writes even if unnecessary, to get around the + * P5 APIC double write bug. + */ + +#define APIC_DIVISOR 16 + +void __setup_APIC_LVTT(unsigned int clocks) +{ + unsigned int lvtt1_value, tmp_value; + + tmp_value = apic_read(APIC_LVTT); + lvtt1_value = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | + APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR; + apic_write(APIC_LVTT, lvtt1_value); + + /* + * Divide PICLK by 16 + */ + tmp_value = apic_read(APIC_TDCR); + apic_write(APIC_TDCR, (tmp_value + & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE)) + | APIC_TDR_DIV_16); + + tmp_value = apic_read(APIC_TMICT); + apic_write(APIC_TMICT, clocks/APIC_DIVISOR); +} + +void setup_APIC_timer(void * data) +{ + unsigned int clocks = (unsigned int) data, slice, t0, t1, nr; + unsigned long flags; + int delta; + + __save_flags(flags); + __sti(); + /* + * ok, Intel has some smart code in their APIC that knows + * if a CPU was in 'hlt' lowpower mode, and this increases + * its APIC arbitration priority. To avoid the external timer + * IRQ APIC event being in synchron with the APIC clock we + * introduce an interrupt skew to spread out timer events. + * + * The number of slices within a 'big' timeslice is smp_num_cpus+1 + */ + + slice = clocks / (smp_num_cpus+1); + nr = cpu_number_map[smp_processor_id()] + 1; + printk("cpu: %d, clocks: %d, slice: %d, nr: %d.\n", + smp_processor_id(), clocks, slice, nr); + /* + * Wait for IRQ0's slice: + */ + wait_8254_wraparound(); + + __setup_APIC_LVTT(clocks); + + t0 = apic_read(APIC_TMCCT)*APIC_DIVISOR; + do { + t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; + delta = (int)(t0 - t1 - slice*nr); + } while (delta < 0); + + __setup_APIC_LVTT(clocks); + + printk("CPU%d\n", + smp_processor_id(), t0, t1, delta, slice, clocks); + + __restore_flags(flags); +} + +/* + * In this function we calibrate APIC bus clocks to the external + * timer. Unfortunately we cannot use jiffies and the timer irq + * to calibrate, since some later bootup code depends on getting + * the first irq? Ugh. + * + * We want to do the calibration only once since we + * want to have local timer irqs syncron. CPUs connected + * by the same APIC bus have the very same bus frequency. + * And we want to have irqs off anyways, no accidental + * APIC irq that way. + */ + +int __init calibrate_APIC_clock(void) +{ + unsigned long long t1 = 0, t2 = 0; + long tt1, tt2; + long result; + int i; + const int LOOPS = HZ/10; + + printk("calibrating APIC timer ... "); + + /* + * Put whatever arbitrary (but long enough) timeout + * value into the APIC clock, we just want to get the + * counter running for calibration. + */ + __setup_APIC_LVTT(1000000000); + + /* + * The timer chip counts down to zero. Let's wait + * for a wraparound to start exact measurement: + * (the current tick might have been already half done) + */ + + wait_8254_wraparound(); + + /* + * We wrapped around just now. Let's start: + */ + if (cpu_has_tsc) + rdtscll(t1); + tt1 = apic_read(APIC_TMCCT); + + /* + * Let's wait LOOPS wraprounds: + */ + for (i = 0; i < LOOPS; i++) + wait_8254_wraparound(); + + tt2 = apic_read(APIC_TMCCT); + if (cpu_has_tsc) + rdtscll(t2); + + /* + * The APIC bus clock counter is 32 bits only, it + * might have overflown, but note that we use signed + * longs, thus no extra care needed. + * + * underflown to be exact, as the timer counts down ;) + */ + + result = (tt1-tt2)*APIC_DIVISOR/LOOPS; + + if (cpu_has_tsc) + printk("\n..... CPU clock speed is %ld.%04ld MHz.\n", + ((long)(t2-t1)/LOOPS)/(1000000/HZ), + ((long)(t2-t1)/LOOPS)%(1000000/HZ)); + + printk("..... host bus clock speed is %ld.%04ld MHz.\n", + result/(1000000/HZ), + result%(1000000/HZ)); + + return result; +} + +static unsigned int calibration_result; + +void __init setup_APIC_clocks(void) +{ + unsigned long flags; + + __save_flags(flags); + __cli(); + + calibration_result = calibrate_APIC_clock(); + + smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1); + + /* + * Now set up the timer for real. + */ + setup_APIC_timer((void *)calibration_result); + + __restore_flags(flags); +} + +/* + * the frequency of the profiling timer can be changed + * by writing a multiplier value into /proc/profile. + */ +int setup_profiling_timer(unsigned int multiplier) +{ + int i; + + /* + * Sanity check. [at least 500 APIC cycles should be + * between APIC interrupts as a rule of thumb, to avoid + * irqs flooding us] + */ + if ( (!multiplier) || (calibration_result/multiplier < 500)) + return -EINVAL; + + /* + * Set the new multiplier for each CPU. CPUs don't start using the + * new values until the next timer interrupt in which they do process + * accounting. At that time they also adjust their APIC timers + * accordingly. + */ + for (i = 0; i < NR_CPUS; ++i) + prof_multiplier[i] = multiplier; + + return 0; +} + +#undef APIC_DIVISOR + +/* + * Local timer interrupt handler. It does both profiling and + * process statistics/rescheduling. + * + * We do profiling in every local tick, statistics/rescheduling + * happen only every 'profiling multiplier' ticks. The default + * multiplier is 1 and it can be changed by writing the new multiplier + * value into /proc/profile. + */ + +inline void smp_local_timer_interrupt(struct pt_regs * regs) +{ + int user = (user_mode(regs) != 0); + int cpu = smp_processor_id(); + + /* + * The profiling function is SMP safe. (nothing can mess + * around with "current", and the profiling counters are + * updated with atomic operations). This is especially + * useful with a profiling multiplier != 1 + */ + if (!user) + x86_do_profile(regs->eip); + + if (--prof_counter[cpu] <= 0) { + int system = 1 - user; + struct task_struct * p = current; + + /* + * The multiplier may have changed since the last time we got + * to this point as a result of the user writing to + * /proc/profile. In this case we need to adjust the APIC + * timer accordingly. + * + * Interrupts are already masked off at this point. + */ + prof_counter[cpu] = prof_multiplier[cpu]; + if (prof_counter[cpu] != prof_old_multiplier[cpu]) { + __setup_APIC_LVTT(calibration_result/prof_counter[cpu]); + prof_old_multiplier[cpu] = prof_counter[cpu]; + } + + /* + * After doing the above, we need to make like + * a normal interrupt - otherwise timer interrupts + * ignore the global interrupt lock, which is the + * WrongThing (tm) to do. + */ + + irq_enter(cpu, 0); + update_one_process(p, 1, user, system, cpu); + if (p->pid) { + p->counter -= 1; + if (p->counter <= 0) { + p->counter = 0; + p->need_resched = 1; + } + if (p->priority < DEF_PRIORITY) { + kstat.cpu_nice += user; + kstat.per_cpu_nice[cpu] += user; + } else { + kstat.cpu_user += user; + kstat.per_cpu_user[cpu] += user; + } + kstat.cpu_system += system; + kstat.per_cpu_system[cpu] += system; + + } + irq_exit(cpu, 0); + } + + /* + * We take the 'long' return path, and there every subsystem + * grabs the apropriate locks (kernel lock/ irq lock). + * + * we might want to decouple profiling from the 'long path', + * and do the profiling totally in assembly. + * + * Currently this isn't too much of an issue (performance wise), + * we can take more than 100K local irqs per second on a 100 MHz P5. + */ +} + +/* + * Local APIC timer interrupt. This is the most natural way for doing + * local interrupts, but local timer interrupts can be emulated by + * broadcast interrupts too. [in case the hw doesnt support APIC timers] + * + * [ if a single-CPU system runs an SMP kernel then we call the local + * interrupt as well. Thus we cannot inline the local irq ... ] + */ +unsigned int apic_timer_irqs [NR_CPUS] = { 0, }; + +void smp_apic_timer_interrupt(struct pt_regs * regs) +{ + /* + * the NMI deadlock-detector uses this. + */ + apic_timer_irqs[smp_processor_id()]++; + + /* + * NOTE! We'd better ACK the irq immediately, + * because timer handling can be slow. + */ + ack_APIC_irq(); + smp_local_timer_interrupt(regs); +} + diff -urN 2.3.29pre1/arch/i386/kernel/time.c 2.3.29pre1-ikd/arch/i386/kernel/time.c --- 2.3.29pre1/arch/i386/kernel/time.c Tue Oct 12 02:40:34 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/time.c Mon Nov 22 16:56:22 1999 @@ -370,8 +370,10 @@ * system, in that case we have to call the local interrupt handler. */ #ifndef __SMP__ +#ifndef CONFIG_PROFILE_GCC if (!user_mode(regs)) x86_do_profile(regs->eip); +#endif #else if (!smp_found_config) smp_local_timer_interrupt(regs); diff -urN 2.3.29pre1/arch/i386/kernel/traps.c 2.3.29pre1-ikd/arch/i386/kernel/traps.c --- 2.3.29pre1/arch/i386/kernel/traps.c Tue Oct 26 21:30:50 1999 +++ 2.3.29pre1-ikd/arch/i386/kernel/traps.c Mon Nov 22 16:56:22 1999 @@ -21,12 +21,17 @@ #include #include #include +#include /* mcount debugger */ #ifdef CONFIG_MCA #include #include #endif +#if defined(CONFIG_KDB) +#include +#endif + #include #include #include @@ -45,6 +50,9 @@ #include asmlinkage int system_call(void); +#if defined(CONFIG_KDB) +asmlinkage int kdb_call(void); +#endif asmlinkage void lcall7(void); asmlinkage void lcall27(void); @@ -126,9 +134,55 @@ * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is * a guess of how much space is likely to be vmalloced. */ -#define VMALLOC_OFFSET (8*1024*1024) #define MODULE_RANGE (8*1024*1024) +#ifdef CONFIG_KERNEL_DEBUGGING +inline void print_call_trace_exact (struct pt_regs * regs, unsigned long esp) +{ + int i=1; + unsigned long *this_stack, *prev_stack, prev_addr, *prev_bp, framesize; + + printk("\nCall Trace: "); + + /* + * the stack layout: /----- *this_stack + * V + * [this_frame][prev_bp][prev_addr][prev_frame][...] + */ + + this_stack = (unsigned long *) regs->ebp; + framesize=0; + + while ((unsigned long) this_stack >= (esp & ~0x1fffUL) && + (unsigned long) (this_stack+1) < + (esp & ~0x1fffUL)+0x2000UL) + { + prev_addr = *(this_stack+1); + + if (!(i++ % 8)) + printk("\n "); + /* ksymoops expects [] */ + printk("[<%08lx>] (%lu) ", prev_addr, framesize); + + prev_bp = (unsigned long *)(*this_stack); + prev_stack = this_stack; + this_stack = prev_bp; + + if (i > 100) + { + printk("WARNING: something fishy with the stack frame?\n"); + printk("this_stack: [<%08lx>]\n", + (unsigned long)this_stack); + break; + } + framesize = (unsigned long)this_stack-(unsigned long)prev_stack; + } +#ifdef CONFIG_TRACE + print_emergency_trace(); +#endif +} +#endif /* CONFIG_KERNEL_DEBUGGING */ + static void show_registers(struct pt_regs *regs) { int i; @@ -162,19 +216,27 @@ printk("\nStack: "); stack = (unsigned long *) esp; for(i=0; i < kstack_depth_to_print; i++) { - if (((long) stack & 4095) == 0) + if (((long) stack & 8191) == 0) break; if (i && ((i % 8) == 0)) printk("\n "); printk("%08lx ", *stack++); } + +/* + * If tracing is switched on then we can walk the stack frame. Otherwise we + * can only guess. + */ +#ifdef CONFIG_KERNEL_DEBUGGING + print_call_trace_exact(regs, esp); +#else printk("\nCall Trace: "); stack = (unsigned long *) esp; i = 1; module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); module_end = module_start + MODULE_RANGE; - while (((long) stack & 4095) != 0) { + while (((long) stack & 8191) != 0) { addr = *stack++; /* * If the address is either in the text segment of the @@ -193,6 +255,7 @@ i++; } } +#endif /* CONFIG_KERNEL_DEBUGGING */ printk("\nCode: "); for(i=0;i<20;i++) printk("%02x ", ((unsigned char *)regs->eip)[i]); @@ -206,6 +269,9 @@ { console_verbose(); spin_lock_irq(&die_lock); +#if defined(CONFIG_KDB) + kdb(KDB_REASON_PANIC, err, regs); +#endif printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); @@ -338,6 +404,11 @@ #if CONFIG_SMP +/* We can't run the nmi watchdog with config-trace or config-stack-meter + because mcount() must grab spinlocks with such two options enabled + and the __cli() won't be enough to protect us from a nmi (that will + wants to run mcount too so recursing on the spinlock). */ +#if ! defined(CONFIG_TRACE) && ! defined(CONFIG_KSTACK_METER) int nmi_watchdog = 1; static int __init setup_nmi_watchdog(char *str) @@ -347,6 +418,9 @@ } __setup("nmi_watchdog=", setup_nmi_watchdog); +#else +int nmi_watchdog = 0; +#endif extern spinlock_t console_lock; static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; @@ -377,6 +451,10 @@ */ int sum, cpu = smp_processor_id(); +#if defined(CONFIG_KDB) + if (kdb_active) + return; +#endif sum = apic_timer_irqs[cpu]; if (last_irq_sums[cpu] == sum) { @@ -498,9 +576,15 @@ return; clear_dr7: + +#if defined(CONFIG_KDB) + kdb(KDB_REASON_DEBUG, error_code, regs); +#else + __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); +#endif /* CONFIG_KDB */ return; clear_TF: @@ -796,6 +880,13 @@ set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); set_system_gate(SYSCALL_VECTOR,&system_call); +#if defined(CONFIG_KDB) + /* + * A trap gate, used by the kernel to enter the + * debugger preserving all registers. + */ + set_trap_gate(KDBENTER_VECTOR,&kdb_call); +#endif /* * default LDT is a single-entry callgate to lcall7 for iBCS diff -urN 2.3.29pre1/arch/i386/kernel/traps.c.orig 2.3.29pre1-ikd/arch/i386/kernel/traps.c.orig --- 2.3.29pre1/arch/i386/kernel/traps.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/kernel/traps.c.orig Tue Oct 26 21:30:50 1999 @@ -0,0 +1,821 @@ +/* + * linux/arch/i386/traps.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MCA +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_X86_VISWS_APIC +#include +#include +#include +#endif + +#include + +asmlinkage int system_call(void); +asmlinkage void lcall7(void); +asmlinkage void lcall27(void); + +struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 } }; + +/* + * The IDT has to be page-aligned to simplify the Pentium + * F0 0F bug workaround.. We have a special link segment + * for this. + */ +struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; + +extern int console_loglevel; + +static inline void console_silent(void) +{ + console_loglevel = 0; +} + +static inline void console_verbose(void) +{ + if (console_loglevel) + console_loglevel = 15; +} + +#define DO_ERROR(trapnr, signr, str, name, tsk) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + tsk->thread.error_code = error_code; \ + tsk->thread.trap_no = trapnr; \ + die_if_no_fixup(str,regs,error_code); \ + force_sig(signr, tsk); \ +} + +#define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + lock_kernel(); \ + if (regs->eflags & VM_MASK) { \ + if (!handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr)) \ + goto out; \ + /* else fall through */ \ + } \ + tsk->thread.error_code = error_code; \ + tsk->thread.trap_no = trapnr; \ + force_sig(signr, tsk); \ + die_if_kernel(str,regs,error_code); \ +out: \ + unlock_kernel(); \ +} + +void page_exception(void); + +asmlinkage void divide_error(void); +asmlinkage void debug(void); +asmlinkage void nmi(void); +asmlinkage void int3(void); +asmlinkage void overflow(void); +asmlinkage void bounds(void); +asmlinkage void invalid_op(void); +asmlinkage void device_not_available(void); +asmlinkage void double_fault(void); +asmlinkage void coprocessor_segment_overrun(void); +asmlinkage void invalid_TSS(void); +asmlinkage void segment_not_present(void); +asmlinkage void stack_segment(void); +asmlinkage void general_protection(void); +asmlinkage void page_fault(void); +asmlinkage void coprocessor_error(void); +asmlinkage void reserved(void); +asmlinkage void alignment_check(void); +asmlinkage void spurious_interrupt_bug(void); + +int kstack_depth_to_print = 24; + +/* + * These constants are for searching for possible module text + * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is + * a guess of how much space is likely to be vmalloced. + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define MODULE_RANGE (8*1024*1024) + +static void show_registers(struct pt_regs *regs) +{ + int i; + int in_kernel = 1; + unsigned long esp; + unsigned short ss; + unsigned long *stack, addr, module_start, module_end; + + esp = (unsigned long) (1+regs); + ss = __KERNEL_DS; + if (regs->xcs & 3) { + in_kernel = 0; + esp = regs->esp; + ss = regs->xss & 0xffff; + } + printk("CPU: %d\nEIP: %04x:[<%08lx>]\nEFLAGS: %08lx\n", + smp_processor_id(), 0xffff & regs->xcs, regs->eip, regs->eflags); + printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", + regs->esi, regs->edi, regs->ebp, esp); + printk("ds: %04x es: %04x ss: %04x\n", + regs->xds & 0xffff, regs->xes & 0xffff, ss); + printk("Process %s (pid: %d, stackpage=%08lx)", + current->comm, current->pid, 4096+(unsigned long)current); + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (in_kernel) { + printk("\nStack: "); + stack = (unsigned long *) esp; + for(i=0; i < kstack_depth_to_print; i++) { + if (((long) stack & 4095) == 0) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + printk("\nCall Trace: "); + stack = (unsigned long *) esp; + i = 1; + module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); + module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); + module_end = module_start + MODULE_RANGE; + while (((long) stack & 4095) != 0) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_stext) && + (addr <= (unsigned long) &_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } + } + printk("\nCode: "); + for(i=0;i<20;i++) + printk("%02x ", ((unsigned char *)regs->eip)[i]); + } + printk("\n"); +} + +spinlock_t die_lock; + +void die(const char * str, struct pt_regs * regs, long err) +{ + console_verbose(); + spin_lock_irq(&die_lock); + printk("%s: %04lx\n", str, err & 0xffff); + show_registers(regs); + + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} + +static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if (!(regs->eflags & VM_MASK) && !(3 & regs->xcs)) + die(str, regs, err); +} + +static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) +{ + if (!(regs->eflags & VM_MASK) && !(3 & regs->xcs)) + { + unsigned long fixup; + fixup = search_exception_table(regs->eip); + if (fixup) { + regs->eip = fixup; + return; + } + die(str, regs, err); + } +} + +DO_VM86_ERROR( 0, SIGFPE, "divide error", divide_error, current) +DO_VM86_ERROR( 3, SIGTRAP, "int3", int3, current) +DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow, current) +DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds, current) +DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current) +DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available, current) +DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current) +DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, current) +DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) +DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) +DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) +DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) +DO_ERROR(18, SIGSEGV, "reserved", reserved, current) +/* I don't have documents for this but it does seem to cover the cache + flush from user space exception some people get. */ +DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current) + +asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code) +{ + if (regs->eflags & VM_MASK) { + handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); + return; + } + die_if_kernel("cache flush denied",regs,error_code); + current->thread.error_code = error_code; + current->thread.trap_no = 19; + force_sig(SIGSEGV, current); +} + +asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) +{ + if (regs->eflags & VM_MASK) + goto gp_in_vm86; + + if (!(regs->xcs & 3)) + goto gp_in_kernel; + + current->thread.error_code = error_code; + current->thread.trap_no = 13; + force_sig(SIGSEGV, current); + return; + +gp_in_vm86: + lock_kernel(); + handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); + unlock_kernel(); + return; + +gp_in_kernel: + { + unsigned long fixup; + fixup = search_exception_table(regs->eip); + if (fixup) { + regs->eip = fixup; + return; + } + die("general protection fault", regs, error_code); + } +} + +static void mem_parity_error(unsigned char reason, struct pt_regs * regs) +{ + printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); + printk("You probably have a hardware problem with your RAM chips\n"); + + /* Clear and disable the memory parity error line. */ + reason = (reason & 0xf) | 4; + outb(reason, 0x61); +} + +static void io_check_error(unsigned char reason, struct pt_regs * regs) +{ + unsigned long i; + + printk("NMI: IOCK error (debug interrupt?)\n"); + show_registers(regs); + + /* Re-enable the IOCK line, wait for a few seconds */ + reason = (reason & 0xf) | 8; + outb(reason, 0x61); + i = 2000; + while (--i) udelay(1000); + reason &= ~8; + outb(reason, 0x61); +} + +static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) +{ +#ifdef CONFIG_MCA + /* Might actually be able to figure out what the guilty party + * is. */ + if( MCA_bus ) { + mca_handle_nmi(); + return; + } +#endif + printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); + printk("Dazed and confused, but trying to continue\n"); + printk("Do you have a strange power saving mode enabled?\n"); +} + +atomic_t nmi_counter[NR_CPUS]; + +#if CONFIG_SMP + +int nmi_watchdog = 1; + +static int __init setup_nmi_watchdog(char *str) +{ + get_option(&str, &nmi_watchdog); + return 1; +} + +__setup("nmi_watchdog=", setup_nmi_watchdog); + +extern spinlock_t console_lock; +static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; + +inline void nmi_watchdog_tick(struct pt_regs * regs) +{ + /* + * the best way to detect wether a CPU has a 'hard lockup' problem + * is to check it's local APIC timer IRQ counts. If they are not + * changing then that CPU has some problem. + * + * as these watchdog NMI IRQs are broadcasted to every CPU, here + * we only have to check the current processor. + * + * since NMIs dont listen to _any_ locks, we have to be extremely + * careful not to rely on unsafe variables. The printk might lock + * up though, so we have to break up console_lock first ... + * [when there will be more tty-related locks, break them up + * here too!] + */ + + static unsigned int last_irq_sums [NR_CPUS] = { 0, }, + alert_counter [NR_CPUS] = { 0, }; + + /* + * Since current-> is always on the stack, and we always switch + * the stack NMI-atomically, it's safe to use smp_processor_id(). + */ + int sum, cpu = smp_processor_id(); + + sum = apic_timer_irqs[cpu]; + + if (last_irq_sums[cpu] == sum) { + /* + * Ayiee, looks like this CPU is stuck ... + * wait a few IRQs (5 seconds) before doing the oops ... + */ + alert_counter[cpu]++; + if (alert_counter[cpu] == 5*HZ) { + spin_lock(&nmi_print_lock); + spin_unlock(&console_lock); // we are in trouble anyway + printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu); + show_registers(regs); + printk("console shuts up ...\n"); + console_silent(); + spin_unlock(&nmi_print_lock); + do_exit(SIGSEGV); + } + } else { + last_irq_sums[cpu] = sum; + alert_counter[cpu] = 0; + } +} +#endif + +asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +{ + unsigned char reason = inb(0x61); + + atomic_inc(nmi_counter+smp_processor_id()); + if (!(reason & 0xc0)) { +#if CONFIG_SMP + /* + * Ok, so this is none of the documented NMI sources, + * so it must be the NMI watchdog. + */ + if (nmi_watchdog) { + nmi_watchdog_tick(regs); + return; + } else + unknown_nmi_error(reason, regs); +#else + unknown_nmi_error(reason, regs); +#endif + return; + } + if (reason & 0x80) + mem_parity_error(reason, regs); + if (reason & 0x40) + io_check_error(reason, regs); + /* + * Reassert NMI in case it became active meanwhile + * as it's edge-triggered. + */ + outb(0x8f, 0x70); + inb(0x71); /* dummy */ + outb(0x0f, 0x70); + inb(0x71); /* dummy */ +} + +/* + * Careful - we must not do a lock-kernel until we have checked that the + * debug fault happened in user mode. Getting debug exceptions while + * in the kernel has to be handled without locking, to avoid deadlocks.. + * + * Being careful here means that we don't have to be as careful in a + * lot of more complicated places (task switching can be a bit lazy + * about restoring all the debug state, and ptrace doesn't have to + * find every occurrence of the TF bit that could be saved away even + * by user code - and we don't have to be careful about what values + * can be written to the debug registers because there are no really + * bad cases). + */ +asmlinkage void do_debug(struct pt_regs * regs, long error_code) +{ + unsigned int condition; + struct task_struct *tsk = current; + + __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); + + /* Mask out spurious debug traps due to lazy DR7 setting */ + if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { + if (!tsk->thread.debugreg[7]) + goto clear_dr7; + } + + if (regs->eflags & VM_MASK) + goto debug_vm86; + + /* Mask out spurious TF errors due to lazy TF clearing */ + if (condition & DR_STEP) { + /* + * The TF error should be masked out only if the current + * process is not traced and if the TRAP flag has been set + * previously by a tracing process (condition detected by + * the PF_DTRACE flag); remember that the i386 TRAP flag + * can be modified by the process itself in user mode, + * allowing programs to debug themselves without the ptrace() + * interface. + */ + if ((tsk->flags & (PF_DTRACE|PF_PTRACED)) == PF_DTRACE) + goto clear_TF; + } + + /* If this is a kernel mode trap, we need to reset db7 to allow us to continue sanely */ + if ((regs->xcs & 3) == 0) + goto clear_dr7; + + /* Ok, finally something we can handle */ + tsk->thread.trap_no = 1; + tsk->thread.error_code = error_code; + force_sig(SIGTRAP, tsk); + return; + +debug_vm86: + lock_kernel(); + handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); + unlock_kernel(); + return; + +clear_dr7: + __asm__("movl %0,%%db7" + : /* no output */ + : "r" (0)); + return; + +clear_TF: + regs->eflags &= ~TF_MASK; + return; +} + +/* + * Note that we play around with the 'TS' bit in an attempt to get + * the correct behaviour even in the presence of the asynchronous + * IRQ13 behaviour + */ +void math_error(void) +{ + struct task_struct * task; + + /* + * Save the info for the exception handler + * (this will also clear the error) + */ + task = current; + save_fpu(task); + task->thread.trap_no = 16; + task->thread.error_code = 0; + force_sig(SIGFPE, task); +} + +asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) +{ + ignore_irq13 = 1; + math_error(); +} + +asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, + long error_code) +{ +#if 0 + /* No need to warn about this any longer. */ + printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); +#endif +} + +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task + * + * Careful.. There are problems with IBM-designed IRQ13 behaviour. + * Don't touch unless you *really* know how it works. + */ +asmlinkage void math_state_restore(struct pt_regs regs) +{ + __asm__ __volatile__("clts"); /* Allow maths ops (or we recurse) */ + + if(current->used_math) + __asm__("frstor %0": :"m" (current->thread.i387)); + else + { + /* + * Our first FPU usage, clean the chip. + */ + __asm__("fninit"); + current->used_math = 1; + } + current->flags|=PF_USEDFPU; /* So we fnsave on switch_to() */ +} + +#ifndef CONFIG_MATH_EMULATION + +asmlinkage void math_emulate(long arg) +{ + lock_kernel(); + printk("math-emulation not enabled and no coprocessor found.\n"); + printk("killing %s.\n",current->comm); + force_sig(SIGFPE,current); + schedule(); + unlock_kernel(); +} + +#endif /* CONFIG_MATH_EMULATION */ + +#ifndef CONFIG_M686 +void __init trap_init_f00f_bug(void) +{ + unsigned long page; + pgd_t * pgd; + pmd_t * pmd; + pte_t * pte; + + /* + * Allocate a new page in virtual address space, + * move the IDT into it and write protect this page. + */ + page = (unsigned long) vmalloc(PAGE_SIZE); + pgd = pgd_offset(&init_mm, page); + pmd = pmd_offset(pgd, page); + pte = pte_offset(pmd, page); + __free_page(pte_page(*pte)); + *pte = mk_pte_phys(__pa(&idt_table), PAGE_KERNEL_RO); + local_flush_tlb(); + + /* + * "idt" is magic - it overlaps the idt_descr + * variable so that updating idt will automatically + * update the idt descriptor.. + */ + idt = (struct desc_struct *)page; + __asm__ __volatile__("lidt %0": "=m" (idt_descr)); +} +#endif + +#define _set_gate(gate_addr,type,dpl,addr) \ +do { \ + int __d0, __d1; \ + __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ + "movw %4,%%dx\n\t" \ + "movl %%eax,%0\n\t" \ + "movl %%edx,%1" \ + :"=m" (*((long *) (gate_addr))), \ + "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ + :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ + "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \ +} while (0) + + +/* + * This needs to use 'idt_table' rather than 'idt', and + * thus use the _nonmapped_ version of the IDT, as the + * Pentium F0 0F bugfix can have resulted in the mapped + * IDT being write-protected. + */ +void set_intr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,14,0,addr); +} + +static void __init set_trap_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,15,0,addr); +} + +static void __init set_system_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,15,3,addr); +} + +static void __init set_call_gate(void *a, void *addr) +{ + _set_gate(a,12,3,addr); +} + +#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\ + *((gate_addr)+1) = ((base) & 0xff000000) | \ + (((base) & 0x00ff0000)>>16) | \ + ((limit) & 0xf0000) | \ + ((dpl)<<13) | \ + (0x00408000) | \ + ((type)<<8); \ + *(gate_addr) = (((base) & 0x0000ffff)<<16) | \ + ((limit) & 0x0ffff); } + +#define _set_tssldt_desc(n,addr,limit,type) \ +__asm__ __volatile__ ("movw %3,0(%2)\n\t" \ + "movw %%ax,2(%2)\n\t" \ + "rorl $16,%%eax\n\t" \ + "movb %%al,4(%2)\n\t" \ + "movb %4,5(%2)\n\t" \ + "movb $0,6(%2)\n\t" \ + "movb %%ah,7(%2)\n\t" \ + "rorl $16,%%eax" \ + : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type)) + +void set_tss_desc(unsigned int n, void *addr) +{ + _set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89); +} + +void set_ldt_desc(unsigned int n, void *addr, unsigned int size) +{ + _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82); +} + +#ifdef CONFIG_X86_VISWS_APIC + +/* + * On Rev 005 motherboards legacy device interrupt lines are wired directly + * to Lithium from the 307. But the PROM leaves the interrupt type of each + * 307 logical device set appropriate for the 8259. Later we'll actually use + * the 8259, but for now we have to flip the interrupt types to + * level triggered, active lo as required by Lithium. + */ + +#define REG 0x2e /* The register to read/write */ +#define DEV 0x07 /* Register: Logical device select */ +#define VAL 0x2f /* The value to read/write */ + +static void +superio_outb(int dev, int reg, int val) +{ + outb(DEV, REG); + outb(dev, VAL); + outb(reg, REG); + outb(val, VAL); +} + +static int __attribute__ ((unused)) +superio_inb(int dev, int reg) +{ + outb(DEV, REG); + outb(dev, VAL); + outb(reg, REG); + return inb(VAL); +} + +#define FLOP 3 /* floppy logical device */ +#define PPORT 4 /* parallel logical device */ +#define UART5 5 /* uart2 logical device (not wired up) */ +#define UART6 6 /* uart1 logical device (THIS is the serial port!) */ +#define IDEST 0x70 /* int. destination (which 307 IRQ line) reg. */ +#define ITYPE 0x71 /* interrupt type register */ + +/* interrupt type bits */ +#define LEVEL 0x01 /* bit 0, 0 == edge triggered */ +#define ACTHI 0x02 /* bit 1, 0 == active lo */ + +static void +superio_init(void) +{ + if (visws_board_type == VISWS_320 && visws_board_rev == 5) { + superio_outb(UART6, IDEST, 0); /* 0 means no intr propagated */ + printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n"); + } +} + +static void +lithium_init(void) +{ + set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS); + printk("Lithium PCI Bridge A, Bus Number: %d\n", + li_pcia_read16(LI_PCI_BUSNUM) & 0xff); + set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS); + printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n", + li_pcib_read16(LI_PCI_BUSNUM) & 0xff); + + /* XXX blindly enables all interrupts */ + li_pcia_write16(LI_PCI_INTEN, 0xffff); + li_pcib_write16(LI_PCI_INTEN, 0xffff); +} + +static void +cobalt_init(void) +{ + /* + * On normal SMP PC this is used only with SMP, but we have to + * use it and set it up here to start the Cobalt clock + */ + set_fixmap(FIX_APIC_BASE, APIC_PHYS_BASE); + printk("Local APIC ID %lx\n", apic_read(APIC_ID)); + printk("Local APIC Version %lx\n", apic_read(APIC_LVR)); + + set_fixmap(FIX_CO_CPU, CO_CPU_PHYS); + printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV)); + + set_fixmap(FIX_CO_APIC, CO_APIC_PHYS); + printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID)); + + /* Enable Cobalt APIC being careful to NOT change the ID! */ + co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE); + + printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID)); +} +#endif +void __init trap_init(void) +{ + if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) + EISA_bus = 1; + + set_trap_gate(0,÷_error); + set_trap_gate(1,&debug); + set_intr_gate(2,&nmi); + set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_gate(4,&overflow); + set_system_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_trap_gate(8,&double_fault); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_trap_gate(14,&page_fault); + set_trap_gate(15,&spurious_interrupt_bug); + set_trap_gate(16,&coprocessor_error); + set_trap_gate(17,&alignment_check); + set_system_gate(SYSCALL_VECTOR,&system_call); + + /* + * default LDT is a single-entry callgate to lcall7 for iBCS + * and a callgate to lcall27 for Solaris/x86 binaries + */ + set_call_gate(&default_ldt[0],lcall7); + set_call_gate(&default_ldt[4],lcall27); + + /* + * on SMP we do not yet know which CPU is on which TSS, + * so we delay this until smp_init(). (the CPU is already + * in a reasonable state, otherwise we wouldnt have gotten so far :) + */ +#ifndef __SMP__ + cpu_init(); +#endif + +#ifdef CONFIG_X86_VISWS_APIC + superio_init(); + lithium_init(); + cobalt_init(); +#endif +} diff -urN 2.3.29pre1/arch/i386/mm/fault.c 2.3.29pre1-ikd/arch/i386/mm/fault.c --- 2.3.29pre1/arch/i386/mm/fault.c Tue Oct 26 21:30:50 1999 +++ 2.3.29pre1-ikd/arch/i386/mm/fault.c Mon Nov 22 16:56:22 1999 @@ -4,6 +4,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include @@ -256,6 +258,8 @@ return; } + /* recursion is the curse of the programming classes */ + SUSPEND_MCOUNT_PROC(current); if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); else diff -urN 2.3.29pre1/arch/i386/mm/fault.c.orig 2.3.29pre1-ikd/arch/i386/mm/fault.c.orig --- 2.3.29pre1/arch/i386/mm/fault.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/mm/fault.c.orig Tue Oct 26 21:30:50 1999 @@ -0,0 +1,304 @@ +/* + * linux/arch/i386/mm/fault.c + * + * Copyright (C) 1995 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern void die(const char *,struct pt_regs *,long); + +/* + * Ugly, ugly, but the goto's result in better assembly.. + */ +int __verify_write(const void * addr, unsigned long size) +{ + struct vm_area_struct * vma; + unsigned long start = (unsigned long) addr; + + if (!size) + return 1; + + vma = find_vma(current->mm, start); + if (!vma) + goto bad_area; + if (vma->vm_start > start) + goto check_stack; + +good_area: + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + size--; + size += start & ~PAGE_MASK; + size >>= PAGE_SHIFT; + start &= PAGE_MASK; + + for (;;) { + if (handle_mm_fault(current, vma, start, 1) <= 0) + goto bad_area; + if (!size) + break; + size--; + start += PAGE_SIZE; + if (start < vma->vm_end) + continue; + vma = vma->vm_next; + if (!vma || vma->vm_start != start) + goto bad_area; + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area;; + } + return 1; + +check_stack: + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (expand_stack(vma, start) == 0) + goto good_area; + +bad_area: + return 0; +} + +static inline void handle_wp_test (void) +{ + const unsigned long vaddr = PAGE_OFFSET; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + /* + * make it read/writable temporarily, so that the fault + * can be handled. + */ + pgd = swapper_pg_dir + __pgd_offset(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset(pmd, vaddr); + *pte = mk_pte_phys(0, PAGE_KERNEL); + local_flush_tlb(); + + boot_cpu_data.wp_works_ok = 1; + /* + * Beware: Black magic here. The printk is needed here to flush + * CPU state on certain buggy processors. + */ + printk("Ok"); +} + +asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); +extern unsigned long idt; + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + * + * error_code: + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * bit 2 == 0 means kernel, 1 means user-mode + */ +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) +{ + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct * vma; + unsigned long address; + unsigned long page; + unsigned long fixup; + int write; + + /* get the address */ + __asm__("movl %%cr2,%0":"=r" (address)); + + tsk = current; + mm = tsk->mm; + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || !mm) + goto no_context; + + down(&mm->mmap_sem); + + vma = find_vma(mm, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (error_code & 4) { + /* + * accessing the stack below %esp is always a bug. + * The "+ 32" is there due to some instructions (like + * pusha) doing post-decrement on the stack and that + * doesn't show up until later.. + */ + if (address + 32 < regs->esp) + goto bad_area; + } + if (expand_stack(vma, address)) + goto bad_area; +/* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + write = 0; + switch (error_code & 3) { + default: /* 3: write, present */ +#ifdef TEST_VERIFY_AREA + if (regs->cs == KERNEL_CS) + printk("WP fault at %08lx\n", regs->eip); +#endif + /* fall through */ + case 2: /* write, not present */ + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + write++; + break; + case 1: /* read, present */ + goto bad_area; + case 0: /* read, not present */ + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + goto bad_area; + } + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + { + int fault = handle_mm_fault(tsk, vma, address, write); + if (fault < 0) + goto out_of_memory; + if (!fault) + goto do_sigbus; + } + + /* + * Did it hit the DOS screen memory VA from vm86 mode? + */ + if (regs->eflags & VM_MASK) { + unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT; + if (bit < 32) + tsk->thread.screen_bitmap |= 1 << bit; + } + up(&mm->mmap_sem); + return; + +/* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + up(&mm->mmap_sem); + + /* User mode accesses just cause a SIGSEGV */ + if (error_code & 4) { + tsk->thread.cr2 = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + force_sig(SIGSEGV, tsk); + return; + } + + /* + * Pentium F0 0F C7 C8 bug workaround. + */ + if (boot_cpu_data.f00f_bug) { + unsigned long nr; + + nr = (address - idt) >> 3; + + if (nr == 6) { + do_invalid_op(regs, 0); + return; + } + } + +no_context: + /* Are we prepared to handle this kernel fault? */ + if ((fixup = search_exception_table(regs->eip)) != 0) { + regs->eip = fixup; + return; + } + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + * + * First we check if it was the bootup rw-test, though.. + */ + if (boot_cpu_data.wp_works_ok < 0 && + address == PAGE_OFFSET && (error_code & 1)) { + handle_wp_test(); + return; + } + + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging request"); + printk(" at virtual address %08lx\n",address); + printk(" printing eip:\n"); + printk("%08lx\n", regs->eip); + asm("movl %%cr3,%0":"=r" (page)); + page = ((unsigned long *) __va(page))[address >> 22]; + printk(KERN_ALERT "*pde = %08lx\n", page); + if (page & 1) { + page &= PAGE_MASK; + address &= 0x003ff000; + page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; + printk(KERN_ALERT "*pte = %08lx\n", page); + } + die("Oops", regs, error_code); + do_exit(SIGKILL); + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up(&mm->mmap_sem); + printk("VM: killing process %s\n", tsk->comm); + if (error_code & 4) + do_exit(SIGKILL); + goto no_context; + +do_sigbus: + up(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->thread.cr2 = address; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 14; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!(error_code & 4)) + goto no_context; +} diff -urN 2.3.29pre1/arch/i386/mm/init.c 2.3.29pre1-ikd/arch/i386/mm/init.c --- 2.3.29pre1/arch/i386/mm/init.c Sun Nov 21 03:20:43 1999 +++ 2.3.29pre1-ikd/arch/i386/mm/init.c Mon Nov 22 16:56:22 1999 @@ -111,6 +111,7 @@ pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); } +#ifndef CONFIG_MEMLEAK /* put these back into pgtable.h */ pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) { pte_t *pte; @@ -154,6 +155,7 @@ } return (pte_t *) pmd_page(*pmd) + offset; } +#endif CONFIG_MEMLEAK int do_check_pgt_cache(int low, int high) { diff -urN 2.3.29pre1/arch/i386/mm/init.c.orig 2.3.29pre1-ikd/arch/i386/mm/init.c.orig --- 2.3.29pre1/arch/i386/mm/init.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/arch/i386/mm/init.c.orig Sun Nov 21 03:20:43 1999 @@ -0,0 +1,629 @@ +/* + * linux/arch/i386/mm/init.c + * + * Copyright (C) 1995 Linus Torvalds + * + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_INITRD +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +unsigned long highstart_pfn, highend_pfn; +static unsigned long totalram_pages = 0; +static unsigned long totalhigh_pages = 0; + +extern void show_net_buffers(void); + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving an inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ + +/* + * These are allocated in head.S so that we get proper page alignment. + * If you change the size of these then change head.S as well. + */ +extern char empty_bad_page[PAGE_SIZE]; +#if CONFIG_X86_PAE +extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD]; +#endif +extern pte_t empty_bad_pte_table[PTRS_PER_PTE]; + +/* + * We init them before every return and make them writable-shared. + * This guarantees we get out of the kernel in some more or less sane + * way. + */ +#if CONFIG_X86_PAE +static pmd_t * get_bad_pmd_table(void) +{ + pmd_t v; + int i; + + pmd_val(v) = _PAGE_TABLE + __pa(empty_bad_pte_table); + + for (i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++) + empty_bad_pmd_table[i] = v; + + return empty_bad_pmd_table; +} +#endif + +static pte_t * get_bad_pte_table(void) +{ + pte_t v; + int i; + + v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); + + for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) + empty_bad_pte_table[i] = v; + + return empty_bad_pte_table; +} + + + +void __handle_bad_pmd(pmd_t *pmd) +{ + pmd_ERROR(*pmd); + pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); +} + +void __handle_bad_pmd_kernel(pmd_t *pmd) +{ + pmd_ERROR(*pmd); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); +} + +pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + clear_page(pte); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + return pte + offset; + } + pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); + return NULL; + } + free_page((unsigned long)pte); + if (pmd_bad(*pmd)) { + __handle_bad_pmd_kernel(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + unsigned long pte; + + pte = (unsigned long) __get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + clear_page((void *)pte); + pmd_val(*pmd) = _PAGE_TABLE + __pa(pte); + return (pte_t *)pte + offset; + } + pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); + return NULL; + } + free_page(pte); + if (pmd_bad(*pmd)) { + __handle_bad_pmd(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +int do_check_pgt_cache(int low, int high) +{ + int freed = 0; + if(pgtable_cache_size > high) { + do { + if(pgd_quicklist) + free_pgd_slow(get_pgd_fast()), freed++; + if(pmd_quicklist) + free_pmd_slow(get_pmd_fast()), freed++; + if(pte_quicklist) + free_pte_slow(get_pte_fast()), freed++; + } while(pgtable_cache_size > low); + } + return freed; +} + +/* + * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the + * physical space so we can cache the place of the first one and move + * around without checking the pgd every time. + */ + +#if CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; + +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) + +void __init kmap_init(void) +{ + unsigned long kmap_vstart; + + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); + + kmap_prot = PAGE_KERNEL; + if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) + pgprot_val(kmap_prot) |= _PAGE_GLOBAL; +} +#endif + +void show_mem(void) +{ + int i,free = 0, total = 0, reserved = 0; + int shared = 0, cached = 0; + int highmem = 0; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageHighMem(mem_map+i)) + highmem++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (!page_count(mem_map+i)) + free++; + else + shared += page_count(mem_map+i) - 1; + } + printk("%d pages of RAM\n", total); + printk("%d pages of HIGHMEM\n",highmem); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); + printk("%ld pages in page table cache\n",pgtable_cache_size); + show_buffers(); +#ifdef CONFIG_NET + show_net_buffers(); +#endif +} + +/* References to section boundaries */ + +extern char _text, _etext, _edata, __bss_start, _end; +extern char __init_begin, __init_end; + +static void set_pte_phys (unsigned long vaddr, unsigned long phys) +{ + pgprot_t prot; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + pgd = swapper_pg_dir + __pgd_offset(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset(pmd, vaddr); + prot = PAGE_KERNEL; + if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) + pgprot_val(prot) |= _PAGE_GLOBAL; + set_pte(pte, mk_pte_phys(phys, prot)); + + /* + * It's enough to flush this one mapping. + */ + __flush_tlb_one(vaddr); +} + +void set_fixmap (enum fixed_addresses idx, unsigned long phys) +{ + unsigned long address = __fix_to_virt(idx); + + if (idx >= __end_of_fixed_addresses) { + printk("Invalid set_fixmap\n"); + return; + } + set_pte_phys (address,phys); +} + +static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int i, j; + + i = __pgd_offset(start); + j = __pmd_offset(start); + pgd = pgd_base + i; + + for ( ; (i < PTRS_PER_PGD) && (start != end); pgd++, i++) { +#if CONFIG_X86_PAE + if (pgd_none(*pgd)) { + pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + memset((void*)pmd, 0, PAGE_SIZE); + pgd_val(*pgd) = __pa(pmd) + 0x1; + if (pmd != pmd_offset(pgd, start)) + BUG(); + } + pmd = pmd_offset(pgd, start); +#else + pmd = (pmd_t *)pgd; +#endif + for (; (j < PTRS_PER_PMD) && start; pmd++, j++) { + if (pmd_none(*pmd)) { + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + memset((void*)pte, 0, PAGE_SIZE); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + if (pte != pte_offset(pmd, 0)) + BUG(); + } + start += PMD_SIZE; + } + j = 0; + } +} + +static void __init pagetable_init(void) +{ + pgd_t *pgd, *pgd_base; + pmd_t *pmd; + pte_t *pte; + int i, j, k; + unsigned long vaddr; + unsigned long end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); + + pgd_base = swapper_pg_dir; + + vaddr = PAGE_OFFSET; + i = __pgd_offset(vaddr); + pgd = pgd_base + i; + + for (; (i < PTRS_PER_PGD) && (vaddr <= end); pgd++, i++) { + vaddr = i*PGDIR_SIZE; +#if CONFIG_X86_PAE + pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); + memset((void*)pmd, 0, PAGE_SIZE); + pgd_val(*pgd) = __pa(pmd) + 0x1; +#else + pmd = (pmd_t *)pgd; +#endif + if (pmd != pmd_offset(pgd, 0)) + BUG(); + for (j = 0; (j < PTRS_PER_PMD) && (vaddr <= end); pmd++, j++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE; + if (cpu_has_pse) { + unsigned long __pe; + + set_in_cr4(X86_CR4_PSE); + boot_cpu_data.wp_works_ok = 1; + __pe = _KERNPG_TABLE + _PAGE_PSE + __pa(vaddr); + /* Make it "global" too if supported */ + if (cpu_has_pge) { + set_in_cr4(X86_CR4_PGE); + __pe += _PAGE_GLOBAL; + } + pmd_val(*pmd) = __pe; + continue; + } + + pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); + memset((void*)pte, 0, PAGE_SIZE); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(pte); + + if (pte != pte_offset(pmd, 0)) + BUG(); + + for (k = 0; + (k < PTRS_PER_PTE) && (vaddr <= end); + pte++, k++) { + vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE; + *pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL); + } + } + } + + /* + * Fixed mappings, only the page table structure has to be + * created - mappings will be set by set_fixmap(): + */ + vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; + fixrange_init(vaddr, 0, pgd_base); + +#if CONFIG_HIGHMEM + /* + * Permanent kmaps: + */ + vaddr = PKMAP_BASE; + fixrange_init(vaddr, vaddr + 4*1024*1024, pgd_base); + + pgd = swapper_pg_dir + __pgd_offset(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset(pmd, vaddr); + pkmap_page_table = pte; +#endif + +#if CONFIG_X86_PAE + /* + * Add low memory identity-mappings - SMP needs it when + * starting up on an AP from real-mode. In the non-PAE + * case we already have these mappings through head.S. + * All user-space mappings are explicitly cleared after + * SMP startup. + */ + pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; +#endif +} + +void __init zap_low_mappings (void) +{ + int i; + /* + * Zap initial low-memory mappings. + * + * Note that "pgd_clear()" doesn't do it for + * us in this case, because pgd_clear() is a + * no-op in the 2-level case (pmd_clear() is + * the thing that clears the page-tables in + * that case). + */ + for (i = 0; i < USER_PTRS_PER_PGD; i++) + pgd_val(swapper_pg_dir[i]) = 0; + flush_tlb_all(); +} + +/* + * paging_init() sets up the page tables - note that the first 4MB are + * already mapped by head.S. + * + * This routines also unmaps the page at virtual kernel address 0, so + * that we can trap those pesky NULL-reference errors in the kernel. + */ +void __init paging_init(void) +{ + pagetable_init(); + + __asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swapper_pg_dir))); + +#if CONFIG_X86_PAE + /* + * We will bail out later - printk doesnt work right now so + * the user would just see a hanging kernel. + */ + if (cpu_has_pae) + set_in_cr4(X86_CR4_PAE); +#endif + + __flush_tlb(); + +#ifdef __SMP__ + init_smp_mappings(); +#endif + +#ifdef CONFIG_HIGHMEM + kmap_init(); +#endif + { + unsigned int zones_size[3]; + + zones_size[0] = virt_to_phys((char *)MAX_DMA_ADDRESS) + >> PAGE_SHIFT; + zones_size[1] = max_low_pfn - zones_size[0]; + zones_size[2] = highend_pfn - zones_size[0] - zones_size[1]; + + free_area_init(zones_size); + } + return; +} + +/* + * Test if the WP bit works in supervisor mode. It isn't supported on 386's + * and also on some strange 486's (NexGen etc.). All 586+'s are OK. The jumps + * before and after the test are here to work-around some nasty CPU bugs. + */ + +void __init test_wp_bit(void) +{ +/* + * Ok, all PAE-capable CPUs are definitely handling the WP bit right. + */ + const unsigned long vaddr = PAGE_OFFSET; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte, old_pte; + char tmp_reg; + + printk("Checking if this processor honours the WP bit even in supervisor mode... "); + + pgd = swapper_pg_dir + __pgd_offset(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset(pmd, vaddr); + old_pte = *pte; + *pte = mk_pte_phys(0, PAGE_READONLY); + local_flush_tlb(); + + __asm__ __volatile__( + "jmp 1f; 1:\n" + "movb %0,%1\n" + "movb %1,%0\n" + "jmp 1f; 1:\n" + :"=m" (*(char *) vaddr), + "=q" (tmp_reg) + :/* no inputs */ + :"memory"); + + *pte = old_pte; + local_flush_tlb(); + + if (boot_cpu_data.wp_works_ok < 0) { + boot_cpu_data.wp_works_ok = 0; + printk("No.\n"); +#ifdef CONFIG_X86_WP_WORKS_OK + panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!"); +#endif + } else + printk(".\n"); +} + +static inline int page_is_ram (unsigned long pagenr) +{ + int i; + + for (i = 0; i < e820.nr_map; i++) { + unsigned long addr, size; + + if (e820.map[i].type != E820_RAM) /* not usable memory */ + continue; + /* + * !!!FIXME!!! Some BIOSen report areas as RAM that + * are not. Notably the 640->1Mb area. We need a sanity + * check here. + */ + addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; + size = e820.map[i].size >> PAGE_SHIFT; + if ((pagenr >= addr) && (pagenr < addr+size)) + return 1; + } + return 0; +} + +void __init mem_init(void) +{ + int codepages = 0; + int reservedpages = 0; + int datapages = 0; + int initpages = 0; +#ifdef CONFIG_HIGHMEM + int tmp; + + if (!mem_map) + BUG(); + highmem_start_page = mem_map + highstart_pfn; + /* cache the highmem_mapnr */ + highmem_mapnr = highstart_pfn; + max_mapnr = num_physpages = highend_pfn; +#else + max_mapnr = num_physpages = max_low_pfn; +#endif + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); + + /* clear the zero-page */ + memset(empty_zero_page, 0, PAGE_SIZE); + + /* this will put all low memory onto the freelists */ + totalram_pages += free_all_bootmem(); + +#ifdef CONFIG_HIGHMEM + for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { + struct page *page = mem_map + tmp; + + if (!page_is_ram(tmp)) { + SetPageReserved(page); + continue; + } + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + totalhigh_pages++; + } + totalram_pages += totalhigh_pages; +#endif + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + max_mapnr << (PAGE_SHIFT-10), + codepages << (PAGE_SHIFT-10), + reservedpages << (PAGE_SHIFT-10), + datapages << (PAGE_SHIFT-10), + initpages << (PAGE_SHIFT-10), + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) + ); + +#if CONFIG_X86_PAE + if (!cpu_has_pae) + panic("cannot execute a PAE-enabled kernel on a PAE-incapable CPU!"); +#endif + if (boot_cpu_data.wp_works_ok < 0) + test_wp_bit(); + + /* + * Subtle. SMP is doing it's boot stuff late (because it has to + * fork idle threads) - but it also needs low mappings for the + * protected-mode entry to work. We zap these entries only after + * the WP-bit has been tested. + */ +#ifndef CONFIG_SMP + zap_low_mappings(); +#endif + +} + +void free_initmem(void) +{ + unsigned long addr; + + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + ClearPageReserved(mem_map + MAP_NR(addr)); + set_page_count(mem_map+MAP_NR(addr), 1); + free_page(addr); + totalram_pages++; + } + printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); +} + +void si_meminfo(struct sysinfo *val) +{ + val->totalram = totalram_pages; + val->sharedram = 0; + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = totalhigh_pages; + val->freehigh = nr_free_highpages(); + val->mem_unit = PAGE_SIZE; + return; +} diff -urN 2.3.29pre1/arch/sparc64/kernel/smp.c 2.3.29pre1-ikd/arch/sparc64/kernel/smp.c --- 2.3.29pre1/arch/sparc64/kernel/smp.c Tue Sep 14 14:35:33 1999 +++ 2.3.29pre1-ikd/arch/sparc64/kernel/smp.c Mon Nov 22 16:56:24 1999 @@ -549,6 +549,7 @@ static inline void sparc64_do_profile(unsigned long pc, unsigned long g3) { +#ifndef CONFIG_PROFILE_GCC if (prof_buffer && current->pid) { extern int _stext; extern int rwlock_impl_begin, rwlock_impl_end; @@ -567,6 +568,7 @@ pc = prof_len - 1; atomic_inc((atomic_t *)&prof_buffer[pc]); } +#endif } static unsigned long current_tick_offset; diff -urN 2.3.29pre1/drivers/char/keyboard.c 2.3.29pre1-ikd/drivers/char/keyboard.c --- 2.3.29pre1/drivers/char/keyboard.c Sun Nov 21 03:20:17 1999 +++ 2.3.29pre1-ikd/drivers/char/keyboard.c Mon Nov 22 16:57:54 1999 @@ -42,6 +42,9 @@ #include #include #include +#if defined(CONFIG_KDB) +#include +#endif #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -248,6 +251,12 @@ up_flag = kbd_unexpected_up(keycode); } else rep = test_and_set_bit(keycode, key_down); + +#if defined(CONFIG_KDB) + if (!up_flag && (keycode == E1_PAUSE)) { + kdb(KDB_REASON_KEYBOARD, 0, kbd_pt_regs); + } +#endif #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == SYSRQ_KEY) { diff -urN 2.3.29pre1/drivers/char/keyboard.c.orig 2.3.29pre1-ikd/drivers/char/keyboard.c.orig --- 2.3.29pre1/drivers/char/keyboard.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/drivers/char/keyboard.c.orig Sun Nov 21 03:20:17 1999 @@ -0,0 +1,935 @@ +/* + * linux/drivers/char/keyboard.c + * + * Written for linux by Johan Myreen as a translation from + * the assembly version by Linus (with diacriticals added) + * + * Some additional features added by Christoph Niemann (ChN), March 1993 + * + * Loadable keymaps by Risto Kankkunen, May 1993 + * + * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993 + * Added decr/incr_console, dynamic keymaps, Unicode support, + * dynamic function/string keys, led setting, Sept 1994 + * `Sticky' modifier keys, 951006. + * + * 11-11-96: SAK should now work in the raw mode (Martin Mares) + * + * Modified to provide 'generic' keyboard support by Hamish Macdonald + * Merge with the m68k keyboard driver and split-off of the PC low-level + * parts by Geert Uytterhoeven, May 1997 + * + * 27-05-97: Added support for the Magic SysRq Key (Martin Mares) + * 30-07-98: Dead keys redone, aeb@cwi.nl. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +#ifndef KBD_DEFMODE +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) +#endif + +#ifndef KBD_DEFLEDS +/* + * Some laptops take the 789uiojklm,. keys as number pad when NumLock + * is on. This seems a good reason to start with NumLock off. + */ +#define KBD_DEFLEDS 0 +#endif + +#ifndef KBD_DEFLOCK +#define KBD_DEFLOCK 0 +#endif + +EXPORT_SYMBOL(handle_scancode); + +extern void ctrl_alt_del(void); + +DECLARE_WAIT_QUEUE_HEAD(keypress_wait); +struct console; + +int keyboard_wait_for_keypress(struct console *co) +{ + sleep_on(&keypress_wait); + return 0; +} + +/* + * global state includes the following, and various static variables + * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. + * (last_console is now a global variable) + */ + +/* shift state counters.. */ +static unsigned char k_down[NR_SHIFT] = {0, }; +/* keyboard key bitmap */ +static unsigned long key_down[256/BITS_PER_LONG] = { 0, }; + +static int dead_key_next = 0; +/* + * In order to retrieve the shift_state (for the mouse server), either + * the variable must be global, or a new procedure must be created to + * return the value. I chose the former way. + */ +int shift_state = 0; +static int npadch = -1; /* -1 or number assembled on pad */ +static unsigned char diacr = 0; +static char rep = 0; /* flag telling character repeat */ +struct kbd_struct kbd_table[MAX_NR_CONSOLES]; +static struct tty_struct **ttytab; +static struct kbd_struct * kbd = kbd_table; +static struct tty_struct * tty = NULL; + +void compute_shiftstate(void); + +typedef void (*k_hand)(unsigned char value, char up_flag); +typedef void (k_handfn)(unsigned char value, char up_flag); + +static k_handfn + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, + do_ignore; + +static k_hand key_handler[16] = { + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, + do_ignore, do_ignore +}; + +/* Key types processed even in raw modes */ + +#define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT)) + +typedef void (*void_fnp)(void); +typedef void (void_fn)(void); + +static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, + SAK, decr_console, incr_console, spawn_console, bare_num; + +static void_fnp spec_fn_table[] = { + do_null, enter, show_ptregs, show_mem, + show_state, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, + boot_it, caps_on, compose, SAK, + decr_console, incr_console, spawn_console, bare_num +}; + +#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK)) + +/* maximum values each key_handler can handle */ +const int max_vals[] = { + 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, + 255, NR_ASCII - 1, NR_LOCK - 1, 255, + NR_LOCK - 1, 255 +}; + +const int NR_TYPES = SIZE(max_vals); + +/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */ +void put_queue(int); +static unsigned char handle_diacr(unsigned char); + +/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ +struct pt_regs * kbd_pt_regs; + +#ifdef CONFIG_MAGIC_SYSRQ +static int sysrq_pressed; +int sysrq_enabled = 1; +#endif + +static struct acpi_dev_info acpi_kbd_info = {ACPI_SYS_DEV, ACPI_KBC_HID, NULL}; +static struct acpi_dev *acpi_kbd = NULL; + +/* + * Many other routines do put_queue, but I think either + * they produce ASCII, or they produce some user-assigned + * string, and in both cases we might assume that it is + * in utf-8 already. + */ +void to_utf8(ushort c) { + if (c < 0x80) + put_queue(c); /* 0******* */ + else if (c < 0x800) { + put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */ + put_queue(0x80 | (c & 0x3f)); + } else { + put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */ + put_queue(0x80 | ((c >> 6) & 0x3f)); + put_queue(0x80 | (c & 0x3f)); + } + /* UTF-8 is defined for words of up to 31 bits, + but we need only 16 bits here */ +} + +/* + * Translation of escaped scancodes to keycodes. + * This is now user-settable (for machines were it makes sense). + */ + +int setkeycode(unsigned int scancode, unsigned int keycode) +{ + return kbd_setkeycode(scancode, keycode); +} + +int getkeycode(unsigned int scancode) +{ + return kbd_getkeycode(scancode); +} + +void handle_scancode(unsigned char scancode, int down) +{ + unsigned char keycode; + char up_flag = down ? 0 : 0200; + char raw_mode; + + acpi_access(acpi_kbd); + + do_poke_blanked_console = 1; + mark_bh(CONSOLE_BH); + add_keyboard_randomness(scancode | up_flag); + + tty = ttytab? ttytab[fg_console]: NULL; + if (tty && (!tty->driver_data)) { + /* + * We touch the tty structure via the the ttytab array + * without knowing whether or not tty is open, which + * is inherently dangerous. We currently rely on that + * fact that console_open sets tty->driver_data when + * it opens it, and clears it when it closes it. + */ + tty = NULL; + } + kbd = kbd_table + fg_console; + if ((raw_mode = (kbd->kbdmode == VC_RAW))) { + put_queue(scancode | up_flag); + /* we do not return yet, because we want to maintain + the key_down array, so that we have the correct + values when finishing RAW mode or when changing VT's */ + } + + /* + * Convert scancode to keycode + */ + if (!kbd_translate(scancode, &keycode, raw_mode)) + return; + + /* + * At this point the variable `keycode' contains the keycode. + * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). + * We keep track of the up/down status of the key, and + * return the keycode if in MEDIUMRAW mode. + */ + + if (up_flag) { + rep = 0; + if(!test_and_clear_bit(keycode, key_down)) + up_flag = kbd_unexpected_up(keycode); + } else + rep = test_and_set_bit(keycode, key_down); + +#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ + if (keycode == SYSRQ_KEY) { + sysrq_pressed = !up_flag; + return; + } else if (sysrq_pressed) { + if (!up_flag && sysrq_enabled) { + handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); + return; + } + } +#endif + + if (kbd->kbdmode == VC_MEDIUMRAW) { + /* soon keycodes will require more than one byte */ + put_queue(keycode + up_flag); + raw_mode = 1; /* Most key classes will be ignored */ + } + + /* + * Small change in philosophy: earlier we defined repetition by + * rep = keycode == prev_keycode; + * prev_keycode = keycode; + * but now by the fact that the depressed key was down already. + * Does this ever make a difference? Yes. + */ + + /* + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. + */ + if (!rep || + (vc_kbd_mode(kbd,VC_REPEAT) && tty && + (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { + u_short keysym; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = (shift_state | kbd->slockstate) ^ + kbd->lockstate; + ushort *key_map = key_maps[shift_final]; + + if (key_map != NULL) { + keysym = key_map[keycode]; + type = KTYP(keysym); + + if (type >= 0xf0) { + type -= 0xf0; + if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) + return; + if (type == KT_LETTER) { + type = KT_LATIN; + if (vc_kbd_led(kbd, VC_CAPSLOCK)) { + key_map = key_maps[shift_final ^ (1<slockstate = 0; + } else { + /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ + if (!up_flag && !raw_mode) + to_utf8(keysym); + } + } else { + /* maybe beep? */ + /* we have at least to update shift_state */ +#if 1 /* how? two almost equivalent choices follow */ + compute_shiftstate(); + kbd->slockstate = 0; /* play it safe */ +#else + keysym = U(plain_map[keycode]); + type = KTYP(keysym); + if (type == KT_SHIFT) + (*key_handler[type])(keysym & 0xff, up_flag); +#endif + } + } +} + + +void put_queue(int ch) +{ + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + con_schedule_flip(tty); + } +} + +static void puts_queue(char *cp) +{ + wake_up(&keypress_wait); + if (!tty) + return; + + while (*cp) { + tty_insert_flip_char(tty, *cp, 0); + cp++; + } + con_schedule_flip(tty); +} + +static void applkey(int key, char mode) +{ + static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; + + buf[1] = (mode ? 'O' : '['); + buf[2] = key; + puts_queue(buf); +} + +static void enter(void) +{ + if (diacr) { + put_queue(diacr); + diacr = 0; + } + put_queue(13); + if (vc_kbd_mode(kbd,VC_CRLF)) + put_queue(10); +} + +static void caps_toggle(void) +{ + if (rep) + return; + chg_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +static void caps_on(void) +{ + if (rep) + return; + set_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +static void show_ptregs(void) +{ + if (kbd_pt_regs) + show_regs(kbd_pt_regs); +} + +static void hold(void) +{ + if (rep || !tty) + return; + + /* + * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); + * these routines are also activated by ^S/^Q. + * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) + */ + if (tty->stopped) + start_tty(tty); + else + stop_tty(tty); +} + +static void num(void) +{ + if (vc_kbd_mode(kbd,VC_APPLIC)) + applkey('P', 1); + else + bare_num(); +} + +/* + * Bind this to Shift-NumLock if you work in application keypad mode + * but want to be able to change the NumLock flag. + * Bind this to NumLock if you prefer that the NumLock key always + * changes the NumLock flag. + */ +static void bare_num(void) +{ + if (!rep) + chg_vc_kbd_led(kbd,VC_NUMLOCK); +} + +static void lastcons(void) +{ + /* switch to the last used console, ChN */ + set_console(last_console); +} + +static void decr_console(void) +{ + int i; + + for (i = fg_console-1; i != fg_console; i--) { + if (i == -1) + i = MAX_NR_CONSOLES-1; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void incr_console(void) +{ + int i; + + for (i = fg_console+1; i != fg_console; i++) { + if (i == MAX_NR_CONSOLES) + i = 0; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void send_intr(void) +{ + if (!tty) + return; + tty_insert_flip_char(tty, 0, TTY_BREAK); + con_schedule_flip(tty); +} + +static void scroll_forw(void) +{ + scrollfront(0); +} + +static void scroll_back(void) +{ + scrollback(0); +} + +static void boot_it(void) +{ + ctrl_alt_del(); +} + +static void compose(void) +{ + dead_key_next = 1; +} + +int spawnpid, spawnsig; + +static void spawn_console(void) +{ + if (spawnpid) + if(kill_proc(spawnpid, spawnsig, 1)) + spawnpid = 0; +} + +static void SAK(void) +{ + /* + * SAK should also work in all raw modes and reset + * them properly. + */ + + do_SAK(tty); + reset_vc(fg_console); +#if 0 + do_unblank_screen(); /* not in interrupt routine? */ +#endif +} + +static void do_ignore(unsigned char value, char up_flag) +{ +} + +static void do_null() +{ + compute_shiftstate(); +} + +static void do_spec(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value >= SIZE(spec_fn_table)) + return; + if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) && + !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) + return; + spec_fn_table[value](); +} + +static void do_lowercase(unsigned char value, char up_flag) +{ + printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n"); +} + +static void do_self(unsigned char value, char up_flag) +{ + if (up_flag) + return; /* no action, if this is a key release */ + + if (diacr) + value = handle_diacr(value); + + if (dead_key_next) { + dead_key_next = 0; + diacr = value; + return; + } + + put_queue(value); +} + +#define A_GRAVE '`' +#define A_ACUTE '\'' +#define A_CFLEX '^' +#define A_TILDE '~' +#define A_DIAER '"' +#define A_CEDIL ',' +static unsigned char ret_diacr[NR_DEAD] = + {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL }; + +/* Obsolete - for backwards compatibility only */ +static void do_dead(unsigned char value, char up_flag) +{ + value = ret_diacr[value]; + do_dead2(value,up_flag); +} + +/* + * Handle dead key. Note that we now may have several + * dead keys modifying the same character. Very useful + * for Vietnamese. + */ +static void do_dead2(unsigned char value, char up_flag) +{ + if (up_flag) + return; + + diacr = (diacr ? handle_diacr(value) : value); +} + + +/* + * We have a combining character DIACR here, followed by the character CH. + * If the combination occurs in the table, return the corresponding value. + * Otherwise, if CH is a space or equals DIACR, return DIACR. + * Otherwise, conclude that DIACR was not combining after all, + * queue it and return CH. + */ +unsigned char handle_diacr(unsigned char ch) +{ + int d = diacr; + int i; + + diacr = 0; + + for (i = 0; i < accent_table_size; i++) { + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; + } + + if (ch == ' ' || ch == d) + return d; + + put_queue(d); + return ch; +} + +static void do_cons(unsigned char value, char up_flag) +{ + if (up_flag) + return; + set_console(value); +} + +static void do_fn(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value < SIZE(func_table)) { + if (func_table[value]) + puts_queue(func_table[value]); + } else + printk(KERN_ERR "do_fn called with value=%d\n", value); +} + +static void do_pad(unsigned char value, char up_flag) +{ + static const char *pad_chars = "0123456789+-*/\015,.?()"; + static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; + + if (up_flag) + return; /* no action, if this is a key release */ + + /* kludge... shift forces cursor/number keys */ + if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) { + applkey(app_map[value], 1); + return; + } + + if (!vc_kbd_led(kbd,VC_NUMLOCK)) + switch (value) { + case KVAL(K_PCOMMA): + case KVAL(K_PDOT): + do_fn(KVAL(K_REMOVE), 0); + return; + case KVAL(K_P0): + do_fn(KVAL(K_INSERT), 0); + return; + case KVAL(K_P1): + do_fn(KVAL(K_SELECT), 0); + return; + case KVAL(K_P2): + do_cur(KVAL(K_DOWN), 0); + return; + case KVAL(K_P3): + do_fn(KVAL(K_PGDN), 0); + return; + case KVAL(K_P4): + do_cur(KVAL(K_LEFT), 0); + return; + case KVAL(K_P6): + do_cur(KVAL(K_RIGHT), 0); + return; + case KVAL(K_P7): + do_fn(KVAL(K_FIND), 0); + return; + case KVAL(K_P8): + do_cur(KVAL(K_UP), 0); + return; + case KVAL(K_P9): + do_fn(KVAL(K_PGUP), 0); + return; + case KVAL(K_P5): + applkey('G', vc_kbd_mode(kbd, VC_APPLIC)); + return; + } + + put_queue(pad_chars[value]); + if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) + put_queue(10); +} + +static void do_cur(unsigned char value, char up_flag) +{ + static const char *cur_chars = "BDCA"; + if (up_flag) + return; + + applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); +} + +static void do_shift(unsigned char value, char up_flag) +{ + int old_state = shift_state; + + if (rep) + return; + + /* Mimic typewriter: + a CapsShift key acts like Shift but undoes CapsLock */ + if (value == KVAL(K_CAPSSHIFT)) { + value = KVAL(K_SHIFT); + if (!up_flag) + clr_vc_kbd_led(kbd, VC_CAPSLOCK); + } + + if (up_flag) { + /* handle the case that two shift or control + keys are depressed simultaneously */ + if (k_down[value]) + k_down[value]--; + } else + k_down[value]++; + + if (k_down[value]) + shift_state |= (1 << value); + else + shift_state &= ~ (1 << value); + + /* kludge */ + if (up_flag && shift_state != old_state && npadch != -1) { + if (kbd->kbdmode == VC_UNICODE) + to_utf8(npadch & 0xffff); + else + put_queue(npadch & 0xff); + npadch = -1; + } +} + +/* called after returning from RAW mode or when changing consoles - + recompute k_down[] and shift_state from key_down[] */ +/* maybe called when keymap is undefined, so that shiftkey release is seen */ +void compute_shiftstate(void) +{ + int i, j, k, sym, val; + + shift_state = 0; + for(i=0; i < SIZE(k_down); i++) + k_down[i] = 0; + + for(i=0; i < SIZE(key_down); i++) + if(key_down[i]) { /* skip this word if not a single bit on */ + k = i*BITS_PER_LONG; + for(j=0; jlockstate ^ kbd->slockstate]) { + kbd->slockstate = 0; + chg_vc_kbd_slock(kbd, value); + } +} + +/* + * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, + * or (ii) whatever pattern of lights people want to show using KDSETLED, + * or (iii) specified bits of specified words in kernel memory. + */ + +static unsigned char ledstate = 0xff; /* undefined */ +static unsigned char ledioctl; + +unsigned char getledstate(void) { + return ledstate; +} + +void setledstate(struct kbd_struct *kbd, unsigned int led) { + if (!(led & ~7)) { + ledioctl = led; + kbd->ledmode = LED_SHOW_IOCTL; + } else + kbd->ledmode = LED_SHOW_FLAGS; + set_leds(); +} + +static struct ledptr { + unsigned int *addr; + unsigned int mask; + unsigned char valid:1; +} ledptrs[3]; + +void register_leds(int console, unsigned int led, + unsigned int *addr, unsigned int mask) { + struct kbd_struct *kbd = kbd_table + console; + if (led < 3) { + ledptrs[led].addr = addr; + ledptrs[led].mask = mask; + ledptrs[led].valid = 1; + kbd->ledmode = LED_SHOW_MEM; + } else + kbd->ledmode = LED_SHOW_FLAGS; +} + +static inline unsigned char getleds(void){ + struct kbd_struct *kbd = kbd_table + fg_console; + unsigned char leds; + + if (kbd->ledmode == LED_SHOW_IOCTL) + return ledioctl; + leds = kbd->ledflagstate; + if (kbd->ledmode == LED_SHOW_MEM) { + if (ledptrs[0].valid) { + if (*ledptrs[0].addr & ledptrs[0].mask) + leds |= 1; + else + leds &= ~1; + } + if (ledptrs[1].valid) { + if (*ledptrs[1].addr & ledptrs[1].mask) + leds |= 2; + else + leds &= ~2; + } + if (ledptrs[2].valid) { + if (*ledptrs[2].addr & ledptrs[2].mask) + leds |= 4; + else + leds &= ~4; + } + } + return leds; +} + +/* + * This routine is the bottom half of the keyboard interrupt + * routine, and runs with all interrupts enabled. It does + * console changing, led setting and copy_to_cooked, which can + * take a reasonably long time. + * + * Aside from timing (which isn't really that important for + * keyboard interrupts as they happen often), using the software + * interrupt routines for this thing allows us to easily mask + * this when we don't want any of the above to happen. Not yet + * used, but this allows for easy and efficient race-condition + * prevention later on. + */ +static void kbd_bh(void) +{ + unsigned char leds = getleds(); + + if (leds != ledstate) { + ledstate = leds; + kbd_leds(leds); + } +} + +int __init kbd_init(void) +{ + int i; + struct kbd_struct kbd0; + extern struct tty_driver console_driver; + + kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; + kbd0.ledmode = LED_SHOW_FLAGS; + kbd0.lockstate = KBD_DEFLOCK; + kbd0.slockstate = 0; + kbd0.modeflags = KBD_DEFMODE; + kbd0.kbdmode = VC_XLATE; + + for (i = 0 ; i < MAX_NR_CONSOLES ; i++) + kbd_table[i] = kbd0; + + ttytab = console_driver.table; + + kbd_init_hw(); + init_bh(KEYBOARD_BH, kbd_bh); + mark_bh(KEYBOARD_BH); + + acpi_kbd = acpi_register(&acpi_kbd_info, 0); + + return 0; +} diff -urN 2.3.29pre1/drivers/char/keyboard.c.rej 2.3.29pre1-ikd/drivers/char/keyboard.c.rej --- 2.3.29pre1/drivers/char/keyboard.c.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/drivers/char/keyboard.c.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,18 @@ +*************** +*** 42,47 **** + #include + #include + #include + + #define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +--- 42,50 ---- + #include + #include + #include ++ #if defined(CONFIG_KDB) ++ #include ++ #endif + + #define SIZE(x) (sizeof(x)/sizeof((x)[0])) + diff -urN 2.3.29pre1/drivers/char/keyboard.c.~1~ 2.3.29pre1-ikd/drivers/char/keyboard.c.~1~ --- 2.3.29pre1/drivers/char/keyboard.c.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/drivers/char/keyboard.c.~1~ Mon Nov 22 16:56:24 1999 @@ -0,0 +1,941 @@ +/* + * linux/drivers/char/keyboard.c + * + * Written for linux by Johan Myreen as a translation from + * the assembly version by Linus (with diacriticals added) + * + * Some additional features added by Christoph Niemann (ChN), March 1993 + * + * Loadable keymaps by Risto Kankkunen, May 1993 + * + * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993 + * Added decr/incr_console, dynamic keymaps, Unicode support, + * dynamic function/string keys, led setting, Sept 1994 + * `Sticky' modifier keys, 951006. + * + * 11-11-96: SAK should now work in the raw mode (Martin Mares) + * + * Modified to provide 'generic' keyboard support by Hamish Macdonald + * Merge with the m68k keyboard driver and split-off of the PC low-level + * parts by Geert Uytterhoeven, May 1997 + * + * 27-05-97: Added support for the Magic SysRq Key (Martin Mares) + * 30-07-98: Dead keys redone, aeb@cwi.nl. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +#ifndef KBD_DEFMODE +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) +#endif + +#ifndef KBD_DEFLEDS +/* + * Some laptops take the 789uiojklm,. keys as number pad when NumLock + * is on. This seems a good reason to start with NumLock off. + */ +#define KBD_DEFLEDS 0 +#endif + +#ifndef KBD_DEFLOCK +#define KBD_DEFLOCK 0 +#endif + +EXPORT_SYMBOL(handle_scancode); + +extern void ctrl_alt_del(void); + +DECLARE_WAIT_QUEUE_HEAD(keypress_wait); +struct console; + +int keyboard_wait_for_keypress(struct console *co) +{ + sleep_on(&keypress_wait); + return 0; +} + +/* + * global state includes the following, and various static variables + * in this module: prev_scancode, shift_state, diacr, npadch, dead_key_next. + * (last_console is now a global variable) + */ + +/* shift state counters.. */ +static unsigned char k_down[NR_SHIFT] = {0, }; +/* keyboard key bitmap */ +static unsigned long key_down[256/BITS_PER_LONG] = { 0, }; + +static int dead_key_next = 0; +/* + * In order to retrieve the shift_state (for the mouse server), either + * the variable must be global, or a new procedure must be created to + * return the value. I chose the former way. + */ +int shift_state = 0; +static int npadch = -1; /* -1 or number assembled on pad */ +static unsigned char diacr = 0; +static char rep = 0; /* flag telling character repeat */ +struct kbd_struct kbd_table[MAX_NR_CONSOLES]; +static struct tty_struct **ttytab; +static struct kbd_struct * kbd = kbd_table; +static struct tty_struct * tty = NULL; + +void compute_shiftstate(void); + +typedef void (*k_hand)(unsigned char value, char up_flag); +typedef void (k_handfn)(unsigned char value, char up_flag); + +static k_handfn + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, + do_ignore; + +static k_hand key_handler[16] = { + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2, + do_ignore, do_ignore +}; + +/* Key types processed even in raw modes */ + +#define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT)) + +typedef void (*void_fnp)(void); +typedef void (void_fn)(void); + +static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, + SAK, decr_console, incr_console, spawn_console, bare_num; + +static void_fnp spec_fn_table[] = { + do_null, enter, show_ptregs, show_mem, + show_state, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, + boot_it, caps_on, compose, SAK, + decr_console, incr_console, spawn_console, bare_num +}; + +#define SPECIALS_ALLOWED_IN_RAW_MODE (1 << KVAL(K_SAK)) + +/* maximum values each key_handler can handle */ +const int max_vals[] = { + 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, + 255, NR_ASCII - 1, NR_LOCK - 1, 255, + NR_LOCK - 1, 255 +}; + +const int NR_TYPES = SIZE(max_vals); + +/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */ +void put_queue(int); +static unsigned char handle_diacr(unsigned char); + +/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ +struct pt_regs * kbd_pt_regs; + +#ifdef CONFIG_MAGIC_SYSRQ +static int sysrq_pressed; +int sysrq_enabled = 1; +#endif + +static struct acpi_dev_info acpi_kbd_info = {ACPI_SYS_DEV, ACPI_KBC_HID, NULL}; +static struct acpi_dev *acpi_kbd = NULL; + +/* + * Many other routines do put_queue, but I think either + * they produce ASCII, or they produce some user-assigned + * string, and in both cases we might assume that it is + * in utf-8 already. + */ +void to_utf8(ushort c) { + if (c < 0x80) + put_queue(c); /* 0******* */ + else if (c < 0x800) { + put_queue(0xc0 | (c >> 6)); /* 110***** 10****** */ + put_queue(0x80 | (c & 0x3f)); + } else { + put_queue(0xe0 | (c >> 12)); /* 1110**** 10****** 10****** */ + put_queue(0x80 | ((c >> 6) & 0x3f)); + put_queue(0x80 | (c & 0x3f)); + } + /* UTF-8 is defined for words of up to 31 bits, + but we need only 16 bits here */ +} + +/* + * Translation of escaped scancodes to keycodes. + * This is now user-settable (for machines were it makes sense). + */ + +int setkeycode(unsigned int scancode, unsigned int keycode) +{ + return kbd_setkeycode(scancode, keycode); +} + +int getkeycode(unsigned int scancode) +{ + return kbd_getkeycode(scancode); +} + +void handle_scancode(unsigned char scancode, int down) +{ + unsigned char keycode; + char up_flag = down ? 0 : 0200; + char raw_mode; + + acpi_access(acpi_kbd); + + do_poke_blanked_console = 1; + mark_bh(CONSOLE_BH); + add_keyboard_randomness(scancode | up_flag); + + tty = ttytab? ttytab[fg_console]: NULL; + if (tty && (!tty->driver_data)) { + /* + * We touch the tty structure via the the ttytab array + * without knowing whether or not tty is open, which + * is inherently dangerous. We currently rely on that + * fact that console_open sets tty->driver_data when + * it opens it, and clears it when it closes it. + */ + tty = NULL; + } + kbd = kbd_table + fg_console; + if ((raw_mode = (kbd->kbdmode == VC_RAW))) { + put_queue(scancode | up_flag); + /* we do not return yet, because we want to maintain + the key_down array, so that we have the correct + values when finishing RAW mode or when changing VT's */ + } + + /* + * Convert scancode to keycode + */ + if (!kbd_translate(scancode, &keycode, raw_mode)) + return; + + /* + * At this point the variable `keycode' contains the keycode. + * Note: the keycode must not be 0 (++Geert: on m68k 0 is valid). + * We keep track of the up/down status of the key, and + * return the keycode if in MEDIUMRAW mode. + */ + + if (up_flag) { + rep = 0; + if(!test_and_clear_bit(keycode, key_down)) + up_flag = kbd_unexpected_up(keycode); + } else + rep = test_and_set_bit(keycode, key_down); + +#if defined(CONFIG_KDB) + if (!up_flag && (keycode == E1_PAUSE)) { + kdb(KDB_REASON_KEYBOARD, 0, kbd_pt_regs); + } +#endif + +#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ + if (keycode == SYSRQ_KEY) { + sysrq_pressed = !up_flag; + return; + } else if (sysrq_pressed) { + if (!up_flag && sysrq_enabled) { + handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty); + return; + } + } +#endif + + if (kbd->kbdmode == VC_MEDIUMRAW) { + /* soon keycodes will require more than one byte */ + put_queue(keycode + up_flag); + raw_mode = 1; /* Most key classes will be ignored */ + } + + /* + * Small change in philosophy: earlier we defined repetition by + * rep = keycode == prev_keycode; + * prev_keycode = keycode; + * but now by the fact that the depressed key was down already. + * Does this ever make a difference? Yes. + */ + + /* + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. + */ + if (!rep || + (vc_kbd_mode(kbd,VC_REPEAT) && tty && + (L_ECHO(tty) || (tty->driver.chars_in_buffer(tty) == 0)))) { + u_short keysym; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = (shift_state | kbd->slockstate) ^ + kbd->lockstate; + ushort *key_map = key_maps[shift_final]; + + if (key_map != NULL) { + keysym = key_map[keycode]; + type = KTYP(keysym); + + if (type >= 0xf0) { + type -= 0xf0; + if (raw_mode && ! (TYPES_ALLOWED_IN_RAW_MODE & (1 << type))) + return; + if (type == KT_LETTER) { + type = KT_LATIN; + if (vc_kbd_led(kbd, VC_CAPSLOCK)) { + key_map = key_maps[shift_final ^ (1<slockstate = 0; + } else { + /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */ + if (!up_flag && !raw_mode) + to_utf8(keysym); + } + } else { + /* maybe beep? */ + /* we have at least to update shift_state */ +#if 1 /* how? two almost equivalent choices follow */ + compute_shiftstate(); + kbd->slockstate = 0; /* play it safe */ +#else + keysym = U(plain_map[keycode]); + type = KTYP(keysym); + if (type == KT_SHIFT) + (*key_handler[type])(keysym & 0xff, up_flag); +#endif + } + } +} + + +void put_queue(int ch) +{ + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + con_schedule_flip(tty); + } +} + +static void puts_queue(char *cp) +{ + wake_up(&keypress_wait); + if (!tty) + return; + + while (*cp) { + tty_insert_flip_char(tty, *cp, 0); + cp++; + } + con_schedule_flip(tty); +} + +static void applkey(int key, char mode) +{ + static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; + + buf[1] = (mode ? 'O' : '['); + buf[2] = key; + puts_queue(buf); +} + +static void enter(void) +{ + if (diacr) { + put_queue(diacr); + diacr = 0; + } + put_queue(13); + if (vc_kbd_mode(kbd,VC_CRLF)) + put_queue(10); +} + +static void caps_toggle(void) +{ + if (rep) + return; + chg_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +static void caps_on(void) +{ + if (rep) + return; + set_vc_kbd_led(kbd, VC_CAPSLOCK); +} + +static void show_ptregs(void) +{ + if (kbd_pt_regs) + show_regs(kbd_pt_regs); +} + +static void hold(void) +{ + if (rep || !tty) + return; + + /* + * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); + * these routines are also activated by ^S/^Q. + * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) + */ + if (tty->stopped) + start_tty(tty); + else + stop_tty(tty); +} + +static void num(void) +{ + if (vc_kbd_mode(kbd,VC_APPLIC)) + applkey('P', 1); + else + bare_num(); +} + +/* + * Bind this to Shift-NumLock if you work in application keypad mode + * but want to be able to change the NumLock flag. + * Bind this to NumLock if you prefer that the NumLock key always + * changes the NumLock flag. + */ +static void bare_num(void) +{ + if (!rep) + chg_vc_kbd_led(kbd,VC_NUMLOCK); +} + +static void lastcons(void) +{ + /* switch to the last used console, ChN */ + set_console(last_console); +} + +static void decr_console(void) +{ + int i; + + for (i = fg_console-1; i != fg_console; i--) { + if (i == -1) + i = MAX_NR_CONSOLES-1; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void incr_console(void) +{ + int i; + + for (i = fg_console+1; i != fg_console; i++) { + if (i == MAX_NR_CONSOLES) + i = 0; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void send_intr(void) +{ + if (!tty) + return; + tty_insert_flip_char(tty, 0, TTY_BREAK); + con_schedule_flip(tty); +} + +static void scroll_forw(void) +{ + scrollfront(0); +} + +static void scroll_back(void) +{ + scrollback(0); +} + +static void boot_it(void) +{ + ctrl_alt_del(); +} + +static void compose(void) +{ + dead_key_next = 1; +} + +int spawnpid, spawnsig; + +static void spawn_console(void) +{ + if (spawnpid) + if(kill_proc(spawnpid, spawnsig, 1)) + spawnpid = 0; +} + +static void SAK(void) +{ + /* + * SAK should also work in all raw modes and reset + * them properly. + */ + + do_SAK(tty); + reset_vc(fg_console); +#if 0 + do_unblank_screen(); /* not in interrupt routine? */ +#endif +} + +static void do_ignore(unsigned char value, char up_flag) +{ +} + +static void do_null() +{ + compute_shiftstate(); +} + +static void do_spec(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value >= SIZE(spec_fn_table)) + return; + if ((kbd->kbdmode == VC_RAW || kbd->kbdmode == VC_MEDIUMRAW) && + !(SPECIALS_ALLOWED_IN_RAW_MODE & (1 << value))) + return; + spec_fn_table[value](); +} + +static void do_lowercase(unsigned char value, char up_flag) +{ + printk(KERN_ERR "keyboard.c: do_lowercase was called - impossible\n"); +} + +static void do_self(unsigned char value, char up_flag) +{ + if (up_flag) + return; /* no action, if this is a key release */ + + if (diacr) + value = handle_diacr(value); + + if (dead_key_next) { + dead_key_next = 0; + diacr = value; + return; + } + + put_queue(value); +} + +#define A_GRAVE '`' +#define A_ACUTE '\'' +#define A_CFLEX '^' +#define A_TILDE '~' +#define A_DIAER '"' +#define A_CEDIL ',' +static unsigned char ret_diacr[NR_DEAD] = + {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL }; + +/* Obsolete - for backwards compatibility only */ +static void do_dead(unsigned char value, char up_flag) +{ + value = ret_diacr[value]; + do_dead2(value,up_flag); +} + +/* + * Handle dead key. Note that we now may have several + * dead keys modifying the same character. Very useful + * for Vietnamese. + */ +static void do_dead2(unsigned char value, char up_flag) +{ + if (up_flag) + return; + + diacr = (diacr ? handle_diacr(value) : value); +} + + +/* + * We have a combining character DIACR here, followed by the character CH. + * If the combination occurs in the table, return the corresponding value. + * Otherwise, if CH is a space or equals DIACR, return DIACR. + * Otherwise, conclude that DIACR was not combining after all, + * queue it and return CH. + */ +unsigned char handle_diacr(unsigned char ch) +{ + int d = diacr; + int i; + + diacr = 0; + + for (i = 0; i < accent_table_size; i++) { + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; + } + + if (ch == ' ' || ch == d) + return d; + + put_queue(d); + return ch; +} + +static void do_cons(unsigned char value, char up_flag) +{ + if (up_flag) + return; + set_console(value); +} + +static void do_fn(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value < SIZE(func_table)) { + if (func_table[value]) + puts_queue(func_table[value]); + } else + printk(KERN_ERR "do_fn called with value=%d\n", value); +} + +static void do_pad(unsigned char value, char up_flag) +{ + static const char *pad_chars = "0123456789+-*/\015,.?()"; + static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; + + if (up_flag) + return; /* no action, if this is a key release */ + + /* kludge... shift forces cursor/number keys */ + if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) { + applkey(app_map[value], 1); + return; + } + + if (!vc_kbd_led(kbd,VC_NUMLOCK)) + switch (value) { + case KVAL(K_PCOMMA): + case KVAL(K_PDOT): + do_fn(KVAL(K_REMOVE), 0); + return; + case KVAL(K_P0): + do_fn(KVAL(K_INSERT), 0); + return; + case KVAL(K_P1): + do_fn(KVAL(K_SELECT), 0); + return; + case KVAL(K_P2): + do_cur(KVAL(K_DOWN), 0); + return; + case KVAL(K_P3): + do_fn(KVAL(K_PGDN), 0); + return; + case KVAL(K_P4): + do_cur(KVAL(K_LEFT), 0); + return; + case KVAL(K_P6): + do_cur(KVAL(K_RIGHT), 0); + return; + case KVAL(K_P7): + do_fn(KVAL(K_FIND), 0); + return; + case KVAL(K_P8): + do_cur(KVAL(K_UP), 0); + return; + case KVAL(K_P9): + do_fn(KVAL(K_PGUP), 0); + return; + case KVAL(K_P5): + applkey('G', vc_kbd_mode(kbd, VC_APPLIC)); + return; + } + + put_queue(pad_chars[value]); + if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) + put_queue(10); +} + +static void do_cur(unsigned char value, char up_flag) +{ + static const char *cur_chars = "BDCA"; + if (up_flag) + return; + + applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); +} + +static void do_shift(unsigned char value, char up_flag) +{ + int old_state = shift_state; + + if (rep) + return; + + /* Mimic typewriter: + a CapsShift key acts like Shift but undoes CapsLock */ + if (value == KVAL(K_CAPSSHIFT)) { + value = KVAL(K_SHIFT); + if (!up_flag) + clr_vc_kbd_led(kbd, VC_CAPSLOCK); + } + + if (up_flag) { + /* handle the case that two shift or control + keys are depressed simultaneously */ + if (k_down[value]) + k_down[value]--; + } else + k_down[value]++; + + if (k_down[value]) + shift_state |= (1 << value); + else + shift_state &= ~ (1 << value); + + /* kludge */ + if (up_flag && shift_state != old_state && npadch != -1) { + if (kbd->kbdmode == VC_UNICODE) + to_utf8(npadch & 0xffff); + else + put_queue(npadch & 0xff); + npadch = -1; + } +} + +/* called after returning from RAW mode or when changing consoles - + recompute k_down[] and shift_state from key_down[] */ +/* maybe called when keymap is undefined, so that shiftkey release is seen */ +void compute_shiftstate(void) +{ + int i, j, k, sym, val; + + shift_state = 0; + for(i=0; i < SIZE(k_down); i++) + k_down[i] = 0; + + for(i=0; i < SIZE(key_down); i++) + if(key_down[i]) { /* skip this word if not a single bit on */ + k = i*BITS_PER_LONG; + for(j=0; jlockstate ^ kbd->slockstate]) { + kbd->slockstate = 0; + chg_vc_kbd_slock(kbd, value); + } +} + +/* + * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, + * or (ii) whatever pattern of lights people want to show using KDSETLED, + * or (iii) specified bits of specified words in kernel memory. + */ + +static unsigned char ledstate = 0xff; /* undefined */ +static unsigned char ledioctl; + +unsigned char getledstate(void) { + return ledstate; +} + +void setledstate(struct kbd_struct *kbd, unsigned int led) { + if (!(led & ~7)) { + ledioctl = led; + kbd->ledmode = LED_SHOW_IOCTL; + } else + kbd->ledmode = LED_SHOW_FLAGS; + set_leds(); +} + +static struct ledptr { + unsigned int *addr; + unsigned int mask; + unsigned char valid:1; +} ledptrs[3]; + +void register_leds(int console, unsigned int led, + unsigned int *addr, unsigned int mask) { + struct kbd_struct *kbd = kbd_table + console; + if (led < 3) { + ledptrs[led].addr = addr; + ledptrs[led].mask = mask; + ledptrs[led].valid = 1; + kbd->ledmode = LED_SHOW_MEM; + } else + kbd->ledmode = LED_SHOW_FLAGS; +} + +static inline unsigned char getleds(void){ + struct kbd_struct *kbd = kbd_table + fg_console; + unsigned char leds; + + if (kbd->ledmode == LED_SHOW_IOCTL) + return ledioctl; + leds = kbd->ledflagstate; + if (kbd->ledmode == LED_SHOW_MEM) { + if (ledptrs[0].valid) { + if (*ledptrs[0].addr & ledptrs[0].mask) + leds |= 1; + else + leds &= ~1; + } + if (ledptrs[1].valid) { + if (*ledptrs[1].addr & ledptrs[1].mask) + leds |= 2; + else + leds &= ~2; + } + if (ledptrs[2].valid) { + if (*ledptrs[2].addr & ledptrs[2].mask) + leds |= 4; + else + leds &= ~4; + } + } + return leds; +} + +/* + * This routine is the bottom half of the keyboard interrupt + * routine, and runs with all interrupts enabled. It does + * console changing, led setting and copy_to_cooked, which can + * take a reasonably long time. + * + * Aside from timing (which isn't really that important for + * keyboard interrupts as they happen often), using the software + * interrupt routines for this thing allows us to easily mask + * this when we don't want any of the above to happen. Not yet + * used, but this allows for easy and efficient race-condition + * prevention later on. + */ +static void kbd_bh(void) +{ + unsigned char leds = getleds(); + + if (leds != ledstate) { + ledstate = leds; + kbd_leds(leds); + } +} + +int __init kbd_init(void) +{ + int i; + struct kbd_struct kbd0; + extern struct tty_driver console_driver; + + kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; + kbd0.ledmode = LED_SHOW_FLAGS; + kbd0.lockstate = KBD_DEFLOCK; + kbd0.slockstate = 0; + kbd0.modeflags = KBD_DEFMODE; + kbd0.kbdmode = VC_XLATE; + + for (i = 0 ; i < MAX_NR_CONSOLES ; i++) + kbd_table[i] = kbd0; + + ttytab = console_driver.table; + + kbd_init_hw(); + init_bh(KEYBOARD_BH, kbd_bh); + mark_bh(KEYBOARD_BH); + + acpi_kbd = acpi_register(&acpi_kbd_info, 0); + + return 0; +} diff -urN 2.3.29pre1/drivers/char/serial.c 2.3.29pre1-ikd/drivers/char/serial.c --- 2.3.29pre1/drivers/char/serial.c Sun Nov 21 03:20:44 1999 +++ 2.3.29pre1-ikd/drivers/char/serial.c Mon Nov 22 17:03:47 1999 @@ -508,6 +508,21 @@ mark_bh(SERIAL_BH); } +#if defined(CONFIG_KDB) +#include +/* + * kdb_serial_line records the serial line number of the + * first serial console. kdb_info will be set upon receipt + * of the first ^A (which cannot happen until the port is + * opened and the interrupt handler attached). To enter + * kdb before this on a serial console-only system, you must + * use the 'kdb' flag to lilo and set the appropriate breakpoints. + */ + +extern int kdb_port; +static int kdb_serial_line = -1; +#endif /* CONFIG_KDB */ + static _INLINE_ void receive_chars(struct async_struct *info, int *status, struct pt_regs * regs) { @@ -519,6 +534,13 @@ icount = &info->state->icount; do { ch = serial_inp(info, UART_RX); +#if defined(CONFIG_KDB) + if ((info->line == kdb_serial_line) + && (ch == 1)) /* CNTRL-A */ { + kdb(KDB_REASON_KEYBOARD, 0, regs); + break; + } +#endif if (tty->flip.count >= TTY_FLIPBUF_SIZE) goto ignore_char; *tty->flip.char_buf_ptr = ch; @@ -4657,12 +4679,15 @@ #if defined(CONFIG_KDB) /* - * Remember I/O port for kdb + * Remember the line number of the first serial + * console. We'll make this the kdb serial console too. */ - if (kdb_port == 0 ) + if (kdb_serial_line == -1) { + kdb_serial_line = co->index; kdb_port = ser->port; + } #endif /* CONFIG_KDB */ - + return 0; } diff -urN 2.3.29pre1/drivers/char/serial.c.orig 2.3.29pre1-ikd/drivers/char/serial.c.orig --- 2.3.29pre1/drivers/char/serial.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/drivers/char/serial.c.orig Sun Nov 21 03:20:44 1999 @@ -0,0 +1,4696 @@ +/* + * linux/drivers/char/serial.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, + * 1998, 1999 Theodore Ts'o + * + * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now + * much more extensible to support other serial cards based on the + * 16450/16550A UART's. Added support for the AST FourPort and the + * Accent Async board. + * + * set_serial_info fixed to set the flags, custom divisor, and uart + * type fields. Fix suggested by Michael K. Johnson 12/12/92. + * + * 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis + * + * 03/96: Modularised by Angelo Haritsis + * + * rs_set_termios fixed to look also for changes of the input + * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK. + * Bernd Anhäupl 05/17/96. + * + * 1/97: Extended dumb serial ports are a config option now. + * Saves 4k. Michael A. Griffith + * + * 8/97: Fix bug in rs_set_termios with RTS + * Stanislav V. Voronyi + * + * 3/98: Change the IRQ detection, use of probe_irq_o*(), + * supress TIOCSERGWILD and TIOCSERSWILD + * Etienne Lorrain + * + * 4/98: Added changes to support the ARM architecture proposed by + * Russell King + * + * 5/99: Updated to include support for the XR16C850 and ST16C654 + * uarts. Stuart MacDonald + * + * 8/99: Generalized PCI support added. Theodore Ts'o + * + * This module exports the following rs232 io functions: + * + * int rs_init(void); + */ + +static char *serial_version = "4.91"; +static char *serial_revdate = "1999-11-17"; + +/* + * Serial driver configuration section. Here are the various options: + * + * CONFIG_HUB6 + * Enables support for the venerable Bell Technologies + * HUB6 card. + * + * CONFIG_SERIAL_MANY_PORTS + * Enables support for ports beyond the standard, stupid + * COM 1/2/3/4. + * + * CONFIG_SERIAL_MULTIPORT + * Enables support for special multiport board support. + * + * CONFIG_SERIAL_SHARE_IRQ + * Enables support for multiple serial ports on one IRQ + * + * CONFIG_SERIAL_DETECT_IRQ + * Enable the autodetection of IRQ on standart ports + * + * SERIAL_PARANOIA_CHECK + * Check the magic number for the async_structure where + * ever possible. + */ + +#include +#include + +#undef SERIAL_PARANOIA_CHECK +#define CONFIG_SERIAL_NOPAUSE_IO +#define SERIAL_DO_RESTART +#define CONFIG_SERIAL_PCI_MEMMAPPED + +#if 0 +/* These defines are normally controlled by the autoconf.h */ +#define CONFIG_SERIAL_MANY_PORTS +#define CONFIG_SERIAL_SHARE_IRQ +#define CONFIG_SERIAL_DETECT_IRQ +#define CONFIG_SERIAL_MULTIPORT +#define CONFIG_HUB6 +#endif + +#if (defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= 131072)) +#define ENABLE_SERIAL_PCI +#ifndef CONFIG_SERIAL_SHARE_IRQ +#define CONFIG_SERIAL_SHARE_IRQ +#endif +#ifndef CONFIG_SERIAL_MANY_PORTS +#define CONFIG_SERIAL_MANY_PORTS +#endif +#endif + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#undef SERIAL_DEBUG_PCI +#undef SERIAL_DEBUG_AUTOCONF + +/* Sanity checks */ + +#ifdef CONFIG_SERIAL_MULTIPORT +#ifndef CONFIG_SERIAL_SHARE_IRQ +#define CONFIG_SERIAL_SHARE_IRQ +#endif +#endif + +#ifdef CONFIG_HUB6 +#ifndef CONFIG_SERIAL_MANY_PORTS +#define CONFIG_SERIAL_MANY_PORTS +#endif +#ifndef CONFIG_SERIAL_SHARE_IRQ +#define CONFIG_SERIAL_SHARE_IRQ +#endif +#endif + +#define RS_STROBE_TIME (10*HZ) +#define RS_ISR_PASS_LIMIT 256 + +#if (defined(__i386__) && (CPU==386 || CPU==486)) +#define SERIAL_INLINE +#endif + +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ + kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) +#else +#define DBG_CNT(s) +#endif + +/* + * End of serial driver configuration section. + */ + +#if (LINUX_VERSION_CODE > 66304) +#define NEW_MODULES +#ifdef LOCAL_HEADERS /* We're building standalone */ +#define MODULE +#endif +#endif + +#ifdef NEW_MODULES +#ifdef MODVERSIONS +#include +#endif +#include +#else /* !NEW_MODULES */ +#ifdef MODVERSIONS +#define MODULE +#endif +#include +#endif /* NEW_MODULES */ + +#include +#ifdef LOCAL_HEADERS +#include "serial_local.h" +#else +#include +#include +#include +#include +#define LOCAL_VERSTRING "" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= 131343) +#include +#endif +#if (LINUX_VERSION_CODE >= 131336) +#include +#endif +#include +#ifdef CONFIG_SERIAL_CONSOLE +#include +#endif +#ifdef ENABLE_SERIAL_PCI +#include +#endif + +/* + * All of the compatibilty code so we can compile serial.c against + * older kernels is hidden in serial_compat.h + */ +#if (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */ +#include "serial_compat.h" +#endif + +#include +#include +#include +#include + +#ifdef CONFIG_MAC_SERIAL +#define SERIAL_DEV_OFFSET 2 +#else +#define SERIAL_DEV_OFFSET 0 +#endif + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#else +#define _INLINE_ +#endif + +static char *serial_name = "Serial driver"; + +static DECLARE_TASK_QUEUE(tq_serial); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* serial subtype definitions */ +#ifndef SERIAL_TYPE_NORMAL +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#endif + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* + * IRQ_timeout - How long the timeout should be for each IRQ + * should be after the IRQ has been active. + */ + +static struct async_struct *IRQ_ports[NR_IRQS]; +#ifdef CONFIG_SERIAL_MULTIPORT +static struct rs_multiport_struct rs_multiport[NR_IRQS]; +#endif +static int IRQ_timeout[NR_IRQS]; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console sercons; +static unsigned long break_pressed; /* break, really ... */ +#endif + +static unsigned detect_uart_irq (struct serial_state * state); +static void autoconfig(struct serial_state * info); +static void change_speed(struct async_struct *info, struct termios *old); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); + +/* + * Here we define the default xmit fifo size used for each type of + * UART + */ +static struct serial_uart_config uart_config[] = { + { "unknown", 1, 0 }, + { "8250", 1, 0 }, + { "16450", 1, 0 }, + { "16550", 1, 0 }, + { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "cirrus", 1, 0 }, /* usurped by cyclades.c */ + { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH }, + { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, + { "Startech", 1, 0}, /* usurped by cyclades.c */ + { "16C950", 128, UART_CLEAR_FIFO | UART_USE_FIFO}, + { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { 0, 0} +}; + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) + +#ifdef ENABLE_SERIAL_PCI +#define NR_PCI_BOARDS 8 +static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; +static int serial_pci_board_idx = 0; +#ifdef PCI_NUM_RESOURCES +#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start) +#else +#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r]) +#endif +#endif /* ENABLE_SERIAL_PCI */ + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +#ifdef DECLARE_MUTEX +static DECLARE_MUTEX(tmp_buf_sem); +#else +static struct semaphore tmp_buf_sem = MUTEX; +#endif + + +static inline int serial_paranoia_check(struct async_struct *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset) +{ + switch (info->io_type) { +#ifdef CONFIG_HUB6 + case SERIAL_IO_HUB6: + outb(info->hub6 - 1 + offset, info->port); + return inb(info->port+1); +#endif +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + case SERIAL_IO_MEM: + return readb(info->iomem_base + + (offset<iomem_reg_shift)); +#endif +#ifdef CONFIG_SERIAL_GSC + case SERIAL_IO_GSC: + return gsc_readb(info->iomem_base + offset); +#endif + default: + return inb(info->port + offset); + } +} + +static _INLINE_ void serial_out(struct async_struct *info, int offset, + int value) +{ + switch (info->io_type) { +#ifdef CONFIG_HUB6 + case SERIAL_IO_HUB6: + outb(info->hub6 - 1 + offset, info->port); + outb(value, info->port+1); + break; +#endif +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + case SERIAL_IO_MEM: + writeb(value, info->iomem_base + + (offset<iomem_reg_shift)); + break; +#endif +#ifdef CONFIG_SERIAL_GSC + case SERIAL_IO_GSC: + gsc_writeb(value, info->iomem_base + offset); + break; +#endif + default: + outb(value, info->port+offset); + } +} + +/* + * We used to support using pause I/O for certain machines. We + * haven't supported this for a while, but just in case it's badly + * needed for certain old 386 machines, I've left these #define's + * in.... + */ +#define serial_inp(info, offset) serial_in(info, offset) +#define serial_outp(info, offset, value) serial_out(info, offset, value) + + +/* + * For the 16C950 + */ +void serial_icr_write(struct async_struct *info, int offset, int value) +{ + serial_out(info, UART_SCR, offset); + serial_out(info, UART_ICR, value); +} + +unsigned int serial_icr_read(struct async_struct *info, int offset) +{ + int value; + + serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD); + serial_out(info, UART_SCR, offset); + value = serial_in(info, UART_ICR); + serial_icr_write(info, UART_ACR, info->ACR); + return value; +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if (info->IER & UART_IER_THRI) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + if (info->state->type == PORT_16C950) { + info->ACR |= UART_ACR_TXDIS; + serial_icr_write(info, UART_ACR, info->ACR); + } + restore_flags(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + if (info->state->type == PORT_16C950) { + info->ACR &= ~UART_ACR_TXDIS; + serial_icr_write(info, UART_ACR, info->ACR); + } + restore_flags(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void rs_sched_event(struct async_struct *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +static _INLINE_ void receive_chars(struct async_struct *info, + int *status, struct pt_regs * regs) +{ + struct tty_struct *tty = info->tty; + unsigned char ch; + int ignored = 0; + struct async_icount *icount; + + icount = &info->state->icount; + do { + ch = serial_inp(info, UART_RX); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, *status); +#endif + *tty->flip.flag_buf_ptr = 0; + if (*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE)) { + /* + * For statistics only + */ + if (*status & UART_LSR_BI) { + *status &= ~(UART_LSR_FE | UART_LSR_PE); + icount->brk++; + } else if (*status & UART_LSR_PE) + icount->parity++; + else if (*status & UART_LSR_FE) + icount->frame++; + if (*status & UART_LSR_OE) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (*status & info->ignore_status_mask) { + if (++ignored > 100) + break; + goto ignore_char; + } + *status &= info->read_status_mask; + + if (*status & (UART_LSR_BI)) { +#ifdef SERIAL_DEBUG_INTR + printk("handling break...."); +#endif +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) + if (info->line == sercons.index) { + if (!break_pressed) { + break_pressed = jiffies; + goto ignore_char; + } + break_pressed = 0; + } +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (*status & UART_LSR_PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (*status & UART_LSR_FE) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (*status & UART_LSR_OE) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + } + } +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) + if (break_pressed && info->line == sercons.index) { + if (ch != 0 && + time_before(jiffies, break_pressed + HZ*5)) { + handle_sysrq(ch, regs, NULL, NULL); + break_pressed = 0; + goto ignore_char; + } + break_pressed = 0; + } +#endif + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + *status = serial_inp(info, UART_LSR); + } while (*status & UART_LSR_DR); +#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ + tty_flip_buffer_push(tty); +#else + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); +#endif +} + +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) +{ + int count; + + if (info->x_char) { + serial_outp(info, UART_TX, info->x_char); + info->state->icount.tx++; + info->x_char = 0; + if (intr_done) + *intr_done = 0; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || + info->tty->hw_stopped) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + return; + } + + count = info->xmit_fifo_size; + do { + serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->state->icount.tx++; + if (--info->xmit_cnt <= 0) + break; + } while (--count > 0); + + if (info->xmit_cnt < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + if (intr_done) + *intr_done = 0; + + if (info->xmit_cnt <= 0) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } +} + +static _INLINE_ void check_modem_status(struct async_struct *info) +{ + int status; + struct async_icount *icount; + + status = serial_in(info, UART_MSR); + + if (status & UART_MSR_ANY_DELTA) { + icount = &info->state->icount; + /* update input line counters */ + if (status & UART_MSR_TERI) + icount->rng++; + if (status & UART_MSR_DDSR) + icount->dsr++; + if (status & UART_MSR_DDCD) { + icount->dcd++; +#ifdef CONFIG_HARD_PPS + if ((info->flags & ASYNC_HARDPPS_CD) && + (status & UART_MSR_DCD)) + hardpps(); +#endif + } + if (status & UART_MSR_DCTS) + icount->cts++; + wake_up_interruptible(&info->delta_msr_wait); + } + + if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) + printk("ttys%d CD now %s...", info->line, + (status & UART_MSR_DCD) ? "on" : "off"); +#endif + if (status & UART_MSR_DCD) + wake_up_interruptible(&info->open_wait); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { +#ifdef SERIAL_DEBUG_OPEN + printk("doing serial hangup..."); +#endif + if (info->tty) + tty_hangup(info->tty); + } + } + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty->hw_stopped) { + if (status & UART_MSR_CTS) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx start..."); +#endif + info->tty->hw_stopped = 0; + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return; + } + } else { + if (!(status & UART_MSR_CTS)) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx stop..."); +#endif + info->tty->hw_stopped = 1; + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + } + } +} + +#ifdef CONFIG_SERIAL_SHARE_IRQ +/* + * This is the serial driver's generic interrupt routine + */ +static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + struct async_struct * info; + int pass_counter = 0; + struct async_struct *end_mark = 0; +#ifdef CONFIG_SERIAL_MULTIPORT + int first_multi = 0; + struct rs_multiport_struct *multi; +#endif + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info) + return; + +#ifdef CONFIG_SERIAL_MULTIPORT + multi = &rs_multiport[irq]; + if (multi->port_monitor) + first_multi = inb(multi->port_monitor); +#endif + + do { + if (!info->tty || + (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { + if (!end_mark) + end_mark = info; + goto next; + } + end_mark = 0; + + info->last_active = jiffies; + + status = serial_inp(info, UART_LSR); +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (status & UART_LSR_DR) + receive_chars(info, &status, regs); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + + next: + info = info->next_port; + if (!info) { + info = IRQ_ports[irq]; + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#if 0 + printk("rs loop break\n"); +#endif + break; /* Prevent infinite loops */ + } + continue; + } + } while (end_mark != info); +#ifdef CONFIG_SERIAL_MULTIPORT + if (multi->port_monitor) + printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n", + info->state->irq, first_multi, + inb(multi->port_monitor)); +#endif +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} +#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */ + + +/* + * This is the serial driver's interrupt routine for a single port + */ +static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + int pass_counter = 0; + struct async_struct * info; +#ifdef CONFIG_SERIAL_MULTIPORT + int first_multi = 0; + struct rs_multiport_struct *multi; +#endif + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_single(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info || !info->tty) + return; + +#ifdef CONFIG_SERIAL_MULTIPORT + multi = &rs_multiport[irq]; + if (multi->port_monitor) + first_multi = inb(multi->port_monitor); +#endif + + do { + status = serial_inp(info, UART_LSR); +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (status & UART_LSR_DR) + receive_chars(info, &status, regs); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#if 0 + printk("rs_single loop break.\n"); +#endif + break; + } + } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); + info->last_active = jiffies; +#ifdef CONFIG_SERIAL_MULTIPORT + if (multi->port_monitor) + printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n", + info->state->irq, first_multi, + inb(multi->port_monitor)); +#endif +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + +#ifdef CONFIG_SERIAL_MULTIPORT +/* + * This is the serial driver's for multiport boards + */ +static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + struct async_struct * info; + int pass_counter = 0; + int first_multi= 0; + struct rs_multiport_struct *multi; + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_multi(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info) + return; + multi = &rs_multiport[irq]; + if (!multi->port1) { + /* Should never happen */ + printk("rs_interrupt_multi: NULL port1!\n"); + return; + } + if (multi->port_monitor) + first_multi = inb(multi->port_monitor); + + while (1) { + if (!info->tty || + (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) + goto next; + + info->last_active = jiffies; + + status = serial_inp(info, UART_LSR); +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (status & UART_LSR_DR) + receive_chars(info, &status, regs); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + + next: + info = info->next_port; + if (info) + continue; + + info = IRQ_ports[irq]; + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#if 1 + printk("rs_multi loop break\n"); +#endif + break; /* Prevent infinite loops */ + } + if (multi->port_monitor) + printk("rs port monitor irq %d: 0x%x, 0x%x\n", + info->state->irq, first_multi, + inb(multi->port_monitor)); + if ((inb(multi->port1) & multi->mask1) != multi->match1) + continue; + if (!multi->port2) + break; + if ((inb(multi->port2) & multi->mask2) != multi->match2) + continue; + if (!multi->port3) + break; + if ((inb(multi->port3) & multi->mask3) != multi->match3) + continue; + if (!multi->port4) + break; + if ((inb(multi->port4) & multi->mask4) != multi->match4) + continue; + break; + } +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} +#endif + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * by the serial driver to handle ports that do not have an interrupt + * (irq=0). This doesn't work very well for 16450's, but gives barely + * passable results for a 16550A. (Although at the expense of much + * CPU overhead). + */ +static void rs_timer(void) +{ + static unsigned long last_strobe = 0; + struct async_struct *info; + unsigned int i; + unsigned long flags; + + if ((jiffies - last_strobe) >= RS_STROBE_TIME) { + for (i=0; i < NR_IRQS; i++) { + info = IRQ_ports[i]; + if (!info) + continue; + save_flags(flags); cli(); +#ifdef CONFIG_SERIAL_SHARE_IRQ + if (info->next_port) { + do { + serial_out(info, UART_IER, 0); + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + info = info->next_port; + } while (info); +#ifdef CONFIG_SERIAL_MULTIPORT + if (rs_multiport[i].port1) + rs_interrupt_multi(i, NULL, NULL); + else +#endif + rs_interrupt(i, NULL, NULL); + } else +#endif /* CONFIG_SERIAL_SHARE_IRQ */ + rs_interrupt_single(i, NULL, NULL); + restore_flags(flags); + } + } + last_strobe = jiffies; + timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME; + timer_active |= 1 << RS_TIMER; + + if (IRQ_ports[0]) { + save_flags(flags); cli(); +#ifdef CONFIG_SERIAL_SHARE_IRQ + rs_interrupt(0, NULL, NULL); +#else + rs_interrupt_single(0, NULL, NULL); +#endif + restore_flags(flags); + + timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2; + } +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +/* + * This routine figures out the correct timeout for a particular IRQ. + * It uses the smallest timeout of all of the serial ports in a + * particular interrupt chain. Now only used for IRQ 0.... + */ +static void figure_IRQ_timeout(int irq) +{ + struct async_struct *info; + int timeout = 60*HZ; /* 60 seconds === a long time :-) */ + + info = IRQ_ports[irq]; + if (!info) { + IRQ_timeout[irq] = 60*HZ; + return; + } + while (info) { + if (info->timeout < timeout) + timeout = info->timeout; + info = info->next_port; + } + if (!irq) + timeout = timeout / 2; + IRQ_timeout[irq] = timeout ? timeout : 1; +} + +static int startup(struct async_struct * info) +{ + unsigned long flags; + int retval=0; + void (*handler)(int, void *, struct pt_regs *); + struct serial_state *state= info->state; + unsigned long page; +#ifdef CONFIG_SERIAL_MANY_PORTS + unsigned short ICP; +#endif + + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!CONFIGURED_SERIAL_PORT(state) || !state->type) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, state->irq); +#endif + + if (uart_config[info->state->type].flags & UART_STARTECH) { + /* Wake up UART */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + /* + * Turn off LCR == 0xBF so we actually set the IER + * register on the XR16C850 + */ + serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_IER, 0); + /* + * Now reset LCR so we can turn off the ECB bit + */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, 0); + /* + * For a XR16C850, we need to set the trigger levels + */ + if (info->state->type == PORT_16850) { + serial_outp(info, UART_FCTR, UART_FCTR_TRGD | + UART_FCTR_RX); + serial_outp(info, UART_TRG, UART_TRG_96); + serial_outp(info, UART_FCTR, UART_FCTR_TRGD | + UART_FCTR_TX); + serial_outp(info, UART_TRG, UART_TRG_96); + } + serial_outp(info, UART_LCR, 0); + } + + if (info->state->type == PORT_16750) { + /* Wake up UART */ + serial_outp(info, UART_IER, 0); + } + + if (info->state->type == PORT_16C950) { + /* Wake up and initialize UART */ + info->ACR = 0; + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_IER, 0); + serial_outp(info, UART_LCR, 0); + serial_icr_write(info, UART_CSR, 0); /* Reset the UART */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_LCR, 0); + } + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + if (uart_config[state->type].flags & UART_CLEAR_FIFO) { + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + serial_outp(info, UART_FCR, 0); + } + + /* + * Clear the interrupt registers. + */ + (void) serial_inp(info, UART_LSR); + (void) serial_inp(info, UART_RX); + (void) serial_inp(info, UART_IIR); + (void) serial_inp(info, UART_MSR); + + /* + * At this point there's no way the LSR could still be 0xFF; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (serial_inp(info, UART_LSR) == 0xff) { + printk("LSR safety check engaged!\n"); + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + } else + retval = -ENODEV; + goto errout; + } + + /* + * Allocate the IRQ if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { +#ifdef CONFIG_SERIAL_SHARE_IRQ + free_irq(state->irq, &IRQ_ports[state->irq]); +#ifdef CONFIG_SERIAL_MULTIPORT + if (rs_multiport[state->irq].port1) + handler = rs_interrupt_multi; + else +#endif + handler = rs_interrupt; +#else + retval = -EBUSY; + goto errout; +#endif /* CONFIG_SERIAL_SHARE_IRQ */ + } else + handler = rs_interrupt_single; + + retval = request_irq(state->irq, handler, SA_SHIRQ, + "serial", &IRQ_ports[state->irq]); + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; + } + goto errout; + } + } + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[state->irq]; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports[state->irq] = info; + figure_IRQ_timeout(state->irq); + + /* + * Now, initialize the UART + */ + serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + + info->MCR = 0; + if (info->tty->termios->c_cflag & CBAUD) + info->MCR = UART_MCR_DTR | UART_MCR_RTS; +#ifdef CONFIG_SERIAL_MANY_PORTS + if (info->flags & ASYNC_FOURPORT) { + if (state->irq == 0) + info->MCR |= UART_MCR_OUT1; + } else +#endif + { + if (state->irq != 0) + info->MCR |= UART_MCR_OUT2; + } + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + serial_outp(info, UART_MCR, info->MCR); + + /* + * Finally, enable interrupts + */ + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; + serial_outp(info, UART_IER, info->IER); /* enable interrupts */ + +#ifdef CONFIG_SERIAL_MANY_PORTS + if (info->flags & ASYNC_FOURPORT) { + /* Enable interrupts on the AST Fourport board */ + ICP = (info->port & 0xFE0) | 0x01F; + outb_p(0x80, ICP); + (void) inb_p(ICP); + } +#endif + + /* + * And clear the interrupt registers again for luck. + */ + (void)serial_inp(info, UART_LSR); + (void)serial_inp(info, UART_RX); + (void)serial_inp(info, UART_IIR); + (void)serial_inp(info, UART_MSR); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * Set up serial timers... + */ + timer_table[RS_TIMER].expires = jiffies + 2*HZ/100; + timer_active |= 1 << RS_TIMER; + + /* + * Set up the tty->alt_speed kludge + */ +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } +#endif + + /* + * and set the speed of the serial port + */ + change_speed(info, 0); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info) +{ + unsigned long flags; + struct serial_state *state; + int retval; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, &IRQ_ports[state->irq]); + retval = request_irq(state->irq, rs_interrupt_single, + SA_SHIRQ, "serial", + &IRQ_ports[state->irq]); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, &IRQ_ports[state->irq]); + } + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + info->IER = 0; + serial_outp(info, UART_IER, 0x00); /* disable all intrs */ +#ifdef CONFIG_SERIAL_MANY_PORTS + if (info->flags & ASYNC_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + (void) inb((info->port & 0xFE0) | 0x01F); + info->MCR |= UART_MCR_OUT1; + } else +#endif + info->MCR &= ~UART_MCR_OUT2; + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + + /* disable break condition */ + serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC); + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + serial_outp(info, UART_MCR, info->MCR); + + /* disable FIFO's */ + serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + serial_outp(info, UART_FCR, 0); + + (void)serial_in(info, UART_RX); /* read data port to reset things */ + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + if (uart_config[info->state->type].flags & UART_STARTECH) { + /* Arrange to enter sleep mode */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_IER, UART_IERX_SLEEP); + serial_outp(info, UART_LCR, 0); + } + if (info->state->type == PORT_16750) { + /* Arrange to enter sleep mode */ + serial_outp(info, UART_IER, UART_IERX_SLEEP); + } + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, + 600, 1200, 1800, 2400, 4800, 9600, 19200, + 38400, 57600, 115200, 230400, 460800, 0 }; + +static int tty_get_baud_rate(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned int cflag, i; + + cflag = tty->termios->c_cflag; + + i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~CBAUDEX; + if (i < 1 || i > 2) + tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i += 1; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i += 2; + } + return baud_table[i]; +} +#endif + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct async_struct *info, + struct termios *old_termios) +{ + int quot = 0, baud_base, baud; + unsigned cflag, cval, fcr = 0; + int bits; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!CONFIGURED_SERIAL_PORT(info)) + return; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: cval = 0x00; bits = 7; break; + case CS6: cval = 0x01; bits = 8; break; + case CS7: cval = 0x02; bits = 9; break; + case CS8: cval = 0x03; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: cval = 0x00; bits = 7; break; + } + if (cflag & CSTOPB) { + cval |= 0x04; + bits++; + } + if (cflag & PARENB) { + cval |= UART_LCR_PARITY; + bits++; + } + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + baud_base = info->state->baud_base; + if (info->state->type == PORT_16C950) { + if (baud <= baud_base) + serial_icr_write(info, UART_TCR, 0); + else if (baud <= 2*baud_base) { + serial_icr_write(info, UART_TCR, 0x8); + baud_base = baud_base * 2; + } else if (baud <= 4*baud_base) { + serial_icr_write(info, UART_TCR, 0x4); + baud_base = baud_base * 4; + } else + serial_icr_write(info, UART_TCR, 0); + } + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*baud_base / 269); + else if (baud) + quot = baud_base / baud; + } + /* If the quotient is zero refuse the change */ + if (!quot && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*baud_base / 269); + else if (baud) + quot = baud_base / baud; + } + } + /* As a last resort, if the quotient is zero, default to 9600 bps */ + if (!quot) + quot = baud_base / 9600; + info->quot = quot; + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + /* Set up FIFO's */ + if (uart_config[info->state->type].flags & UART_USE_FIFO) { + if ((info->state->baud_base / quot) < 2400) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; + } + if (info->state->type == PORT_16750) + fcr |= UART_FCR7_64BYTE; + + /* CTS flow control flag and modem status interrupts */ + info->IER &= ~UART_IER_MSI; + if (info->flags & ASYNC_HARDPPS_CD) + info->IER |= UART_IER_MSI; + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + info->IER |= UART_IER_MSI; + } else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else { + info->flags |= ASYNC_CHECK_CD; + info->IER |= UART_IER_MSI; + } + serial_out(info, UART_IER, info->IER); + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (I_INPCK(info->tty)) + info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_OE; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->ignore_status_mask |= UART_LSR_DR; + save_flags(flags); cli(); + if (uart_config[info->state->type].flags & UART_STARTECH) { + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, + (cflag & CRTSCTS) ? UART_EFR_CTS : 0); + } + serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */ + if (info->state->type == PORT_16750) + serial_outp(info, UART_FCR, fcr); /* set fcr */ + serial_outp(info, UART_LCR, cval); /* reset DLAB */ + info->LCR = cval; /* Save LCR */ + if (info->state->type != PORT_16750) + serial_outp(info, UART_FCR, fcr); /* set fcr */ + restore_flags(flags); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + if (!tty || !info->xmit_buf) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + restore_flags(flags); + return; + } + + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= SERIAL_XMIT_SIZE-1; + info->xmit_cnt++; + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + save_flags(flags); cli(); + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf || !tmp_buf) + return 0; + + save_flags(flags); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + } + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + return ret; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + save_flags(flags); cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_send_char")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) + info->MCR &= ~UART_MCR_RTS; + + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + if (tty->termios->c_cflag & CRTSCTS) + info->MCR |= UART_MCR_RTS; + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct async_struct * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + struct serial_state *state = info->state; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = state->type; + tmp.line = state->line; + tmp.port = state->port; + tmp.irq = state->irq; + tmp.flags = state->flags; + tmp.xmit_fifo_size = state->xmit_fifo_size; + tmp.baud_base = state->baud_base; + tmp.close_delay = state->close_delay; + tmp.closing_wait = state->closing_wait; + tmp.custom_divisor = state->custom_divisor; + tmp.hub6 = state->hub6; + tmp.io_type = state->io_type; + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_serial_info(struct async_struct * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct serial_state old_state, *state; + unsigned int i,change_irq,change_port; + int retval = 0; + + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; + state = info->state; + old_state = *state; + + change_irq = new_serial.irq != state->irq; + change_port = (new_serial.port != state->port) || + (new_serial.hub6 != state->hub6); + + if (!capable(CAP_SYS_ADMIN)) { + if (change_irq || change_port || + (new_serial.baud_base != state->baud_base) || + (new_serial.type != state->type) || + (new_serial.close_delay != state->close_delay) || + (new_serial.xmit_fifo_size != state->xmit_fifo_size) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (state->flags & ~ASYNC_USR_MASK))) + return -EPERM; + state->flags = ((state->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + state->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + new_serial.irq = irq_cannonicalize(new_serial.irq); + + if ((new_serial.irq >= NR_IRQS) || + (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) || + (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || + (new_serial.type == PORT_STARTECH)) { + return -EINVAL; + } + + if ((new_serial.type != state->type) || + (new_serial.xmit_fifo_size <= 0)) + new_serial.xmit_fifo_size = + uart_config[new_serial.type].dfl_xmit_fifo_size; + + /* Make sure address is not already in use */ + if (new_serial.type) { + for (i = 0 ; i < NR_PORTS; i++) + if ((state != &rs_table[i]) && + (rs_table[i].port == new_serial.port) && + rs_table[i].type) + return -EADDRINUSE; + } + + if ((change_port || change_irq) && (state->count > 1)) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + state->baud_base = new_serial.baud_base; + state->flags = ((state->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | + (info->flags & ASYNC_INTERNAL_FLAGS)); + state->custom_divisor = new_serial.custom_divisor; + state->close_delay = new_serial.close_delay * HZ/100; + state->closing_wait = new_serial.closing_wait * HZ/100; +#if (LINUX_VERSION_CODE > 0x20100) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + info->xmit_fifo_size = state->xmit_fifo_size = + new_serial.xmit_fifo_size; + + if ((state->type != PORT_UNKNOWN) && state->port) + release_region(state->port,8); + state->type = new_serial.type; + if (change_port || change_irq) { + /* + * We need to shutdown the serial port at the old + * port/irq combination. + */ + shutdown(info); + state->irq = new_serial.irq; + info->port = state->port = new_serial.port; + info->hub6 = state->hub6 = new_serial.hub6; + if (info->hub6) + info->io_type = state->io_type = SERIAL_IO_HUB6; + else if (info->io_type == SERIAL_IO_HUB6) + info->io_type = state->io_type = SERIAL_IO_PORT; + } + if ((state->type != PORT_UNKNOWN) && state->port) + request_region(state->port,8,"serial(set)"); + + +check_and_exit: + if (!state->port || !state->type) + return 0; + if (info->flags & ASYNC_INITIALIZED) { + if (((old_state.flags & ASYNC_SPD_MASK) != + (state->flags & ASYNC_SPD_MASK)) || + (old_state.custom_divisor != state->custom_divisor)) { +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; +#endif + change_speed(info, 0); + } + } else + retval = startup(info); + return retval; +} + + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct async_struct * info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + unsigned long flags; + + save_flags(flags); cli(); + status = serial_in(info, UART_LSR); + restore_flags(flags); + result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + + /* + * If we're about to load something into the transmit + * register, we'll pretend the transmitter isn't empty to + * avoid a race condition (depending on when the transmit + * interrupt happens). + */ + if (info->x_char || + ((info->xmit_cnt > 0) && !info->tty->stopped && + !info->tty->hw_stopped)) + result &= TIOCSER_TEMT; + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + + +static int get_modem_info(struct async_struct * info, unsigned int *value) +{ + unsigned char control, status; + unsigned int result; + unsigned long flags; + + control = info->MCR; + save_flags(flags); cli(); + status = serial_in(info, UART_MSR); + restore_flags(flags); + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) + | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) +#ifdef TIOCM_OUT1 + | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) + | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) +#endif + | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) + | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) + | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) + | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +static int set_modem_info(struct async_struct * info, unsigned int cmd, + unsigned int *value) +{ + unsigned int arg; + unsigned long flags; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + info->MCR |= UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR |= UART_MCR_DTR; +#ifdef TIOCM_OUT1 + if (arg & TIOCM_OUT1) + info->MCR |= UART_MCR_OUT1; + if (arg & TIOCM_OUT2) + info->MCR |= UART_MCR_OUT2; +#endif + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + info->MCR &= ~UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR &= ~UART_MCR_DTR; +#ifdef TIOCM_OUT1 + if (arg & TIOCM_OUT1) + info->MCR &= ~UART_MCR_OUT1; + if (arg & TIOCM_OUT2) + info->MCR &= ~UART_MCR_OUT2; +#endif + break; + case TIOCMSET: + info->MCR = ((info->MCR & ~(UART_MCR_RTS | +#ifdef TIOCM_OUT1 + UART_MCR_OUT1 | + UART_MCR_OUT2 | +#endif + UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) +#ifdef TIOCM_OUT1 + | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0) + | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0) +#endif + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + break; + default: + return -EINVAL; + } + save_flags(flags); cli(); + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); + return 0; +} + +static int do_autoconfig(struct async_struct * info) +{ + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (info->state->count > 1) + return -EBUSY; + + shutdown(info); + + autoconfig(info->state); + if ((info->state->flags & ASYNC_AUTO_IRQ) && + (info->state->port != 0) && + (info->state->type != PORT_UNKNOWN)) + info->state->irq = detect_uart_irq(info->state); + + retval = startup(info); + if (retval) + return retval; + return 0; +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ +static void send_break( struct async_struct * info, int duration) +{ + if (!CONFIGURED_SERIAL_PORT(info)) + return; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + duration; + cli(); + info->LCR |= UART_LCR_SBC; + serial_out(info, UART_LCR, info->LCR); + schedule(); + info->LCR &= ~UART_LCR_SBC; + serial_out(info, UART_LCR, info->LCR); + sti(); +} +#else +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_break")) + return; + + if (!CONFIGURED_SERIAL_PORT(info)) + return; + save_flags(flags); cli(); + if (break_state == -1) + info->LCR |= UART_LCR_SBC; + else + info->LCR &= ~UART_LCR_SBC; + serial_out(info, UART_LCR, info->LCR); + restore_flags(flags); +} +#endif + +#ifdef CONFIG_SERIAL_MULTIPORT +static int get_multiport_struct(struct async_struct * info, + struct serial_multiport_struct *retinfo) +{ + struct serial_multiport_struct ret; + struct rs_multiport_struct *multi; + + multi = &rs_multiport[info->state->irq]; + + ret.port_monitor = multi->port_monitor; + + ret.port1 = multi->port1; + ret.mask1 = multi->mask1; + ret.match1 = multi->match1; + + ret.port2 = multi->port2; + ret.mask2 = multi->mask2; + ret.match2 = multi->match2; + + ret.port3 = multi->port3; + ret.mask3 = multi->mask3; + ret.match3 = multi->match3; + + ret.port4 = multi->port4; + ret.mask4 = multi->mask4; + ret.match4 = multi->match4; + + ret.irq = info->state->irq; + + if (copy_to_user(retinfo,&ret,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_multiport_struct(struct async_struct * info, + struct serial_multiport_struct *in_multi) +{ + struct serial_multiport_struct new_multi; + struct rs_multiport_struct *multi; + struct serial_state *state; + int was_multi, now_multi; + int retval; + void (*handler)(int, void *, struct pt_regs *); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + state = info->state; + + if (copy_from_user(&new_multi, in_multi, + sizeof(struct serial_multiport_struct))) + return -EFAULT; + + if (new_multi.irq != state->irq || state->irq == 0 || + !IRQ_ports[state->irq]) + return -EINVAL; + + multi = &rs_multiport[state->irq]; + was_multi = (multi->port1 != 0); + + multi->port_monitor = new_multi.port_monitor; + + if (multi->port1) + release_region(multi->port1,1); + multi->port1 = new_multi.port1; + multi->mask1 = new_multi.mask1; + multi->match1 = new_multi.match1; + if (multi->port1) + request_region(multi->port1,1,"serial(multiport1)"); + + if (multi->port2) + release_region(multi->port2,1); + multi->port2 = new_multi.port2; + multi->mask2 = new_multi.mask2; + multi->match2 = new_multi.match2; + if (multi->port2) + request_region(multi->port2,1,"serial(multiport2)"); + + if (multi->port3) + release_region(multi->port3,1); + multi->port3 = new_multi.port3; + multi->mask3 = new_multi.mask3; + multi->match3 = new_multi.match3; + if (multi->port3) + request_region(multi->port3,1,"serial(multiport3)"); + + if (multi->port4) + release_region(multi->port4,1); + multi->port4 = new_multi.port4; + multi->mask4 = new_multi.mask4; + multi->match4 = new_multi.match4; + if (multi->port4) + request_region(multi->port4,1,"serial(multiport4)"); + + now_multi = (multi->port1 != 0); + + if (IRQ_ports[state->irq]->next_port && + (was_multi != now_multi)) { + free_irq(state->irq, &IRQ_ports[state->irq]); + if (now_multi) + handler = rs_interrupt_multi; + else + handler = rs_interrupt; + + retval = request_irq(state->irq, handler, SA_SHIRQ, + "serial", &IRQ_ports[state->irq]); + if (retval) { + printk("Couldn't reallocate serial interrupt " + "driver!!\n"); + } + } + return 0; +} +#endif + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct icount; + unsigned long flags; +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ + int retval, tmp; +#endif + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + if (!arg) { + send_break(info, HZ/4); /* 1/4 second */ + if (signal_pending(current)) + return -EINTR; + } + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + send_break(info, arg ? arg*(HZ/10) : HZ/4); + if (signal_pending(current)) + return -EINTR; + return 0; + case TIOCGSOFTCAR: + tmp = C_CLOCAL(tty) ? 1 : 0; + if (copy_to_user((void *)arg, &tmp, sizeof(int))) + return -EFAULT; + return 0; + case TIOCSSOFTCAR: + if (copy_from_user(&tmp, (void *)arg, sizeof(int))) + return -EFAULT; + + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (tmp ? CLOCAL : 0)); + return 0; +#endif + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERCONFIG: + return do_autoconfig(info); + + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct async_struct *) arg, + info, sizeof(struct async_struct))) + return -EFAULT; + return 0; + +#ifdef CONFIG_SERIAL_MULTIPORT + case TIOCSERGETMULTI: + return get_multiport_struct(info, + (struct serial_multiport_struct *) arg); + case TIOCSERSETMULTI: + return set_multiport_struct(info, + (struct serial_multiport_struct *) arg); +#endif + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + save_flags(flags); cli(); + /* note the counters on entry */ + cprev = info->state->icount; + restore_flags(flags); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + save_flags(flags); cli(); + cnow = info->state->icount; /* atomic copy */ + restore_flags(flags); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + save_flags(flags); cli(); + cnow = info->state->icount; + restore_flags(flags); + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + if (copy_to_user((void *)arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + if ( (cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(cflag & CBAUD)) { + info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (cflag & CBAUD)) { + info->MCR |= UART_MCR_DTR; + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + info->MCR |= UART_MCR_RTS; + } + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } + +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + DBG_CNT("before DEC-hung"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + DBG_CNT("before DEC-2"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->IER &= ~UART_IER_RLSI; + info->read_status_mask &= ~UART_LSR_DR; + if (info->flags & ASYNC_INITIALIZED) { + serial_out(info, UART_IER, info->IER); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + rs_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; + restore_flags(flags); +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int lsr; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + + if (info->state->type == PORT_UNKNOWN) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...", lsr, jiffies); +#endif + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + set_current_state(TASK_RUNNING); +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#endif +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + state = info->state; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct async_struct *info) +{ + DECLARE_WAITQUEUE(wait, current); + struct serial_state *state = info->state; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, state->count); +#endif + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + state->count--; + } + restore_flags(flags); + info->blocked_open++; + while (1) { + save_flags(flags); cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + serial_out(info, UART_MCR, + serial_inp(info, UART_MCR) | + (UART_MCR_DTR | UART_MCR_RTS)); + restore_flags(flags); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (serial_in(info, UART_MSR) & + UART_MSR_DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + state->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->io_type = sstate->io_type; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + info->iomem_base = sstate->iomem_base; + info->iomem_reg_shift = sstate->iomem_reg_shift; +#endif + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree_s(info, sizeof(struct async_struct)); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + MOD_INC_USE_COUNT; + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) { + MOD_DEC_USE_COUNT; + return retval; + } + tty->driver_data = info; + info->tty = tty; + if (serial_paranoia_check(info, tty->device, "rs_open")) + return -ENODEV; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif +#if (LINUX_VERSION_CODE > 0x20100) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + + if (!tmp_buf) { + page = get_zeroed_page(GFP_KERNEL); + if (!page) { + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + return retval; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + change_speed(info, 0); + } +#ifdef CONFIG_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + change_speed(info, 0); + } +#endif + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ + struct async_struct *info = state->info, scr_info; + char stat_buf[30], control, status; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", + state->line, uart_config[state->type].name, + state->port, state->irq); + + if (!state->port || (state->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + save_flags(flags); cli(); + status = serial_in(info, UART_MSR); + control = info ? info->MCR : serial_in(info, UART_MCR); + restore_flags(flags); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (control & UART_MCR_RTS) + strcat(stat_buf, "|RTS"); + if (status & UART_MSR_CTS) + strcat(stat_buf, "|CTS"); + if (control & UART_MCR_DTR) + strcat(stat_buf, "|DTR"); + if (status & UART_MSR_DSR) + strcat(stat_buf, "|DSR"); + if (status & UART_MSR_DCD) + strcat(stat_buf, "|CD"); + if (status & UART_MSR_RI) + strcat(stat_buf, "|RI"); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; +} + +int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n", + serial_version, LOCAL_VERSTRING, serial_revdate); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s%s (%s) with", serial_name, + serial_version, LOCAL_VERSTRING, serial_revdate); +#ifdef CONFIG_HUB6 + printk(" HUB-6"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_MANY_PORTS + printk(" MANY_PORTS"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_MULTIPORT + printk(" MULTIPORT"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_SHARE_IRQ + printk(" SHARE_IRQ"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_DETECT_IRQ + printk(" DETECT_IRQ"); +#define SERIAL_OPT +#endif +#ifdef ENABLE_SERIAL_PCI + printk(" SERIAL_PCI"); +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + printk(" PCI_IOMEM"); +#endif +#define SERIAL_OPT +#endif +#ifdef SERIAL_OPT + printk(" enabled\n"); +#else + printk(" no serial options enabled\n"); +#endif +#undef SERIAL_OPT +} + +/* + * This routine detect the IRQ of a serial port by clearing OUT2 when + * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at + * each time, as long as no other device permanently request the IRQ. + * If no IRQ is detected, or multiple IRQ appear, this function returns 0. + * The variable "state" and the field "state->port" should not be null. + */ +static unsigned detect_uart_irq (struct serial_state * state) +{ + int irq; + unsigned long irqs; + unsigned char save_mcr, save_ier; + struct async_struct scr_info; /* serial_{in,out} because HUB6 */ + +#ifdef CONFIG_SERIAL_MANY_PORTS + unsigned char save_ICP=0; /* no warning */ + unsigned short ICP=0; + + if (state->flags & ASYNC_FOURPORT) { + ICP = (state->port & 0xFE0) | 0x01F; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); + (void) inb_p(ICP); + } +#endif + scr_info.magic = SERIAL_MAGIC; + scr_info.port = state->port; + scr_info.flags = state->flags; +#ifdef CONFIG_HUB6 + scr_info.hub6 = state->hub6; +#endif + + /* forget possible initially masked and pending IRQ */ + probe_irq_off(probe_irq_on()); + save_mcr = serial_inp(&scr_info, UART_MCR); + save_ier = serial_inp(&scr_info, UART_IER); + serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + + irqs = probe_irq_on(); + serial_outp(&scr_info, UART_MCR, 0); + udelay (10); + if (state->flags & ASYNC_FOURPORT) { + serial_outp(&scr_info, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS); + } else { + serial_outp(&scr_info, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + } + serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */ + (void)serial_inp(&scr_info, UART_LSR); + (void)serial_inp(&scr_info, UART_RX); + (void)serial_inp(&scr_info, UART_IIR); + (void)serial_inp(&scr_info, UART_MSR); + serial_outp(&scr_info, UART_TX, 0xFF); + udelay (20); + irq = probe_irq_off(irqs); + + serial_outp(&scr_info, UART_MCR, save_mcr); + serial_outp(&scr_info, UART_IER, save_ier); +#ifdef CONFIG_SERIAL_MANY_PORTS + if (state->flags & ASYNC_FOURPORT) + outb_p(save_ICP, ICP); +#endif + return (irq > 0)? irq : 0; +} + +/* + * This is a quickie test to see how big the FIFO is. + * It doesn't work at all the time, more's the pity. + */ +static int size_fifo(struct async_struct *info) +{ + unsigned char old_fcr, old_mcr, old_dll, old_dlm; + int count; + + old_fcr = serial_inp(info, UART_FCR); + old_mcr = serial_inp(info, UART_MCR); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(info, UART_MCR, UART_MCR_LOOP); + serial_outp(info, UART_LCR, UART_LCR_DLAB); + old_dll = serial_inp(info, UART_DLL); + old_dlm = serial_inp(info, UART_DLM); + serial_outp(info, UART_DLL, 0x01); + serial_outp(info, UART_DLM, 0x00); + serial_outp(info, UART_LCR, 0x03); + for (count = 0; count < 256; count++) + serial_outp(info, UART_TX, count); + mdelay(20); + for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) && + (count < 256); count++) + serial_inp(info, UART_RX); + serial_outp(info, UART_FCR, old_fcr); + serial_outp(info, UART_MCR, old_mcr); + serial_outp(info, UART_LCR, UART_LCR_DLAB); + serial_outp(info, UART_DLL, old_dll); + serial_outp(info, UART_DLM, old_dlm); + + return count; +} + +/* + * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. + * When this function is called we know it is at least a StarTech + * 16650 V2, but it might be one of several StarTech UARTs, or one of + * its clones. (We treat the broken original StarTech 16650 V1 as a + * 16550, and why not? Startech doesn't seem to even acknowledge its + * existence.) + * + * What evil have men's minds wrought... + */ +static void autoconfig_startech_uarts(struct async_struct *info, + struct serial_state *state, + unsigned long flags) +{ + unsigned char scratch, scratch2, scratch3; + + /* + * First we check to see if it's an Oxford Semiconductor UART. + * + * If we have to do this here because some non-National + * Semiconductor clone chips lock up if you try writing to the + * LSR register (which serial_icr_read does) + */ + if (state->type == PORT_16550A) { + /* Check for Oxford Semiconductor 16C950 */ + scratch = serial_icr_read(info, UART_ID1); + scratch2 = serial_icr_read(info, UART_ID2); + scratch3 = serial_icr_read(info, UART_ID3); + + if (scratch == 0x16 && scratch2 == 0xC9 && + (scratch3 == 0x50 || scratch3 == 0x52 || + scratch3 == 0x54)) { + state->type = PORT_16C950; + state->revision = serial_icr_read(info, UART_REV); + return; + } + } + + /* + * We check for a XR16C850 by setting DLL and DLM to 0, and + * then reading back DLL and DLM. If DLM reads back 0x10, + * then the UART is a XR16C850 and the DLL contains the chip + * revision. If DLM reads back 0x14, then the UART is a + * XR16C854. + * + */ + serial_outp(info, UART_LCR, UART_LCR_DLAB); + serial_outp(info, UART_DLL, 0); + serial_outp(info, UART_DLM, 0); + state->revision = serial_inp(info, UART_DLL); + scratch = serial_inp(info, UART_DLM); + serial_outp(info, UART_LCR, 0); + if (scratch == 0x10 || scratch == 0x14) { + state->type = PORT_16850; + return; + } + + /* + * We distinguish between the '654 and the '650 by counting + * how many bytes are in the FIFO. I'm using this for now, + * since that's the technique that was sent to me in the + * serial driver update, but I'm not convinced this works. + * I've had problems doing this in the past. -TYT + */ + if (size_fifo(info) == 64) + state->type = PORT_16654; + else + state->type = PORT_16650V2; +} + +/* + * This routine is called by rs_init() to initialize a specific serial + * port. It determines what type of UART chip this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ +static void autoconfig(struct serial_state * state) +{ + unsigned char status1, status2, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; + struct async_struct *info, scr_info; + unsigned long flags; + + state->type = PORT_UNKNOWN; + +#ifdef SERIAL_DEBUG_AUTOCONF + printk("Testing ttyS%d (0x%04x, 0x%04x)...\n", state->line, + state->port, (unsigned) state->iomem_base); +#endif + + if (!CONFIGURED_SERIAL_PORT(state)) + return; + + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; +#ifdef CONFIG_HUB6 + info->hub6 = state->hub6; +#endif + info->io_type = state->io_type; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; +#endif + + save_flags(flags); cli(); + + if (!state->iomem_base) { + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. + * + * 0x80 is used as a nonsense port to prevent against + * false positives due to ISA bus float. The + * assumption is that 0x80 is a non-existent port; + * which should be safe since include/asm/io.h also + * makes this assumption. + */ + scratch = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + scratch2 = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, 0x0F); +#ifdef __i386__ + outb(0, 0x080); +#endif + scratch3 = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, scratch); + if (scratch2 || scratch3 != 0x0F) { +#ifdef SERIAL_DEBUG_AUTOCONF + printk("serial: ttyS%d: simple autoconfig failed\n", + state->line); +#endif + restore_flags(flags); + return; /* We failed; there's nothing here */ + } + } + + save_mcr = serial_in(info, UART_MCR); + save_lcr = serial_in(info, UART_LCR); + + /* + * Check to see if a UART is really there. Certain broken + * internal modems based on the Rockwell chipset fail this + * test, because they apparently don't implement the loopback + * test mode. So this test is skipped on the COM 1 through + * COM 4 ports. This *should* be safe, since no board + * manufacturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ + if (!(state->flags & ASYNC_SKIP_TEST)) { + serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_inp(info, UART_MSR) & 0xF0; + serial_outp(info, UART_MCR, save_mcr); + if (status1 != 0x90) { +#ifdef SERIAL_DEBUG_AUTOCONF + printk("serial: ttyS%d: no UART loopback failed\n", + state->line); +#endif + restore_flags(flags); + return; + } + } + serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */ + serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */ + serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(info, UART_IIR) >> 6; + switch (scratch) { + case 0: + state->type = PORT_16450; + break; + case 1: + state->type = PORT_UNKNOWN; + break; + case 2: + state->type = PORT_16550; + break; + case 3: + state->type = PORT_16550A; + break; + } + if (state->type == PORT_16550A) { + /* Check for Startech UART's */ + serial_outp(info, UART_LCR, UART_LCR_DLAB); + if (serial_in(info, UART_EFR) == 0) { + state->type = PORT_16650; + } else { + serial_outp(info, UART_LCR, 0xBF); + if (serial_in(info, UART_EFR) == 0) + autoconfig_startech_uarts(info, state, flags); + } + } + if (state->type == PORT_16550A) { + /* Check for TI 16750 */ + serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB); + serial_outp(info, UART_FCR, + UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + scratch = serial_in(info, UART_IIR) >> 5; + if (scratch == 7) { + /* + * If this is a 16750, and not a cheap UART + * clone, then it should only go into 64 byte + * mode if the UART_FCR7_64BYTE bit was set + * while UART_LCR_DLAB was latched. + */ + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_FCR, + UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + scratch = serial_in(info, UART_IIR) >> 5; + if (scratch == 6) + state->type = PORT_16750; + } + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + } + serial_outp(info, UART_LCR, save_lcr); + if (state->type == PORT_16450) { + scratch = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0xa5); + status1 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0x5a); + status2 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, scratch); + + if ((status1 != 0xa5) || (status2 != 0x5a)) + state->type = PORT_8250; + } + state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size; + + if (state->type == PORT_UNKNOWN) { + restore_flags(flags); + return; + } + + if (info->port) + request_region(info->port,8,"serial(auto)"); + + /* + * Reset the UART. + */ + serial_outp(info, UART_MCR, save_mcr); + serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + serial_outp(info, UART_FCR, 0); + (void)serial_in(info, UART_RX); + serial_outp(info, UART_IER, 0); + + restore_flags(flags); +} + +int register_serial(struct serial_struct *req); +void unregister_serial(int line); + +#if (LINUX_VERSION_CODE > 0x20100) +EXPORT_SYMBOL(register_serial); +EXPORT_SYMBOL(unregister_serial); +#else +static struct symbol_table serial_syms = { +#include + X(register_serial), + X(unregister_serial), +#include +}; +#endif + +#ifdef ENABLE_SERIAL_PCI +/* + * Some PCI serial cards using the PLX 9050 PCI interface chip require + * that the card interrupt be explicitly enabled or disabled. This + * seems to be mainly needed on card using the PLX which also use I/O + * mapped memory. + * + * Note that __init is a no-op if MODULE is defined; we depend on this. + */ +static int __init pci_plx9050_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + u8 data, *p, scratch; + + pci_read_config_byte(dev, PCI_COMMAND, &data); + + if (enable) + pci_write_config_byte(dev, PCI_COMMAND, + data | PCI_COMMAND_MEMORY); + + /* enable/disable interrupts */ + p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); + if (board->vendor == PCI_VENDOR_ID_PANACOM) { + scratch = readl(p + 0x4c); + if (enable) + scratch |= 0x40; + else + scratch &= ~0x40; + writel(scratch, p + 0x4c); + } else + writel(enable ? 0x41 : 0x00, p + 0x4c); + iounmap(p); + + if (!enable) + pci_write_config_byte(dev, PCI_COMMAND, + data & ~PCI_COMMAND_MEMORY); + return 0; +} + +/* + * SIIG serial cards have an PCI interface chip which also controls + * the UART clocking frequency. Each UART can be clocked independently + * (except cards equiped with 4 UARTs) and initial clocking settings + * are stored in the EEPROM chip. It can cause problems because this + * version of serial driver doesn't support differently clocked UART's + * on single PCI card. To prevent this, initialization functions set + * high frequency clocking for all UART's on given card. It is safe (I + * hope) because it doesn't touch EEPROM settings to prevent conflicts + * with other OSes (like M$ DOS). + * + * SIIG support added by Andrey Panin , 10/1999 + * + * There is two family of SIIG serial cards with different PCI + * interface chip and different configuration methods: + * - 10x cards have control registers in IO and/or memory space; + * - 20x cards have control registers in standard PCI configuration space. + */ + +#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) + +static int __init pci_siig10x_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + u16 data, *p; + + if (!enable) return 0; + + p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); + + switch (dev->device & 0xfff8) { + case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ + data = 0xffdf; + break; + case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */ + data = 0xf7ff; + break; + default: /* 1S1P, 4S */ + data = 0xfffb; + break; + } + + writew(readw(p + 0x28) & data, p + 0x28); + iounmap(p); + return 0; +} + +#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) + +static int __init pci_siig20x_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + u8 data; + + if (!enable) return 0; + + /* Change clock frequency for the first UART. */ + pci_read_config_byte(dev, 0x6f, &data); + pci_write_config_byte(dev, 0x6f, data & 0xef); + + /* If this card has 2 UART, we have to do the same with second UART. */ + if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) || + ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) { + pci_read_config_byte(dev, 0x73, &data); + pci_write_config_byte(dev, 0x73, data & 0xef); + } + return 0; +} + +/* + * This is the configuration table for all of the PCI serial boards + * which we support. + */ +static struct pci_board pci_boards[] = { + /* + * Vendor ID, Device ID, + * Subvendor ID, Subdevice ID, + * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, + * Offset to get to next UART's registers + * Register shift to use for memory-mapped I/O + */ + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, + SPCI_FL_BASE1, 8, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, + SPCI_FL_BASE1, 4, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, + SPCI_FL_BASE1, 2, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, + SPCI_FL_BASE1, 8, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, + SPCI_FL_BASE1, 4, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, + SPCI_FL_BASE1, 2, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, + SPCI_FL_BASE1, 2, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, + SPCI_FL_BASE1, 2, 921600 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 8, 115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_KEYSPAN, + PCI_SUBDEVICE_ID_KEYSPAN_SX2, + SPCI_FL_BASE2 | SPCI_FL_IOMEM, 2, 921600, + 0x400, 7, pci_plx9050_fn }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0x400, 7, pci_plx9050_fn }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0x400, 7, pci_plx9050_fn }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST4, + SPCI_FL_BASE2, 4, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST8, + SPCI_FL_BASE2, 8, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16, + SPCI_FL_BASE2, 16, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, + SPCI_FL_BASE2, 16, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS4, + SPCI_FL_BASE2, 4, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS8, + SPCI_FL_BASE2, 8, 460800 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 4, 115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 2, 115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 8, 115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 8, 115200 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, + SPCI_FL_BASE0 , 4, 115200 }, + { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, + SPCI_FL_BASE0 , 4, 921600 }, + { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 , 2, 921600 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_SERIAL, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 460800, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 460800, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 460800, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig20x_fn }, + /* Computone devices submitted by Doug McNash dmcnash@computone.com */ + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, + SPCI_FL_IOMEM | SPCI_FL_BASE0, 4, 921600, + 0x40, 2, NULL, 0x200 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, + SPCI_FL_IOMEM | SPCI_FL_BASE0, 8, 921600, + 0x40, 2, NULL, 0x200 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, + SPCI_FL_IOMEM | SPCI_FL_BASE0, 6, 921600, + 0x40, 2, NULL, 0x200 }, + /* + * Untested PCI modems, sent in from various folks... + */ + /* at+t zoom 56K faxmodem, from dougd@shieldsbag.com */ + { PCI_VENDOR_ID_ATT, 0x442, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 1, 115200 }, + /* at&t unknown modem, from jimd@esoft.com */ + { PCI_VENDOR_ID_ATT, 0x480, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 1, 115200 }, + /* Elsa Model 56K PCI Modem, from Andreas Rath */ + { PCI_VENDOR_ID_ROCKWELL, 0x1004, + 0x1048, 0x1500, + SPCI_FL_BASE1, 1, 115200 }, + /* 3Com US Robotics 56k* Voice Internal PCI, model# 2884 */ + /* from evidal@iti.upv.es */ + /* XXX complete guess this may not work!!! */ + { PCI_VENDOR_ID_USR, 0x1006, + 0x12b9, 0x0060, + SPCI_FL_BASE1 | SPCI_FL_IOMEM, 1, 115200 }, + { 0, } +}; + +/* + * Query PCI space for known serial boards + * If found, add them to the PCI device space in rs_table[] + * + * Accept a maximum of eight boards + * + */ +static void probe_serial_pci(void) +{ + u16 subvendor, subdevice; + int k, line; + struct pci_dev *dev = NULL; + struct pci_board *board; + struct serial_struct fake_state; + int uart_offset, base_baud, base_idx; + unsigned long port; + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG "Entered probe_serial_pci()\n"); +#endif + + if (!pcibios_present()) { +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n"); +#endif + return; + } + + for(dev=pci_devices; dev; dev=dev->next) { + pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, + &subvendor); + pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice); + + for (board = pci_boards; board->vendor; board++) { + if (board->vendor != (unsigned short) PCI_ANY_ID && + dev->vendor != board->vendor) + continue; + if (board->device != (unsigned short) PCI_ANY_ID && + dev->device != board->device) + continue; + if (board->subvendor != (unsigned short) PCI_ANY_ID && + subvendor != board->subvendor) + continue; + if (board->subdevice != (unsigned short) PCI_ANY_ID && + subdevice != board->subdevice) + continue; + break; + } + + if (board->vendor == 0) { +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG + "Found unknown serial board: %x:%x, %x:%x, %x\n", + dev->vendor, dev->device, subvendor, subdevice, + dev->class); + printk(KERN_DEBUG + " Addresses: %lx, %lx, %lx, %lx\n", + PCI_BASE_ADDRESS(dev, 0), PCI_BASE_ADDRESS(dev, 1), + PCI_BASE_ADDRESS(dev, 2), PCI_BASE_ADDRESS(dev, 3)); +#endif + continue; + } + + /* + * Run the initialization function, if any + */ + if (board->init_fn) + if ((board->init_fn)(dev, board, 1) != 0) + continue; + + /* + * Register the serial board in the array so we can + * shutdown the board later, if necessary. + */ + if (serial_pci_board_idx >= NR_PCI_BOARDS) + continue; + serial_pci_board[serial_pci_board_idx].board = board; + serial_pci_board[serial_pci_board_idx].dev = dev; + serial_pci_board_idx++; + + base_idx = board->flags & SPCI_FL_BASE_MASK; + port = PCI_BASE_ADDRESS(dev, base_idx) + + board->first_uart_offset; + if (board->flags & SPCI_FL_IOMEM) + port &= PCI_BASE_ADDRESS_MEM_MASK; + else + port &= PCI_BASE_ADDRESS_IO_MASK; + + /* + * Set some defaults for the loop below, which + * actually registers each serial port belonging to + * the card. + */ + uart_offset = board->uart_offset; + if (!uart_offset) + uart_offset = 8; + base_baud = board->base_baud; + if (!base_baud) + base_baud = BASE_BAUD; +#ifndef CONFIG_SERIAL_PCI_MEMMAPPED + if (board->flags & SPCI_FL_IOMEM) { +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG + "Can't support memory mapped PCI serial device\n"); +#endif + continue; + } +#endif + memset(&fake_state, 0, sizeof(fake_state)); + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG + "Found Serial PCI device: %x:%x, %x:%x, %x\n", + dev->vendor, dev->device, subvendor, subdevice, + dev->class); + printk(KERN_DEBUG + " IRQ: %d, base: %lx (%s), num_ports: %d\n", + dev->irq, port, board->flags & SPCI_FL_IOMEM ? + "iomem" : "port", board->num_ports); +#endif + + for (k=0; k < board->num_ports; k++) { + if (board->flags & SPCI_FL_BASE_TABLE) { + port = PCI_BASE_ADDRESS(dev, base_idx++); + if (board->flags & SPCI_FL_IOMEM) + port &= PCI_BASE_ADDRESS_MEM_MASK; + else + port &= PCI_BASE_ADDRESS_IO_MASK; + } + fake_state.irq = dev->irq; + fake_state.port = port; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + if (board->flags & SPCI_FL_IOMEM) { + fake_state.io_type = SERIAL_IO_MEM; + fake_state.iomem_base = + ioremap(port, board->uart_offset); + fake_state.iomem_reg_shift = board->reg_shift; + fake_state.port = 0; + } +#endif + port += uart_offset; + fake_state.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; + line = register_serial(&fake_state); + if (line < 0) + break; + rs_table[line].baud_base = base_baud; + } + } + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n"); +#endif + return; +} + +#endif /* ENABLE_SERIAL_PCI */ + +/* + * The serial driver boot-time initialization code! + */ +int __init rs_init(void) +{ + int i; + struct serial_state * state; + extern void atomwide_serial_init (void); + extern void dualsp_serial_init (void); + +#ifdef CONFIG_ATOMWIDE_SERIAL + atomwide_serial_init (); +#endif +#ifdef CONFIG_DUALSP_SERIAL + dualsp_serial_init (); +#endif + + if (timer_table[RS_TIMER].fn) { + printk("RS_TIMER already set, another serial driver " + "already loaded?\n"); +#ifdef MODULE + printk("Can't load serial driver module over built-in " + "serial driver\n"); +#endif + return -EBUSY; + } + + init_bh(SERIAL_BH, do_serial_bh); + timer_table[RS_TIMER].fn = rs_timer; + timer_table[RS_TIMER].expires = 0; + + for (i = 0; i < NR_IRQS; i++) { + IRQ_ports[i] = 0; + IRQ_timeout[i] = 0; +#ifdef CONFIG_SERIAL_MULTIPORT + memset(&rs_multiport[i], 0, + sizeof(struct rs_multiport_struct)); +#endif + } +#ifdef CONFIG_SERIAL_CONSOLE + /* + * The interrupt of the serial console port + * can't be shared. + */ + if (sercons.flags & CON_CONSDEV) { + for(i = 0; i < NR_PORTS; i++) + if (i != sercons.index && + rs_table[i].irq == rs_table[sercons.index].irq) + rs_table[i].irq = 0; + } +#endif + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; +#if (LINUX_VERSION_CODE > 0x20100) + serial_driver.driver_name = "serial"; +#endif + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + serial_driver.break_ctl = rs_break; +#endif +#if (LINUX_VERSION_CODE >= 131343) + serial_driver.send_xchar = rs_send_xchar; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; +#endif + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; +#if (LINUX_VERSION_CODE >= 131343) + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; +#endif + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = irq_cannonicalize(state->irq); + if (state->hub6) + state->io_type = SERIAL_IO_HUB6; + if (state->port && check_region(state->port,8)) + continue; + if (state->flags & ASYNC_BOOT_AUTOCONF) + autoconfig(state); + } + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + if (state->type == PORT_UNKNOWN) + continue; + if ( (state->flags & ASYNC_BOOT_AUTOCONF) + && (state->flags & ASYNC_AUTO_IRQ) + && (state->port != 0)) + state->irq = detect_uart_irq(state); + printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n", + state->line + SERIAL_DEV_OFFSET, + (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", + state->port, state->irq, + uart_config[state->type].name); + } +#ifdef ENABLE_SERIAL_PCI + probe_serial_pci(); +#endif + return 0; +} + +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + */ +int register_serial(struct serial_struct *req) +{ + int i; + unsigned long flags; + struct serial_state *state; + + save_flags(flags); + cli(); + for (i = 0; i < NR_PORTS; i++) { + if ((rs_table[i].port == req->port) && + (rs_table[i].iomem_base == req->iomem_base)) + break; + } + if (i == NR_PORTS) { + for (i = 0; i < NR_PORTS; i++) + if ((rs_table[i].type == PORT_UNKNOWN) && + (rs_table[i].count == 0)) + break; + } + if (i == NR_PORTS) { + restore_flags(flags); + return -1; + } + state = &rs_table[i]; + if (rs_table[i].count) { + restore_flags(flags); + printk("Couldn't configure serial #%d (port=%d,irq=%d): " + "device already open\n", i, req->port, req->irq); + return -1; + } + state->irq = req->irq; + state->port = req->port; + state->flags = req->flags; + state->io_type = req->io_type; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + state->iomem_base = req->iomem_base; + state->iomem_reg_shift = req->iomem_reg_shift; +#endif + if (req->baud_base) + state->baud_base = req->baud_base; + + autoconfig(state); + if (state->type == PORT_UNKNOWN) { + restore_flags(flags); + printk("register_serial(): autoconfig failed\n"); + return -1; + } + restore_flags(flags); + + if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state)) + state->irq = detect_uart_irq(state); + + printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n", + state->line + SERIAL_DEV_OFFSET, + state->iomem_base ? "iomem" : "port", + state->iomem_base ? (unsigned long)state->iomem_base : + (unsigned long)state->port, + state->irq, uart_config[state->type].name); + return state->line + SERIAL_DEV_OFFSET; +} + +void unregister_serial(int line) +{ + unsigned long flags; + struct serial_state *state = &rs_table[line]; + + save_flags(flags); + cli(); + if (state->info && state->info->tty) + tty_hangup(state->info->tty); + state->type = PORT_UNKNOWN; + printk(KERN_INFO "tty%02d unloaded\n", state->line); + restore_flags(flags); +} + +#ifdef MODULE +int init_module(void) +{ + return rs_init(); +} + +void cleanup_module(void) +{ + unsigned long flags; + int e1, e2; + int i; + struct async_struct *info; + + /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ + save_flags(flags); + cli(); + timer_active &= ~(1 << RS_TIMER); + timer_table[RS_TIMER].fn = NULL; + timer_table[RS_TIMER].expires = 0; + remove_bh(SERIAL_BH); + if ((e1 = tty_unregister_driver(&serial_driver))) + printk("SERIAL: failed to unregister serial driver (%d)\n", + e1); + if ((e2 = tty_unregister_driver(&callout_driver))) + printk("SERIAL: failed to unregister callout driver (%d)\n", + e2); + restore_flags(flags); + + for (i = 0; i < NR_PORTS; i++) { + if ((info = rs_table[i].info)) { + rs_table[i].info = NULL; + kfree_s(info, sizeof(struct async_struct)); + } + if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) + release_region(rs_table[i].port, 8); +#if defined(ENABLE_SERIAL_PCI) && defined (CONFIG_SERIAL_PCI_MEMMAPPED) + if (rs_table[i].iomem_base) + iounmap(rs_table[i].iomem_base); +#endif + } +#ifdef ENABLE_SERIAL_PCI + for (i=0; i < serial_pci_board_idx; i++) { + struct pci_board_inst *brd = &serial_pci_board[i]; + + if (brd->board->init_fn) + (brd->board->init_fn)(brd->dev, brd->board, 0); + } +#endif + if (tmp_buf) { + free_page((unsigned long) tmp_buf); + tmp_buf = NULL; + } +} +#endif /* MODULE */ + + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_SERIAL_CONSOLE + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct async_struct async_sercons; + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct async_struct *info) +{ + unsigned int tmout = 1000000; + + while (--tmout && + ((serial_in(info, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)); +} + + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + static struct async_struct *info = &async_sercons; + int ier; + unsigned i; + + /* + * First save the IER then disable the interrupts + */ + ier = serial_in(info, UART_IER); + serial_out(info, UART_IER, 0x00); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + wait_for_xmitr(info); + + /* + * Send the character out. + * If a LF, also do CR... + */ + serial_out(info, UART_TX, *s); + if (*s == 10) { + wait_for_xmitr(info); + serial_out(info, UART_TX, 13); + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + wait_for_xmitr(info); + serial_out(info, UART_IER, ier); +} + +/* + * Receive character from the serial port + */ +static int serial_console_wait_key(struct console *co) +{ + static struct async_struct *info; + int ier, c; + + info = &async_sercons; + + /* + * First save the IER then disable the interrupts so + * that the real driver for the port does not get the + * character. + */ + ier = serial_in(info, UART_IER); + serial_out(info, UART_IER, 0x00); + + while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0); + c = serial_in(info, UART_RX); + + /* + * Restore the interrupts + */ + serial_out(info, UART_IER, ier); + + return c; +} + +static kdev_t serial_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init serial_console_setup(struct console *co, char *options) +{ + static struct async_struct *info; + struct serial_state *state; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; +#if defined(CONFIG_KDB) + extern int kdb_port; +#endif + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* + * Divisor, bytesize and parity + */ + state = rs_table + co->index; + info = &async_sercons; + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; +#ifdef CONFIG_HUB6 + info->hub6 = state->hub6; +#endif + info->io_type = state->io_type; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; +#endif + quot = state->baud_base / baud; + cval = cflag & (CSIZE | CSTOPB); +#if defined(__powerpc__) || defined(__alpha__) + cval >>= 8; +#else /* !__powerpc__ && !__alpha__ */ + cval >>= 4; +#endif /* !__powerpc__ && !__alpha__ */ + if (cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; + + /* + * Disable UART interrupts, set DTR and RTS high + * and set speed. + */ + serial_out(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + serial_out(info, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_out(info, UART_DLM, quot >> 8); /* MS of divisor */ + serial_out(info, UART_LCR, cval); /* reset DLAB */ + serial_out(info, UART_IER, 0); + serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + + /* + * If we read 0xff from the LSR, there is no UART here. + */ + if (serial_in(info, UART_LSR) == 0xff) + return -1; + +#if defined(CONFIG_KDB) + /* + * Remember I/O port for kdb + */ + if (kdb_port == 0 ) + kdb_port = ser->port; +#endif /* CONFIG_KDB */ + + return 0; +} + +static struct console sercons = { + "ttyS", + serial_console_write, + NULL, + serial_console_device, + serial_console_wait_key, + NULL, + serial_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ +void __init serial_console_init(void) +{ + register_console(&sercons); +} +#endif + +/* + Local variables: + compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" + End: +*/ diff -urN 2.3.29pre1/drivers/char/serial.c.rej 2.3.29pre1-ikd/drivers/char/serial.c.rej --- 2.3.29pre1/drivers/char/serial.c.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/drivers/char/serial.c.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,128 @@ +*************** +*** 577,584 **** + mark_bh(SERIAL_BH); + } + + static _INLINE_ void receive_chars(struct async_struct *info, + int *status) + { + struct tty_struct *tty = info->tty; + unsigned char ch; +--- 577,603 ---- + mark_bh(SERIAL_BH); + } + ++ #if defined(CONFIG_KDB) ++ #include ++ /* ++ * kdb_serial_line records the serial line number of the ++ * first serial console. kdb_info will be set upon receipt ++ * of the first ^A (which cannot happen until the port is ++ * opened and the interrupt handler attached). To enter ++ * kdb before this on a serial console-only system, you must ++ * use the 'kdb' flag to lilo and set the appropriate breakpoints. ++ */ ++ ++ extern int kdb_port; ++ static int kdb_serial_line = -1; ++ #endif /* CONFIG_KDB */ ++ + static _INLINE_ void receive_chars(struct async_struct *info, ++ #if defined(CONFIG_KDB) ++ int *status, struct pt_regs * regs) ++ #else + int *status) ++ #endif + { + struct tty_struct *tty = info->tty; + unsigned char ch; +*************** +*** 749,755 **** + printk("status = %x...", status); + #endif + if (status & UART_LSR_DR) + receive_chars(info, &status); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); +--- 775,785 ---- + printk("status = %x...", status); + #endif + if (status & UART_LSR_DR) ++ #if defined(CONFIG_KDB) ++ receive_chars(info, &status, regs); ++ #else + receive_chars(info, &status); ++ #endif + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); +*************** +*** 813,819 **** + printk("status = %x...", status); + #endif + if (status & UART_LSR_DR) + receive_chars(info, &status); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); +--- 843,853 ---- + printk("status = %x...", status); + #endif + if (status & UART_LSR_DR) ++ #if defined(CONFIG_KDB) ++ receive_chars(info, &status, regs); ++ #else + receive_chars(info, &status); ++ #endif + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); +*************** +*** 876,882 **** + printk("status = %x...", status); + #endif + if (status & UART_LSR_DR) + receive_chars(info, &status); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); +--- 910,920 ---- + printk("status = %x...", status); + #endif + if (status & UART_LSR_DR) ++ #if defined(CONFIG_KDB) ++ receive_chars(info, &status, regs); ++ #else + receive_chars(info, &status); ++ #endif + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); +*************** +*** 4270,4275 **** + */ + if (inb(ser->port + UART_LSR) == 0xff) + return -1; + return 0; + } + +--- 4308,4325 ---- + */ + if (inb(ser->port + UART_LSR) == 0xff) + return -1; ++ ++ #if defined(CONFIG_KDB) ++ /* ++ * Remember the line number of the first serial ++ * console. We'll make this the kdb serial console too. ++ */ ++ if (kdb_serial_line == -1) { ++ kdb_serial_line = co->index; ++ kdb_port = ser->port; ++ } ++ #endif /* CONFIG_KDB */ ++ + return 0; + } + diff -urN 2.3.29pre1/drivers/char/serial.c.~1~ 2.3.29pre1-ikd/drivers/char/serial.c.~1~ --- 2.3.29pre1/drivers/char/serial.c.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/drivers/char/serial.c.~1~ Mon Nov 22 16:56:24 1999 @@ -0,0 +1,4703 @@ +/* + * linux/drivers/char/serial.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, + * 1998, 1999 Theodore Ts'o + * + * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now + * much more extensible to support other serial cards based on the + * 16450/16550A UART's. Added support for the AST FourPort and the + * Accent Async board. + * + * set_serial_info fixed to set the flags, custom divisor, and uart + * type fields. Fix suggested by Michael K. Johnson 12/12/92. + * + * 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis + * + * 03/96: Modularised by Angelo Haritsis + * + * rs_set_termios fixed to look also for changes of the input + * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK. + * Bernd Anhäupl 05/17/96. + * + * 1/97: Extended dumb serial ports are a config option now. + * Saves 4k. Michael A. Griffith + * + * 8/97: Fix bug in rs_set_termios with RTS + * Stanislav V. Voronyi + * + * 3/98: Change the IRQ detection, use of probe_irq_o*(), + * supress TIOCSERGWILD and TIOCSERSWILD + * Etienne Lorrain + * + * 4/98: Added changes to support the ARM architecture proposed by + * Russell King + * + * 5/99: Updated to include support for the XR16C850 and ST16C654 + * uarts. Stuart MacDonald + * + * 8/99: Generalized PCI support added. Theodore Ts'o + * + * This module exports the following rs232 io functions: + * + * int rs_init(void); + */ + +static char *serial_version = "4.91"; +static char *serial_revdate = "1999-11-17"; + +/* + * Serial driver configuration section. Here are the various options: + * + * CONFIG_HUB6 + * Enables support for the venerable Bell Technologies + * HUB6 card. + * + * CONFIG_SERIAL_MANY_PORTS + * Enables support for ports beyond the standard, stupid + * COM 1/2/3/4. + * + * CONFIG_SERIAL_MULTIPORT + * Enables support for special multiport board support. + * + * CONFIG_SERIAL_SHARE_IRQ + * Enables support for multiple serial ports on one IRQ + * + * CONFIG_SERIAL_DETECT_IRQ + * Enable the autodetection of IRQ on standart ports + * + * SERIAL_PARANOIA_CHECK + * Check the magic number for the async_structure where + * ever possible. + */ + +#include +#include + +#undef SERIAL_PARANOIA_CHECK +#define CONFIG_SERIAL_NOPAUSE_IO +#define SERIAL_DO_RESTART +#define CONFIG_SERIAL_PCI_MEMMAPPED + +#if 0 +/* These defines are normally controlled by the autoconf.h */ +#define CONFIG_SERIAL_MANY_PORTS +#define CONFIG_SERIAL_SHARE_IRQ +#define CONFIG_SERIAL_DETECT_IRQ +#define CONFIG_SERIAL_MULTIPORT +#define CONFIG_HUB6 +#endif + +#if (defined(CONFIG_PCI) && (LINUX_VERSION_CODE >= 131072)) +#define ENABLE_SERIAL_PCI +#ifndef CONFIG_SERIAL_SHARE_IRQ +#define CONFIG_SERIAL_SHARE_IRQ +#endif +#ifndef CONFIG_SERIAL_MANY_PORTS +#define CONFIG_SERIAL_MANY_PORTS +#endif +#endif + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#undef SERIAL_DEBUG_PCI +#undef SERIAL_DEBUG_AUTOCONF + +/* Sanity checks */ + +#ifdef CONFIG_SERIAL_MULTIPORT +#ifndef CONFIG_SERIAL_SHARE_IRQ +#define CONFIG_SERIAL_SHARE_IRQ +#endif +#endif + +#ifdef CONFIG_HUB6 +#ifndef CONFIG_SERIAL_MANY_PORTS +#define CONFIG_SERIAL_MANY_PORTS +#endif +#ifndef CONFIG_SERIAL_SHARE_IRQ +#define CONFIG_SERIAL_SHARE_IRQ +#endif +#endif + +#define RS_STROBE_TIME (10*HZ) +#define RS_ISR_PASS_LIMIT 256 + +#if (defined(__i386__) && (CPU==386 || CPU==486)) +#define SERIAL_INLINE +#endif + +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ + kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) +#else +#define DBG_CNT(s) +#endif + +/* + * End of serial driver configuration section. + */ + +#if (LINUX_VERSION_CODE > 66304) +#define NEW_MODULES +#ifdef LOCAL_HEADERS /* We're building standalone */ +#define MODULE +#endif +#endif + +#ifdef NEW_MODULES +#ifdef MODVERSIONS +#include +#endif +#include +#else /* !NEW_MODULES */ +#ifdef MODVERSIONS +#define MODULE +#endif +#include +#endif /* NEW_MODULES */ + +#include +#ifdef LOCAL_HEADERS +#include "serial_local.h" +#else +#include +#include +#include +#include +#define LOCAL_VERSTRING "" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= 131343) +#include +#endif +#if (LINUX_VERSION_CODE >= 131336) +#include +#endif +#include +#ifdef CONFIG_SERIAL_CONSOLE +#include +#endif +#ifdef ENABLE_SERIAL_PCI +#include +#endif + +/* + * All of the compatibilty code so we can compile serial.c against + * older kernels is hidden in serial_compat.h + */ +#if (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */ +#include "serial_compat.h" +#endif + +#include +#include +#include +#include + +#ifdef CONFIG_MAC_SERIAL +#define SERIAL_DEV_OFFSET 2 +#else +#define SERIAL_DEV_OFFSET 0 +#endif + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#else +#define _INLINE_ +#endif + +static char *serial_name = "Serial driver"; + +static DECLARE_TASK_QUEUE(tq_serial); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* serial subtype definitions */ +#ifndef SERIAL_TYPE_NORMAL +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#endif + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* + * IRQ_timeout - How long the timeout should be for each IRQ + * should be after the IRQ has been active. + */ + +static struct async_struct *IRQ_ports[NR_IRQS]; +#ifdef CONFIG_SERIAL_MULTIPORT +static struct rs_multiport_struct rs_multiport[NR_IRQS]; +#endif +static int IRQ_timeout[NR_IRQS]; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console sercons; +static unsigned long break_pressed; /* break, really ... */ +#endif + +static unsigned detect_uart_irq (struct serial_state * state); +static void autoconfig(struct serial_state * info); +static void change_speed(struct async_struct *info, struct termios *old); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); + +/* + * Here we define the default xmit fifo size used for each type of + * UART + */ +static struct serial_uart_config uart_config[] = { + { "unknown", 1, 0 }, + { "8250", 1, 0 }, + { "16450", 1, 0 }, + { "16550", 1, 0 }, + { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "cirrus", 1, 0 }, /* usurped by cyclades.c */ + { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH }, + { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, + { "Startech", 1, 0}, /* usurped by cyclades.c */ + { "16C950", 128, UART_CLEAR_FIFO | UART_USE_FIFO}, + { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { 0, 0} +}; + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) + +#ifdef ENABLE_SERIAL_PCI +#define NR_PCI_BOARDS 8 +static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; +static int serial_pci_board_idx = 0; +#ifdef PCI_NUM_RESOURCES +#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start) +#else +#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r]) +#endif +#endif /* ENABLE_SERIAL_PCI */ + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +#ifdef DECLARE_MUTEX +static DECLARE_MUTEX(tmp_buf_sem); +#else +static struct semaphore tmp_buf_sem = MUTEX; +#endif + + +static inline int serial_paranoia_check(struct async_struct *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset) +{ + switch (info->io_type) { +#ifdef CONFIG_HUB6 + case SERIAL_IO_HUB6: + outb(info->hub6 - 1 + offset, info->port); + return inb(info->port+1); +#endif +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + case SERIAL_IO_MEM: + return readb(info->iomem_base + + (offset<iomem_reg_shift)); +#endif +#ifdef CONFIG_SERIAL_GSC + case SERIAL_IO_GSC: + return gsc_readb(info->iomem_base + offset); +#endif + default: + return inb(info->port + offset); + } +} + +static _INLINE_ void serial_out(struct async_struct *info, int offset, + int value) +{ + switch (info->io_type) { +#ifdef CONFIG_HUB6 + case SERIAL_IO_HUB6: + outb(info->hub6 - 1 + offset, info->port); + outb(value, info->port+1); + break; +#endif +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + case SERIAL_IO_MEM: + writeb(value, info->iomem_base + + (offset<iomem_reg_shift)); + break; +#endif +#ifdef CONFIG_SERIAL_GSC + case SERIAL_IO_GSC: + gsc_writeb(value, info->iomem_base + offset); + break; +#endif + default: + outb(value, info->port+offset); + } +} + +/* + * We used to support using pause I/O for certain machines. We + * haven't supported this for a while, but just in case it's badly + * needed for certain old 386 machines, I've left these #define's + * in.... + */ +#define serial_inp(info, offset) serial_in(info, offset) +#define serial_outp(info, offset, value) serial_out(info, offset, value) + + +/* + * For the 16C950 + */ +void serial_icr_write(struct async_struct *info, int offset, int value) +{ + serial_out(info, UART_SCR, offset); + serial_out(info, UART_ICR, value); +} + +unsigned int serial_icr_read(struct async_struct *info, int offset) +{ + int value; + + serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD); + serial_out(info, UART_SCR, offset); + value = serial_in(info, UART_ICR); + serial_icr_write(info, UART_ACR, info->ACR); + return value; +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if (info->IER & UART_IER_THRI) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + if (info->state->type == PORT_16C950) { + info->ACR |= UART_ACR_TXDIS; + serial_icr_write(info, UART_ACR, info->ACR); + } + restore_flags(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + if (info->state->type == PORT_16C950) { + info->ACR &= ~UART_ACR_TXDIS; + serial_icr_write(info, UART_ACR, info->ACR); + } + restore_flags(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void rs_sched_event(struct async_struct *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +static _INLINE_ void receive_chars(struct async_struct *info, + int *status, struct pt_regs * regs) +{ + struct tty_struct *tty = info->tty; + unsigned char ch; + int ignored = 0; + struct async_icount *icount; + + icount = &info->state->icount; + do { + ch = serial_inp(info, UART_RX); +#if defined(CONFIG_KDB) + if ((info->line == kdb_serial_line) + && (ch == 1)) /* CNTRL-A */ { + kdb(KDB_REASON_KEYBOARD, 0, regs); + break; + } +#endif + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, *status); +#endif + *tty->flip.flag_buf_ptr = 0; + if (*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE)) { + /* + * For statistics only + */ + if (*status & UART_LSR_BI) { + *status &= ~(UART_LSR_FE | UART_LSR_PE); + icount->brk++; + } else if (*status & UART_LSR_PE) + icount->parity++; + else if (*status & UART_LSR_FE) + icount->frame++; + if (*status & UART_LSR_OE) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (*status & info->ignore_status_mask) { + if (++ignored > 100) + break; + goto ignore_char; + } + *status &= info->read_status_mask; + + if (*status & (UART_LSR_BI)) { +#ifdef SERIAL_DEBUG_INTR + printk("handling break...."); +#endif +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) + if (info->line == sercons.index) { + if (!break_pressed) { + break_pressed = jiffies; + goto ignore_char; + } + break_pressed = 0; + } +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (*status & UART_LSR_PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (*status & UART_LSR_FE) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (*status & UART_LSR_OE) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + } + } +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) + if (break_pressed && info->line == sercons.index) { + if (ch != 0 && + time_before(jiffies, break_pressed + HZ*5)) { + handle_sysrq(ch, regs, NULL, NULL); + break_pressed = 0; + goto ignore_char; + } + break_pressed = 0; + } +#endif + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + *status = serial_inp(info, UART_LSR); + } while (*status & UART_LSR_DR); +#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ + tty_flip_buffer_push(tty); +#else + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); +#endif +} + +static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) +{ + int count; + + if (info->x_char) { + serial_outp(info, UART_TX, info->x_char); + info->state->icount.tx++; + info->x_char = 0; + if (intr_done) + *intr_done = 0; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || + info->tty->hw_stopped) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + return; + } + + count = info->xmit_fifo_size; + do { + serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->state->icount.tx++; + if (--info->xmit_cnt <= 0) + break; + } while (--count > 0); + + if (info->xmit_cnt < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + if (intr_done) + *intr_done = 0; + + if (info->xmit_cnt <= 0) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } +} + +static _INLINE_ void check_modem_status(struct async_struct *info) +{ + int status; + struct async_icount *icount; + + status = serial_in(info, UART_MSR); + + if (status & UART_MSR_ANY_DELTA) { + icount = &info->state->icount; + /* update input line counters */ + if (status & UART_MSR_TERI) + icount->rng++; + if (status & UART_MSR_DDSR) + icount->dsr++; + if (status & UART_MSR_DDCD) { + icount->dcd++; +#ifdef CONFIG_HARD_PPS + if ((info->flags & ASYNC_HARDPPS_CD) && + (status & UART_MSR_DCD)) + hardpps(); +#endif + } + if (status & UART_MSR_DCTS) + icount->cts++; + wake_up_interruptible(&info->delta_msr_wait); + } + + if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) + printk("ttys%d CD now %s...", info->line, + (status & UART_MSR_DCD) ? "on" : "off"); +#endif + if (status & UART_MSR_DCD) + wake_up_interruptible(&info->open_wait); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { +#ifdef SERIAL_DEBUG_OPEN + printk("doing serial hangup..."); +#endif + if (info->tty) + tty_hangup(info->tty); + } + } + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty->hw_stopped) { + if (status & UART_MSR_CTS) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx start..."); +#endif + info->tty->hw_stopped = 0; + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return; + } + } else { + if (!(status & UART_MSR_CTS)) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx stop..."); +#endif + info->tty->hw_stopped = 1; + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + } + } +} + +#ifdef CONFIG_SERIAL_SHARE_IRQ +/* + * This is the serial driver's generic interrupt routine + */ +static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + struct async_struct * info; + int pass_counter = 0; + struct async_struct *end_mark = 0; +#ifdef CONFIG_SERIAL_MULTIPORT + int first_multi = 0; + struct rs_multiport_struct *multi; +#endif + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info) + return; + +#ifdef CONFIG_SERIAL_MULTIPORT + multi = &rs_multiport[irq]; + if (multi->port_monitor) + first_multi = inb(multi->port_monitor); +#endif + + do { + if (!info->tty || + (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { + if (!end_mark) + end_mark = info; + goto next; + } + end_mark = 0; + + info->last_active = jiffies; + + status = serial_inp(info, UART_LSR); +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (status & UART_LSR_DR) + receive_chars(info, &status, regs); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + + next: + info = info->next_port; + if (!info) { + info = IRQ_ports[irq]; + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#if 0 + printk("rs loop break\n"); +#endif + break; /* Prevent infinite loops */ + } + continue; + } + } while (end_mark != info); +#ifdef CONFIG_SERIAL_MULTIPORT + if (multi->port_monitor) + printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n", + info->state->irq, first_multi, + inb(multi->port_monitor)); +#endif +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} +#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */ + + +/* + * This is the serial driver's interrupt routine for a single port + */ +static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + int pass_counter = 0; + struct async_struct * info; +#ifdef CONFIG_SERIAL_MULTIPORT + int first_multi = 0; + struct rs_multiport_struct *multi; +#endif + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_single(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info || !info->tty) + return; + +#ifdef CONFIG_SERIAL_MULTIPORT + multi = &rs_multiport[irq]; + if (multi->port_monitor) + first_multi = inb(multi->port_monitor); +#endif + + do { + status = serial_inp(info, UART_LSR); +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (status & UART_LSR_DR) + receive_chars(info, &status, regs); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#if 0 + printk("rs_single loop break.\n"); +#endif + break; + } + } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); + info->last_active = jiffies; +#ifdef CONFIG_SERIAL_MULTIPORT + if (multi->port_monitor) + printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n", + info->state->irq, first_multi, + inb(multi->port_monitor)); +#endif +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + +#ifdef CONFIG_SERIAL_MULTIPORT +/* + * This is the serial driver's for multiport boards + */ +static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + struct async_struct * info; + int pass_counter = 0; + int first_multi= 0; + struct rs_multiport_struct *multi; + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_multi(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info) + return; + multi = &rs_multiport[irq]; + if (!multi->port1) { + /* Should never happen */ + printk("rs_interrupt_multi: NULL port1!\n"); + return; + } + if (multi->port_monitor) + first_multi = inb(multi->port_monitor); + + while (1) { + if (!info->tty || + (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) + goto next; + + info->last_active = jiffies; + + status = serial_inp(info, UART_LSR); +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (status & UART_LSR_DR) + receive_chars(info, &status, regs); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + + next: + info = info->next_port; + if (info) + continue; + + info = IRQ_ports[irq]; + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#if 1 + printk("rs_multi loop break\n"); +#endif + break; /* Prevent infinite loops */ + } + if (multi->port_monitor) + printk("rs port monitor irq %d: 0x%x, 0x%x\n", + info->state->irq, first_multi, + inb(multi->port_monitor)); + if ((inb(multi->port1) & multi->mask1) != multi->match1) + continue; + if (!multi->port2) + break; + if ((inb(multi->port2) & multi->mask2) != multi->match2) + continue; + if (!multi->port3) + break; + if ((inb(multi->port3) & multi->mask3) != multi->match3) + continue; + if (!multi->port4) + break; + if ((inb(multi->port4) & multi->mask4) != multi->match4) + continue; + break; + } +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} +#endif + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * by the serial driver to handle ports that do not have an interrupt + * (irq=0). This doesn't work very well for 16450's, but gives barely + * passable results for a 16550A. (Although at the expense of much + * CPU overhead). + */ +static void rs_timer(void) +{ + static unsigned long last_strobe = 0; + struct async_struct *info; + unsigned int i; + unsigned long flags; + + if ((jiffies - last_strobe) >= RS_STROBE_TIME) { + for (i=0; i < NR_IRQS; i++) { + info = IRQ_ports[i]; + if (!info) + continue; + save_flags(flags); cli(); +#ifdef CONFIG_SERIAL_SHARE_IRQ + if (info->next_port) { + do { + serial_out(info, UART_IER, 0); + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + info = info->next_port; + } while (info); +#ifdef CONFIG_SERIAL_MULTIPORT + if (rs_multiport[i].port1) + rs_interrupt_multi(i, NULL, NULL); + else +#endif + rs_interrupt(i, NULL, NULL); + } else +#endif /* CONFIG_SERIAL_SHARE_IRQ */ + rs_interrupt_single(i, NULL, NULL); + restore_flags(flags); + } + } + last_strobe = jiffies; + timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME; + timer_active |= 1 << RS_TIMER; + + if (IRQ_ports[0]) { + save_flags(flags); cli(); +#ifdef CONFIG_SERIAL_SHARE_IRQ + rs_interrupt(0, NULL, NULL); +#else + rs_interrupt_single(0, NULL, NULL); +#endif + restore_flags(flags); + + timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2; + } +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +/* + * This routine figures out the correct timeout for a particular IRQ. + * It uses the smallest timeout of all of the serial ports in a + * particular interrupt chain. Now only used for IRQ 0.... + */ +static void figure_IRQ_timeout(int irq) +{ + struct async_struct *info; + int timeout = 60*HZ; /* 60 seconds === a long time :-) */ + + info = IRQ_ports[irq]; + if (!info) { + IRQ_timeout[irq] = 60*HZ; + return; + } + while (info) { + if (info->timeout < timeout) + timeout = info->timeout; + info = info->next_port; + } + if (!irq) + timeout = timeout / 2; + IRQ_timeout[irq] = timeout ? timeout : 1; +} + +static int startup(struct async_struct * info) +{ + unsigned long flags; + int retval=0; + void (*handler)(int, void *, struct pt_regs *); + struct serial_state *state= info->state; + unsigned long page; +#ifdef CONFIG_SERIAL_MANY_PORTS + unsigned short ICP; +#endif + + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!CONFIGURED_SERIAL_PORT(state) || !state->type) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, state->irq); +#endif + + if (uart_config[info->state->type].flags & UART_STARTECH) { + /* Wake up UART */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + /* + * Turn off LCR == 0xBF so we actually set the IER + * register on the XR16C850 + */ + serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_IER, 0); + /* + * Now reset LCR so we can turn off the ECB bit + */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, 0); + /* + * For a XR16C850, we need to set the trigger levels + */ + if (info->state->type == PORT_16850) { + serial_outp(info, UART_FCTR, UART_FCTR_TRGD | + UART_FCTR_RX); + serial_outp(info, UART_TRG, UART_TRG_96); + serial_outp(info, UART_FCTR, UART_FCTR_TRGD | + UART_FCTR_TX); + serial_outp(info, UART_TRG, UART_TRG_96); + } + serial_outp(info, UART_LCR, 0); + } + + if (info->state->type == PORT_16750) { + /* Wake up UART */ + serial_outp(info, UART_IER, 0); + } + + if (info->state->type == PORT_16C950) { + /* Wake up and initialize UART */ + info->ACR = 0; + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_IER, 0); + serial_outp(info, UART_LCR, 0); + serial_icr_write(info, UART_CSR, 0); /* Reset the UART */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_LCR, 0); + } + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + if (uart_config[state->type].flags & UART_CLEAR_FIFO) { + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + serial_outp(info, UART_FCR, 0); + } + + /* + * Clear the interrupt registers. + */ + (void) serial_inp(info, UART_LSR); + (void) serial_inp(info, UART_RX); + (void) serial_inp(info, UART_IIR); + (void) serial_inp(info, UART_MSR); + + /* + * At this point there's no way the LSR could still be 0xFF; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (serial_inp(info, UART_LSR) == 0xff) { + printk("LSR safety check engaged!\n"); + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + } else + retval = -ENODEV; + goto errout; + } + + /* + * Allocate the IRQ if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { +#ifdef CONFIG_SERIAL_SHARE_IRQ + free_irq(state->irq, &IRQ_ports[state->irq]); +#ifdef CONFIG_SERIAL_MULTIPORT + if (rs_multiport[state->irq].port1) + handler = rs_interrupt_multi; + else +#endif + handler = rs_interrupt; +#else + retval = -EBUSY; + goto errout; +#endif /* CONFIG_SERIAL_SHARE_IRQ */ + } else + handler = rs_interrupt_single; + + retval = request_irq(state->irq, handler, SA_SHIRQ, + "serial", &IRQ_ports[state->irq]); + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; + } + goto errout; + } + } + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[state->irq]; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports[state->irq] = info; + figure_IRQ_timeout(state->irq); + + /* + * Now, initialize the UART + */ + serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + + info->MCR = 0; + if (info->tty->termios->c_cflag & CBAUD) + info->MCR = UART_MCR_DTR | UART_MCR_RTS; +#ifdef CONFIG_SERIAL_MANY_PORTS + if (info->flags & ASYNC_FOURPORT) { + if (state->irq == 0) + info->MCR |= UART_MCR_OUT1; + } else +#endif + { + if (state->irq != 0) + info->MCR |= UART_MCR_OUT2; + } + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + serial_outp(info, UART_MCR, info->MCR); + + /* + * Finally, enable interrupts + */ + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; + serial_outp(info, UART_IER, info->IER); /* enable interrupts */ + +#ifdef CONFIG_SERIAL_MANY_PORTS + if (info->flags & ASYNC_FOURPORT) { + /* Enable interrupts on the AST Fourport board */ + ICP = (info->port & 0xFE0) | 0x01F; + outb_p(0x80, ICP); + (void) inb_p(ICP); + } +#endif + + /* + * And clear the interrupt registers again for luck. + */ + (void)serial_inp(info, UART_LSR); + (void)serial_inp(info, UART_RX); + (void)serial_inp(info, UART_IIR); + (void)serial_inp(info, UART_MSR); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * Set up serial timers... + */ + timer_table[RS_TIMER].expires = jiffies + 2*HZ/100; + timer_active |= 1 << RS_TIMER; + + /* + * Set up the tty->alt_speed kludge + */ +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } +#endif + + /* + * and set the speed of the serial port + */ + change_speed(info, 0); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info) +{ + unsigned long flags; + struct serial_state *state; + int retval; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, &IRQ_ports[state->irq]); + retval = request_irq(state->irq, rs_interrupt_single, + SA_SHIRQ, "serial", + &IRQ_ports[state->irq]); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, &IRQ_ports[state->irq]); + } + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + info->IER = 0; + serial_outp(info, UART_IER, 0x00); /* disable all intrs */ +#ifdef CONFIG_SERIAL_MANY_PORTS + if (info->flags & ASYNC_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + (void) inb((info->port & 0xFE0) | 0x01F); + info->MCR |= UART_MCR_OUT1; + } else +#endif + info->MCR &= ~UART_MCR_OUT2; + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + + /* disable break condition */ + serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC); + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + serial_outp(info, UART_MCR, info->MCR); + + /* disable FIFO's */ + serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + serial_outp(info, UART_FCR, 0); + + (void)serial_in(info, UART_RX); /* read data port to reset things */ + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + if (uart_config[info->state->type].flags & UART_STARTECH) { + /* Arrange to enter sleep mode */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_IER, UART_IERX_SLEEP); + serial_outp(info, UART_LCR, 0); + } + if (info->state->type == PORT_16750) { + /* Arrange to enter sleep mode */ + serial_outp(info, UART_IER, UART_IERX_SLEEP); + } + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, + 600, 1200, 1800, 2400, 4800, 9600, 19200, + 38400, 57600, 115200, 230400, 460800, 0 }; + +static int tty_get_baud_rate(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned int cflag, i; + + cflag = tty->termios->c_cflag; + + i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~CBAUDEX; + if (i < 1 || i > 2) + tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i += 1; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i += 2; + } + return baud_table[i]; +} +#endif + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(struct async_struct *info, + struct termios *old_termios) +{ + int quot = 0, baud_base, baud; + unsigned cflag, cval, fcr = 0; + int bits; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!CONFIGURED_SERIAL_PORT(info)) + return; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: cval = 0x00; bits = 7; break; + case CS6: cval = 0x01; bits = 8; break; + case CS7: cval = 0x02; bits = 9; break; + case CS8: cval = 0x03; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: cval = 0x00; bits = 7; break; + } + if (cflag & CSTOPB) { + cval |= 0x04; + bits++; + } + if (cflag & PARENB) { + cval |= UART_LCR_PARITY; + bits++; + } + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; /* B0 transition handled in rs_set_termios */ + baud_base = info->state->baud_base; + if (info->state->type == PORT_16C950) { + if (baud <= baud_base) + serial_icr_write(info, UART_TCR, 0); + else if (baud <= 2*baud_base) { + serial_icr_write(info, UART_TCR, 0x8); + baud_base = baud_base * 2; + } else if (baud <= 4*baud_base) { + serial_icr_write(info, UART_TCR, 0x4); + baud_base = baud_base * 4; + } else + serial_icr_write(info, UART_TCR, 0); + } + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*baud_base / 269); + else if (baud) + quot = baud_base / baud; + } + /* If the quotient is zero refuse the change */ + if (!quot && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2*baud_base / 269); + else if (baud) + quot = baud_base / baud; + } + } + /* As a last resort, if the quotient is zero, default to 9600 bps */ + if (!quot) + quot = baud_base / 9600; + info->quot = quot; + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + /* Set up FIFO's */ + if (uart_config[info->state->type].flags & UART_USE_FIFO) { + if ((info->state->baud_base / quot) < 2400) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; + } + if (info->state->type == PORT_16750) + fcr |= UART_FCR7_64BYTE; + + /* CTS flow control flag and modem status interrupts */ + info->IER &= ~UART_IER_MSI; + if (info->flags & ASYNC_HARDPPS_CD) + info->IER |= UART_IER_MSI; + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + info->IER |= UART_IER_MSI; + } else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else { + info->flags |= ASYNC_CHECK_CD; + info->IER |= UART_IER_MSI; + } + serial_out(info, UART_IER, info->IER); + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (I_INPCK(info->tty)) + info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_OE; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->ignore_status_mask |= UART_LSR_DR; + save_flags(flags); cli(); + if (uart_config[info->state->type].flags & UART_STARTECH) { + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, + (cflag & CRTSCTS) ? UART_EFR_CTS : 0); + } + serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */ + if (info->state->type == PORT_16750) + serial_outp(info, UART_FCR, fcr); /* set fcr */ + serial_outp(info, UART_LCR, cval); /* reset DLAB */ + info->LCR = cval; /* Save LCR */ + if (info->state->type != PORT_16750) + serial_outp(info, UART_FCR, fcr); /* set fcr */ + restore_flags(flags); +} + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + if (!tty || !info->xmit_buf) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + restore_flags(flags); + return; + } + + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= SERIAL_XMIT_SIZE-1; + info->xmit_cnt++; + restore_flags(flags); +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + save_flags(flags); cli(); + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf || !tmp_buf) + return 0; + + save_flags(flags); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + } + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + return ret; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + save_flags(flags); cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_send_char")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) + info->MCR &= ~UART_MCR_RTS; + + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + if (tty->termios->c_cflag & CRTSCTS) + info->MCR |= UART_MCR_RTS; + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct async_struct * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + struct serial_state *state = info->state; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = state->type; + tmp.line = state->line; + tmp.port = state->port; + tmp.irq = state->irq; + tmp.flags = state->flags; + tmp.xmit_fifo_size = state->xmit_fifo_size; + tmp.baud_base = state->baud_base; + tmp.close_delay = state->close_delay; + tmp.closing_wait = state->closing_wait; + tmp.custom_divisor = state->custom_divisor; + tmp.hub6 = state->hub6; + tmp.io_type = state->io_type; + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_serial_info(struct async_struct * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct serial_state old_state, *state; + unsigned int i,change_irq,change_port; + int retval = 0; + + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; + state = info->state; + old_state = *state; + + change_irq = new_serial.irq != state->irq; + change_port = (new_serial.port != state->port) || + (new_serial.hub6 != state->hub6); + + if (!capable(CAP_SYS_ADMIN)) { + if (change_irq || change_port || + (new_serial.baud_base != state->baud_base) || + (new_serial.type != state->type) || + (new_serial.close_delay != state->close_delay) || + (new_serial.xmit_fifo_size != state->xmit_fifo_size) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (state->flags & ~ASYNC_USR_MASK))) + return -EPERM; + state->flags = ((state->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + state->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + new_serial.irq = irq_cannonicalize(new_serial.irq); + + if ((new_serial.irq >= NR_IRQS) || + (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) || + (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || + (new_serial.type == PORT_STARTECH)) { + return -EINVAL; + } + + if ((new_serial.type != state->type) || + (new_serial.xmit_fifo_size <= 0)) + new_serial.xmit_fifo_size = + uart_config[new_serial.type].dfl_xmit_fifo_size; + + /* Make sure address is not already in use */ + if (new_serial.type) { + for (i = 0 ; i < NR_PORTS; i++) + if ((state != &rs_table[i]) && + (rs_table[i].port == new_serial.port) && + rs_table[i].type) + return -EADDRINUSE; + } + + if ((change_port || change_irq) && (state->count > 1)) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + state->baud_base = new_serial.baud_base; + state->flags = ((state->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | + (info->flags & ASYNC_INTERNAL_FLAGS)); + state->custom_divisor = new_serial.custom_divisor; + state->close_delay = new_serial.close_delay * HZ/100; + state->closing_wait = new_serial.closing_wait * HZ/100; +#if (LINUX_VERSION_CODE > 0x20100) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + info->xmit_fifo_size = state->xmit_fifo_size = + new_serial.xmit_fifo_size; + + if ((state->type != PORT_UNKNOWN) && state->port) + release_region(state->port,8); + state->type = new_serial.type; + if (change_port || change_irq) { + /* + * We need to shutdown the serial port at the old + * port/irq combination. + */ + shutdown(info); + state->irq = new_serial.irq; + info->port = state->port = new_serial.port; + info->hub6 = state->hub6 = new_serial.hub6; + if (info->hub6) + info->io_type = state->io_type = SERIAL_IO_HUB6; + else if (info->io_type == SERIAL_IO_HUB6) + info->io_type = state->io_type = SERIAL_IO_PORT; + } + if ((state->type != PORT_UNKNOWN) && state->port) + request_region(state->port,8,"serial(set)"); + + +check_and_exit: + if (!state->port || !state->type) + return 0; + if (info->flags & ASYNC_INITIALIZED) { + if (((old_state.flags & ASYNC_SPD_MASK) != + (state->flags & ASYNC_SPD_MASK)) || + (old_state.custom_divisor != state->custom_divisor)) { +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; +#endif + change_speed(info, 0); + } + } else + retval = startup(info); + return retval; +} + + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct async_struct * info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + unsigned long flags; + + save_flags(flags); cli(); + status = serial_in(info, UART_LSR); + restore_flags(flags); + result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + + /* + * If we're about to load something into the transmit + * register, we'll pretend the transmitter isn't empty to + * avoid a race condition (depending on when the transmit + * interrupt happens). + */ + if (info->x_char || + ((info->xmit_cnt > 0) && !info->tty->stopped && + !info->tty->hw_stopped)) + result &= TIOCSER_TEMT; + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + + +static int get_modem_info(struct async_struct * info, unsigned int *value) +{ + unsigned char control, status; + unsigned int result; + unsigned long flags; + + control = info->MCR; + save_flags(flags); cli(); + status = serial_in(info, UART_MSR); + restore_flags(flags); + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) + | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) +#ifdef TIOCM_OUT1 + | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) + | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) +#endif + | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) + | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) + | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) + | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +static int set_modem_info(struct async_struct * info, unsigned int cmd, + unsigned int *value) +{ + unsigned int arg; + unsigned long flags; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + info->MCR |= UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR |= UART_MCR_DTR; +#ifdef TIOCM_OUT1 + if (arg & TIOCM_OUT1) + info->MCR |= UART_MCR_OUT1; + if (arg & TIOCM_OUT2) + info->MCR |= UART_MCR_OUT2; +#endif + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + info->MCR &= ~UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR &= ~UART_MCR_DTR; +#ifdef TIOCM_OUT1 + if (arg & TIOCM_OUT1) + info->MCR &= ~UART_MCR_OUT1; + if (arg & TIOCM_OUT2) + info->MCR &= ~UART_MCR_OUT2; +#endif + break; + case TIOCMSET: + info->MCR = ((info->MCR & ~(UART_MCR_RTS | +#ifdef TIOCM_OUT1 + UART_MCR_OUT1 | + UART_MCR_OUT2 | +#endif + UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) +#ifdef TIOCM_OUT1 + | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0) + | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0) +#endif + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + break; + default: + return -EINVAL; + } + save_flags(flags); cli(); + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); + return 0; +} + +static int do_autoconfig(struct async_struct * info) +{ + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (info->state->count > 1) + return -EBUSY; + + shutdown(info); + + autoconfig(info->state); + if ((info->state->flags & ASYNC_AUTO_IRQ) && + (info->state->port != 0) && + (info->state->type != PORT_UNKNOWN)) + info->state->irq = detect_uart_irq(info->state); + + retval = startup(info); + if (retval) + return retval; + return 0; +} + +/* + * rs_break() --- routine which turns the break handling on or off + */ +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ +static void send_break( struct async_struct * info, int duration) +{ + if (!CONFIGURED_SERIAL_PORT(info)) + return; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + duration; + cli(); + info->LCR |= UART_LCR_SBC; + serial_out(info, UART_LCR, info->LCR); + schedule(); + info->LCR &= ~UART_LCR_SBC; + serial_out(info, UART_LCR, info->LCR); + sti(); +} +#else +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_break")) + return; + + if (!CONFIGURED_SERIAL_PORT(info)) + return; + save_flags(flags); cli(); + if (break_state == -1) + info->LCR |= UART_LCR_SBC; + else + info->LCR &= ~UART_LCR_SBC; + serial_out(info, UART_LCR, info->LCR); + restore_flags(flags); +} +#endif + +#ifdef CONFIG_SERIAL_MULTIPORT +static int get_multiport_struct(struct async_struct * info, + struct serial_multiport_struct *retinfo) +{ + struct serial_multiport_struct ret; + struct rs_multiport_struct *multi; + + multi = &rs_multiport[info->state->irq]; + + ret.port_monitor = multi->port_monitor; + + ret.port1 = multi->port1; + ret.mask1 = multi->mask1; + ret.match1 = multi->match1; + + ret.port2 = multi->port2; + ret.mask2 = multi->mask2; + ret.match2 = multi->match2; + + ret.port3 = multi->port3; + ret.mask3 = multi->mask3; + ret.match3 = multi->match3; + + ret.port4 = multi->port4; + ret.mask4 = multi->mask4; + ret.match4 = multi->match4; + + ret.irq = info->state->irq; + + if (copy_to_user(retinfo,&ret,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_multiport_struct(struct async_struct * info, + struct serial_multiport_struct *in_multi) +{ + struct serial_multiport_struct new_multi; + struct rs_multiport_struct *multi; + struct serial_state *state; + int was_multi, now_multi; + int retval; + void (*handler)(int, void *, struct pt_regs *); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + state = info->state; + + if (copy_from_user(&new_multi, in_multi, + sizeof(struct serial_multiport_struct))) + return -EFAULT; + + if (new_multi.irq != state->irq || state->irq == 0 || + !IRQ_ports[state->irq]) + return -EINVAL; + + multi = &rs_multiport[state->irq]; + was_multi = (multi->port1 != 0); + + multi->port_monitor = new_multi.port_monitor; + + if (multi->port1) + release_region(multi->port1,1); + multi->port1 = new_multi.port1; + multi->mask1 = new_multi.mask1; + multi->match1 = new_multi.match1; + if (multi->port1) + request_region(multi->port1,1,"serial(multiport1)"); + + if (multi->port2) + release_region(multi->port2,1); + multi->port2 = new_multi.port2; + multi->mask2 = new_multi.mask2; + multi->match2 = new_multi.match2; + if (multi->port2) + request_region(multi->port2,1,"serial(multiport2)"); + + if (multi->port3) + release_region(multi->port3,1); + multi->port3 = new_multi.port3; + multi->mask3 = new_multi.mask3; + multi->match3 = new_multi.match3; + if (multi->port3) + request_region(multi->port3,1,"serial(multiport3)"); + + if (multi->port4) + release_region(multi->port4,1); + multi->port4 = new_multi.port4; + multi->mask4 = new_multi.mask4; + multi->match4 = new_multi.match4; + if (multi->port4) + request_region(multi->port4,1,"serial(multiport4)"); + + now_multi = (multi->port1 != 0); + + if (IRQ_ports[state->irq]->next_port && + (was_multi != now_multi)) { + free_irq(state->irq, &IRQ_ports[state->irq]); + if (now_multi) + handler = rs_interrupt_multi; + else + handler = rs_interrupt; + + retval = request_irq(state->irq, handler, SA_SHIRQ, + "serial", &IRQ_ports[state->irq]); + if (retval) { + printk("Couldn't reallocate serial interrupt " + "driver!!\n"); + } + } + return 0; +} +#endif + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct icount; + unsigned long flags; +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ + int retval, tmp; +#endif + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + if (!arg) { + send_break(info, HZ/4); /* 1/4 second */ + if (signal_pending(current)) + return -EINTR; + } + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + send_break(info, arg ? arg*(HZ/10) : HZ/4); + if (signal_pending(current)) + return -EINTR; + return 0; + case TIOCGSOFTCAR: + tmp = C_CLOCAL(tty) ? 1 : 0; + if (copy_to_user((void *)arg, &tmp, sizeof(int))) + return -EFAULT; + return 0; + case TIOCSSOFTCAR: + if (copy_from_user(&tmp, (void *)arg, sizeof(int))) + return -EFAULT; + + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (tmp ? CLOCAL : 0)); + return 0; +#endif + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERCONFIG: + return do_autoconfig(info); + + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct async_struct *) arg, + info, sizeof(struct async_struct))) + return -EFAULT; + return 0; + +#ifdef CONFIG_SERIAL_MULTIPORT + case TIOCSERGETMULTI: + return get_multiport_struct(info, + (struct serial_multiport_struct *) arg); + case TIOCSERSETMULTI: + return set_multiport_struct(info, + (struct serial_multiport_struct *) arg); +#endif + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + save_flags(flags); cli(); + /* note the counters on entry */ + cprev = info->state->icount; + restore_flags(flags); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + save_flags(flags); cli(); + cnow = info->state->icount; /* atomic copy */ + restore_flags(flags); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + save_flags(flags); cli(); + cnow = info->state->icount; + restore_flags(flags); + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + if (copy_to_user((void *)arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + if ( (cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(cflag & CBAUD)) { + info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (cflag & CBAUD)) { + info->MCR |= UART_MCR_DTR; + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + info->MCR |= UART_MCR_RTS; + } + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } + +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + DBG_CNT("before DEC-hung"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + DBG_CNT("before DEC-2"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->IER &= ~UART_IER_RLSI; + info->read_status_mask &= ~UART_LSR_DR; + if (info->flags & ASYNC_INITIALIZED) { + serial_out(info, UART_IER, info->IER); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + rs_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; + restore_flags(flags); +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int lsr; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + + if (info->state->type == PORT_UNKNOWN) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...", lsr, jiffies); +#endif + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + set_current_state(TASK_RUNNING); +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#endif +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + state = info->state; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct async_struct *info) +{ + DECLARE_WAITQUEUE(wait, current); + struct serial_state *state = info->state; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, state->count); +#endif + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + state->count--; + } + restore_flags(flags); + info->blocked_open++; + while (1) { + save_flags(flags); cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + serial_out(info, UART_MCR, + serial_inp(info, UART_MCR) | + (UART_MCR_DTR | UART_MCR_RTS)); + restore_flags(flags); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (serial_in(info, UART_MSR) & + UART_MSR_DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + state->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->io_type = sstate->io_type; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + info->iomem_base = sstate->iomem_base; + info->iomem_reg_shift = sstate->iomem_reg_shift; +#endif + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree_s(info, sizeof(struct async_struct)); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + + MOD_INC_USE_COUNT; + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + retval = get_async_struct(line, &info); + if (retval) { + MOD_DEC_USE_COUNT; + return retval; + } + tty->driver_data = info; + info->tty = tty; + if (serial_paranoia_check(info, tty->device, "rs_open")) + return -ENODEV; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif +#if (LINUX_VERSION_CODE > 0x20100) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + + if (!tmp_buf) { + page = get_zeroed_page(GFP_KERNEL); + if (!page) { + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) { + return retval; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + change_speed(info, 0); + } +#ifdef CONFIG_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + change_speed(info, 0); + } +#endif + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ + struct async_struct *info = state->info, scr_info; + char stat_buf[30], control, status; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", + state->line, uart_config[state->type].name, + state->port, state->irq); + + if (!state->port || (state->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + save_flags(flags); cli(); + status = serial_in(info, UART_MSR); + control = info ? info->MCR : serial_in(info, UART_MCR); + restore_flags(flags); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (control & UART_MCR_RTS) + strcat(stat_buf, "|RTS"); + if (status & UART_MSR_CTS) + strcat(stat_buf, "|CTS"); + if (control & UART_MCR_DTR) + strcat(stat_buf, "|DTR"); + if (status & UART_MSR_DSR) + strcat(stat_buf, "|DSR"); + if (status & UART_MSR_DCD) + strcat(stat_buf, "|CD"); + if (status & UART_MSR_RI) + strcat(stat_buf, "|RI"); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; +} + +int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n", + serial_version, LOCAL_VERSTRING, serial_revdate); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s%s (%s) with", serial_name, + serial_version, LOCAL_VERSTRING, serial_revdate); +#ifdef CONFIG_HUB6 + printk(" HUB-6"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_MANY_PORTS + printk(" MANY_PORTS"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_MULTIPORT + printk(" MULTIPORT"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_SHARE_IRQ + printk(" SHARE_IRQ"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_SERIAL_DETECT_IRQ + printk(" DETECT_IRQ"); +#define SERIAL_OPT +#endif +#ifdef ENABLE_SERIAL_PCI + printk(" SERIAL_PCI"); +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + printk(" PCI_IOMEM"); +#endif +#define SERIAL_OPT +#endif +#ifdef SERIAL_OPT + printk(" enabled\n"); +#else + printk(" no serial options enabled\n"); +#endif +#undef SERIAL_OPT +} + +/* + * This routine detect the IRQ of a serial port by clearing OUT2 when + * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at + * each time, as long as no other device permanently request the IRQ. + * If no IRQ is detected, or multiple IRQ appear, this function returns 0. + * The variable "state" and the field "state->port" should not be null. + */ +static unsigned detect_uart_irq (struct serial_state * state) +{ + int irq; + unsigned long irqs; + unsigned char save_mcr, save_ier; + struct async_struct scr_info; /* serial_{in,out} because HUB6 */ + +#ifdef CONFIG_SERIAL_MANY_PORTS + unsigned char save_ICP=0; /* no warning */ + unsigned short ICP=0; + + if (state->flags & ASYNC_FOURPORT) { + ICP = (state->port & 0xFE0) | 0x01F; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); + (void) inb_p(ICP); + } +#endif + scr_info.magic = SERIAL_MAGIC; + scr_info.port = state->port; + scr_info.flags = state->flags; +#ifdef CONFIG_HUB6 + scr_info.hub6 = state->hub6; +#endif + + /* forget possible initially masked and pending IRQ */ + probe_irq_off(probe_irq_on()); + save_mcr = serial_inp(&scr_info, UART_MCR); + save_ier = serial_inp(&scr_info, UART_IER); + serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + + irqs = probe_irq_on(); + serial_outp(&scr_info, UART_MCR, 0); + udelay (10); + if (state->flags & ASYNC_FOURPORT) { + serial_outp(&scr_info, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS); + } else { + serial_outp(&scr_info, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + } + serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */ + (void)serial_inp(&scr_info, UART_LSR); + (void)serial_inp(&scr_info, UART_RX); + (void)serial_inp(&scr_info, UART_IIR); + (void)serial_inp(&scr_info, UART_MSR); + serial_outp(&scr_info, UART_TX, 0xFF); + udelay (20); + irq = probe_irq_off(irqs); + + serial_outp(&scr_info, UART_MCR, save_mcr); + serial_outp(&scr_info, UART_IER, save_ier); +#ifdef CONFIG_SERIAL_MANY_PORTS + if (state->flags & ASYNC_FOURPORT) + outb_p(save_ICP, ICP); +#endif + return (irq > 0)? irq : 0; +} + +/* + * This is a quickie test to see how big the FIFO is. + * It doesn't work at all the time, more's the pity. + */ +static int size_fifo(struct async_struct *info) +{ + unsigned char old_fcr, old_mcr, old_dll, old_dlm; + int count; + + old_fcr = serial_inp(info, UART_FCR); + old_mcr = serial_inp(info, UART_MCR); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(info, UART_MCR, UART_MCR_LOOP); + serial_outp(info, UART_LCR, UART_LCR_DLAB); + old_dll = serial_inp(info, UART_DLL); + old_dlm = serial_inp(info, UART_DLM); + serial_outp(info, UART_DLL, 0x01); + serial_outp(info, UART_DLM, 0x00); + serial_outp(info, UART_LCR, 0x03); + for (count = 0; count < 256; count++) + serial_outp(info, UART_TX, count); + mdelay(20); + for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) && + (count < 256); count++) + serial_inp(info, UART_RX); + serial_outp(info, UART_FCR, old_fcr); + serial_outp(info, UART_MCR, old_mcr); + serial_outp(info, UART_LCR, UART_LCR_DLAB); + serial_outp(info, UART_DLL, old_dll); + serial_outp(info, UART_DLM, old_dlm); + + return count; +} + +/* + * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. + * When this function is called we know it is at least a StarTech + * 16650 V2, but it might be one of several StarTech UARTs, or one of + * its clones. (We treat the broken original StarTech 16650 V1 as a + * 16550, and why not? Startech doesn't seem to even acknowledge its + * existence.) + * + * What evil have men's minds wrought... + */ +static void autoconfig_startech_uarts(struct async_struct *info, + struct serial_state *state, + unsigned long flags) +{ + unsigned char scratch, scratch2, scratch3; + + /* + * First we check to see if it's an Oxford Semiconductor UART. + * + * If we have to do this here because some non-National + * Semiconductor clone chips lock up if you try writing to the + * LSR register (which serial_icr_read does) + */ + if (state->type == PORT_16550A) { + /* Check for Oxford Semiconductor 16C950 */ + scratch = serial_icr_read(info, UART_ID1); + scratch2 = serial_icr_read(info, UART_ID2); + scratch3 = serial_icr_read(info, UART_ID3); + + if (scratch == 0x16 && scratch2 == 0xC9 && + (scratch3 == 0x50 || scratch3 == 0x52 || + scratch3 == 0x54)) { + state->type = PORT_16C950; + state->revision = serial_icr_read(info, UART_REV); + return; + } + } + + /* + * We check for a XR16C850 by setting DLL and DLM to 0, and + * then reading back DLL and DLM. If DLM reads back 0x10, + * then the UART is a XR16C850 and the DLL contains the chip + * revision. If DLM reads back 0x14, then the UART is a + * XR16C854. + * + */ + serial_outp(info, UART_LCR, UART_LCR_DLAB); + serial_outp(info, UART_DLL, 0); + serial_outp(info, UART_DLM, 0); + state->revision = serial_inp(info, UART_DLL); + scratch = serial_inp(info, UART_DLM); + serial_outp(info, UART_LCR, 0); + if (scratch == 0x10 || scratch == 0x14) { + state->type = PORT_16850; + return; + } + + /* + * We distinguish between the '654 and the '650 by counting + * how many bytes are in the FIFO. I'm using this for now, + * since that's the technique that was sent to me in the + * serial driver update, but I'm not convinced this works. + * I've had problems doing this in the past. -TYT + */ + if (size_fifo(info) == 64) + state->type = PORT_16654; + else + state->type = PORT_16650V2; +} + +/* + * This routine is called by rs_init() to initialize a specific serial + * port. It determines what type of UART chip this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ +static void autoconfig(struct serial_state * state) +{ + unsigned char status1, status2, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; + struct async_struct *info, scr_info; + unsigned long flags; + + state->type = PORT_UNKNOWN; + +#ifdef SERIAL_DEBUG_AUTOCONF + printk("Testing ttyS%d (0x%04x, 0x%04x)...\n", state->line, + state->port, (unsigned) state->iomem_base); +#endif + + if (!CONFIGURED_SERIAL_PORT(state)) + return; + + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; +#ifdef CONFIG_HUB6 + info->hub6 = state->hub6; +#endif + info->io_type = state->io_type; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; +#endif + + save_flags(flags); cli(); + + if (!state->iomem_base) { + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. + * + * 0x80 is used as a nonsense port to prevent against + * false positives due to ISA bus float. The + * assumption is that 0x80 is a non-existent port; + * which should be safe since include/asm/io.h also + * makes this assumption. + */ + scratch = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + scratch2 = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, 0x0F); +#ifdef __i386__ + outb(0, 0x080); +#endif + scratch3 = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, scratch); + if (scratch2 || scratch3 != 0x0F) { +#ifdef SERIAL_DEBUG_AUTOCONF + printk("serial: ttyS%d: simple autoconfig failed\n", + state->line); +#endif + restore_flags(flags); + return; /* We failed; there's nothing here */ + } + } + + save_mcr = serial_in(info, UART_MCR); + save_lcr = serial_in(info, UART_LCR); + + /* + * Check to see if a UART is really there. Certain broken + * internal modems based on the Rockwell chipset fail this + * test, because they apparently don't implement the loopback + * test mode. So this test is skipped on the COM 1 through + * COM 4 ports. This *should* be safe, since no board + * manufacturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ + if (!(state->flags & ASYNC_SKIP_TEST)) { + serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_inp(info, UART_MSR) & 0xF0; + serial_outp(info, UART_MCR, save_mcr); + if (status1 != 0x90) { +#ifdef SERIAL_DEBUG_AUTOCONF + printk("serial: ttyS%d: no UART loopback failed\n", + state->line); +#endif + restore_flags(flags); + return; + } + } + serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */ + serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */ + serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(info, UART_IIR) >> 6; + switch (scratch) { + case 0: + state->type = PORT_16450; + break; + case 1: + state->type = PORT_UNKNOWN; + break; + case 2: + state->type = PORT_16550; + break; + case 3: + state->type = PORT_16550A; + break; + } + if (state->type == PORT_16550A) { + /* Check for Startech UART's */ + serial_outp(info, UART_LCR, UART_LCR_DLAB); + if (serial_in(info, UART_EFR) == 0) { + state->type = PORT_16650; + } else { + serial_outp(info, UART_LCR, 0xBF); + if (serial_in(info, UART_EFR) == 0) + autoconfig_startech_uarts(info, state, flags); + } + } + if (state->type == PORT_16550A) { + /* Check for TI 16750 */ + serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB); + serial_outp(info, UART_FCR, + UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + scratch = serial_in(info, UART_IIR) >> 5; + if (scratch == 7) { + /* + * If this is a 16750, and not a cheap UART + * clone, then it should only go into 64 byte + * mode if the UART_FCR7_64BYTE bit was set + * while UART_LCR_DLAB was latched. + */ + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(info, UART_LCR, 0); + serial_outp(info, UART_FCR, + UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + scratch = serial_in(info, UART_IIR) >> 5; + if (scratch == 6) + state->type = PORT_16750; + } + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + } + serial_outp(info, UART_LCR, save_lcr); + if (state->type == PORT_16450) { + scratch = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0xa5); + status1 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0x5a); + status2 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, scratch); + + if ((status1 != 0xa5) || (status2 != 0x5a)) + state->type = PORT_8250; + } + state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size; + + if (state->type == PORT_UNKNOWN) { + restore_flags(flags); + return; + } + + if (info->port) + request_region(info->port,8,"serial(auto)"); + + /* + * Reset the UART. + */ + serial_outp(info, UART_MCR, save_mcr); + serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + serial_outp(info, UART_FCR, 0); + (void)serial_in(info, UART_RX); + serial_outp(info, UART_IER, 0); + + restore_flags(flags); +} + +int register_serial(struct serial_struct *req); +void unregister_serial(int line); + +#if (LINUX_VERSION_CODE > 0x20100) +EXPORT_SYMBOL(register_serial); +EXPORT_SYMBOL(unregister_serial); +#else +static struct symbol_table serial_syms = { +#include + X(register_serial), + X(unregister_serial), +#include +}; +#endif + +#ifdef ENABLE_SERIAL_PCI +/* + * Some PCI serial cards using the PLX 9050 PCI interface chip require + * that the card interrupt be explicitly enabled or disabled. This + * seems to be mainly needed on card using the PLX which also use I/O + * mapped memory. + * + * Note that __init is a no-op if MODULE is defined; we depend on this. + */ +static int __init pci_plx9050_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + u8 data, *p, scratch; + + pci_read_config_byte(dev, PCI_COMMAND, &data); + + if (enable) + pci_write_config_byte(dev, PCI_COMMAND, + data | PCI_COMMAND_MEMORY); + + /* enable/disable interrupts */ + p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); + if (board->vendor == PCI_VENDOR_ID_PANACOM) { + scratch = readl(p + 0x4c); + if (enable) + scratch |= 0x40; + else + scratch &= ~0x40; + writel(scratch, p + 0x4c); + } else + writel(enable ? 0x41 : 0x00, p + 0x4c); + iounmap(p); + + if (!enable) + pci_write_config_byte(dev, PCI_COMMAND, + data & ~PCI_COMMAND_MEMORY); + return 0; +} + +/* + * SIIG serial cards have an PCI interface chip which also controls + * the UART clocking frequency. Each UART can be clocked independently + * (except cards equiped with 4 UARTs) and initial clocking settings + * are stored in the EEPROM chip. It can cause problems because this + * version of serial driver doesn't support differently clocked UART's + * on single PCI card. To prevent this, initialization functions set + * high frequency clocking for all UART's on given card. It is safe (I + * hope) because it doesn't touch EEPROM settings to prevent conflicts + * with other OSes (like M$ DOS). + * + * SIIG support added by Andrey Panin , 10/1999 + * + * There is two family of SIIG serial cards with different PCI + * interface chip and different configuration methods: + * - 10x cards have control registers in IO and/or memory space; + * - 20x cards have control registers in standard PCI configuration space. + */ + +#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) + +static int __init pci_siig10x_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + u16 data, *p; + + if (!enable) return 0; + + p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); + + switch (dev->device & 0xfff8) { + case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ + data = 0xffdf; + break; + case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */ + data = 0xf7ff; + break; + default: /* 1S1P, 4S */ + data = 0xfffb; + break; + } + + writew(readw(p + 0x28) & data, p + 0x28); + iounmap(p); + return 0; +} + +#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) + +static int __init pci_siig20x_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + u8 data; + + if (!enable) return 0; + + /* Change clock frequency for the first UART. */ + pci_read_config_byte(dev, 0x6f, &data); + pci_write_config_byte(dev, 0x6f, data & 0xef); + + /* If this card has 2 UART, we have to do the same with second UART. */ + if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) || + ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) { + pci_read_config_byte(dev, 0x73, &data); + pci_write_config_byte(dev, 0x73, data & 0xef); + } + return 0; +} + +/* + * This is the configuration table for all of the PCI serial boards + * which we support. + */ +static struct pci_board pci_boards[] = { + /* + * Vendor ID, Device ID, + * Subvendor ID, Subdevice ID, + * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, + * Offset to get to next UART's registers + * Register shift to use for memory-mapped I/O + */ + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, + SPCI_FL_BASE1, 8, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, + SPCI_FL_BASE1, 4, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, + SPCI_FL_BASE1, 2, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, + SPCI_FL_BASE1, 8, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, + SPCI_FL_BASE1, 4, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, + SPCI_FL_BASE1, 2, 1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, + SPCI_FL_BASE1, 2, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, + SPCI_FL_BASE1, 8, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, + SPCI_FL_BASE1, 4, 921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, + SPCI_FL_BASE1, 2, 921600 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 8, 115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_KEYSPAN, + PCI_SUBDEVICE_ID_KEYSPAN_SX2, + SPCI_FL_BASE2 | SPCI_FL_IOMEM, 2, 921600, + 0x400, 7, pci_plx9050_fn }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0x400, 7, pci_plx9050_fn }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0x400, 7, pci_plx9050_fn }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST4, + SPCI_FL_BASE2, 4, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST8, + SPCI_FL_BASE2, 8, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16, + SPCI_FL_BASE2, 16, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, + SPCI_FL_BASE2, 16, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS4, + SPCI_FL_BASE2, 4, 460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS8, + SPCI_FL_BASE2, 8, 460800 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 4, 115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 2, 115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 8, 115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 8, 115200 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, + SPCI_FL_BASE0 , 4, 115200 }, + { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, + SPCI_FL_BASE0 , 4, 921600 }, + { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 , 2, 921600 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_SERIAL, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 460800, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 460800, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 460800, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 1, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig10x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig20x_fn }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, + 0, 0, pci_siig20x_fn }, + /* Computone devices submitted by Doug McNash dmcnash@computone.com */ + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, + SPCI_FL_IOMEM | SPCI_FL_BASE0, 4, 921600, + 0x40, 2, NULL, 0x200 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, + SPCI_FL_IOMEM | SPCI_FL_BASE0, 8, 921600, + 0x40, 2, NULL, 0x200 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, + SPCI_FL_IOMEM | SPCI_FL_BASE0, 6, 921600, + 0x40, 2, NULL, 0x200 }, + /* + * Untested PCI modems, sent in from various folks... + */ + /* at+t zoom 56K faxmodem, from dougd@shieldsbag.com */ + { PCI_VENDOR_ID_ATT, 0x442, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 1, 115200 }, + /* at&t unknown modem, from jimd@esoft.com */ + { PCI_VENDOR_ID_ATT, 0x480, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 1, 115200 }, + /* Elsa Model 56K PCI Modem, from Andreas Rath */ + { PCI_VENDOR_ID_ROCKWELL, 0x1004, + 0x1048, 0x1500, + SPCI_FL_BASE1, 1, 115200 }, + /* 3Com US Robotics 56k* Voice Internal PCI, model# 2884 */ + /* from evidal@iti.upv.es */ + /* XXX complete guess this may not work!!! */ + { PCI_VENDOR_ID_USR, 0x1006, + 0x12b9, 0x0060, + SPCI_FL_BASE1 | SPCI_FL_IOMEM, 1, 115200 }, + { 0, } +}; + +/* + * Query PCI space for known serial boards + * If found, add them to the PCI device space in rs_table[] + * + * Accept a maximum of eight boards + * + */ +static void probe_serial_pci(void) +{ + u16 subvendor, subdevice; + int k, line; + struct pci_dev *dev = NULL; + struct pci_board *board; + struct serial_struct fake_state; + int uart_offset, base_baud, base_idx; + unsigned long port; + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG "Entered probe_serial_pci()\n"); +#endif + + if (!pcibios_present()) { +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n"); +#endif + return; + } + + for(dev=pci_devices; dev; dev=dev->next) { + pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, + &subvendor); + pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice); + + for (board = pci_boards; board->vendor; board++) { + if (board->vendor != (unsigned short) PCI_ANY_ID && + dev->vendor != board->vendor) + continue; + if (board->device != (unsigned short) PCI_ANY_ID && + dev->device != board->device) + continue; + if (board->subvendor != (unsigned short) PCI_ANY_ID && + subvendor != board->subvendor) + continue; + if (board->subdevice != (unsigned short) PCI_ANY_ID && + subdevice != board->subdevice) + continue; + break; + } + + if (board->vendor == 0) { +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG + "Found unknown serial board: %x:%x, %x:%x, %x\n", + dev->vendor, dev->device, subvendor, subdevice, + dev->class); + printk(KERN_DEBUG + " Addresses: %lx, %lx, %lx, %lx\n", + PCI_BASE_ADDRESS(dev, 0), PCI_BASE_ADDRESS(dev, 1), + PCI_BASE_ADDRESS(dev, 2), PCI_BASE_ADDRESS(dev, 3)); +#endif + continue; + } + + /* + * Run the initialization function, if any + */ + if (board->init_fn) + if ((board->init_fn)(dev, board, 1) != 0) + continue; + + /* + * Register the serial board in the array so we can + * shutdown the board later, if necessary. + */ + if (serial_pci_board_idx >= NR_PCI_BOARDS) + continue; + serial_pci_board[serial_pci_board_idx].board = board; + serial_pci_board[serial_pci_board_idx].dev = dev; + serial_pci_board_idx++; + + base_idx = board->flags & SPCI_FL_BASE_MASK; + port = PCI_BASE_ADDRESS(dev, base_idx) + + board->first_uart_offset; + if (board->flags & SPCI_FL_IOMEM) + port &= PCI_BASE_ADDRESS_MEM_MASK; + else + port &= PCI_BASE_ADDRESS_IO_MASK; + + /* + * Set some defaults for the loop below, which + * actually registers each serial port belonging to + * the card. + */ + uart_offset = board->uart_offset; + if (!uart_offset) + uart_offset = 8; + base_baud = board->base_baud; + if (!base_baud) + base_baud = BASE_BAUD; +#ifndef CONFIG_SERIAL_PCI_MEMMAPPED + if (board->flags & SPCI_FL_IOMEM) { +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG + "Can't support memory mapped PCI serial device\n"); +#endif + continue; + } +#endif + memset(&fake_state, 0, sizeof(fake_state)); + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG + "Found Serial PCI device: %x:%x, %x:%x, %x\n", + dev->vendor, dev->device, subvendor, subdevice, + dev->class); + printk(KERN_DEBUG + " IRQ: %d, base: %lx (%s), num_ports: %d\n", + dev->irq, port, board->flags & SPCI_FL_IOMEM ? + "iomem" : "port", board->num_ports); +#endif + + for (k=0; k < board->num_ports; k++) { + if (board->flags & SPCI_FL_BASE_TABLE) { + port = PCI_BASE_ADDRESS(dev, base_idx++); + if (board->flags & SPCI_FL_IOMEM) + port &= PCI_BASE_ADDRESS_MEM_MASK; + else + port &= PCI_BASE_ADDRESS_IO_MASK; + } + fake_state.irq = dev->irq; + fake_state.port = port; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + if (board->flags & SPCI_FL_IOMEM) { + fake_state.io_type = SERIAL_IO_MEM; + fake_state.iomem_base = + ioremap(port, board->uart_offset); + fake_state.iomem_reg_shift = board->reg_shift; + fake_state.port = 0; + } +#endif + port += uart_offset; + fake_state.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; + line = register_serial(&fake_state); + if (line < 0) + break; + rs_table[line].baud_base = base_baud; + } + } + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n"); +#endif + return; +} + +#endif /* ENABLE_SERIAL_PCI */ + +/* + * The serial driver boot-time initialization code! + */ +int __init rs_init(void) +{ + int i; + struct serial_state * state; + extern void atomwide_serial_init (void); + extern void dualsp_serial_init (void); + +#ifdef CONFIG_ATOMWIDE_SERIAL + atomwide_serial_init (); +#endif +#ifdef CONFIG_DUALSP_SERIAL + dualsp_serial_init (); +#endif + + if (timer_table[RS_TIMER].fn) { + printk("RS_TIMER already set, another serial driver " + "already loaded?\n"); +#ifdef MODULE + printk("Can't load serial driver module over built-in " + "serial driver\n"); +#endif + return -EBUSY; + } + + init_bh(SERIAL_BH, do_serial_bh); + timer_table[RS_TIMER].fn = rs_timer; + timer_table[RS_TIMER].expires = 0; + + for (i = 0; i < NR_IRQS; i++) { + IRQ_ports[i] = 0; + IRQ_timeout[i] = 0; +#ifdef CONFIG_SERIAL_MULTIPORT + memset(&rs_multiport[i], 0, + sizeof(struct rs_multiport_struct)); +#endif + } +#ifdef CONFIG_SERIAL_CONSOLE + /* + * The interrupt of the serial console port + * can't be shared. + */ + if (sercons.flags & CON_CONSDEV) { + for(i = 0; i < NR_PORTS; i++) + if (i != sercons.index && + rs_table[i].irq == rs_table[sercons.index].irq) + rs_table[i].irq = 0; + } +#endif + show_serial_version(); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; +#if (LINUX_VERSION_CODE > 0x20100) + serial_driver.driver_name = "serial"; +#endif + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.put_char = rs_put_char; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + serial_driver.break_ctl = rs_break; +#endif +#if (LINUX_VERSION_CODE >= 131343) + serial_driver.send_xchar = rs_send_xchar; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; +#endif + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; +#if (LINUX_VERSION_CODE >= 131343) + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; +#endif + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + state->irq = irq_cannonicalize(state->irq); + if (state->hub6) + state->io_type = SERIAL_IO_HUB6; + if (state->port && check_region(state->port,8)) + continue; + if (state->flags & ASYNC_BOOT_AUTOCONF) + autoconfig(state); + } + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + if (state->type == PORT_UNKNOWN) + continue; + if ( (state->flags & ASYNC_BOOT_AUTOCONF) + && (state->flags & ASYNC_AUTO_IRQ) + && (state->port != 0)) + state->irq = detect_uart_irq(state); + printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n", + state->line + SERIAL_DEV_OFFSET, + (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", + state->port, state->irq, + uart_config[state->type].name); + } +#ifdef ENABLE_SERIAL_PCI + probe_serial_pci(); +#endif + return 0; +} + +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + */ +int register_serial(struct serial_struct *req) +{ + int i; + unsigned long flags; + struct serial_state *state; + + save_flags(flags); + cli(); + for (i = 0; i < NR_PORTS; i++) { + if ((rs_table[i].port == req->port) && + (rs_table[i].iomem_base == req->iomem_base)) + break; + } + if (i == NR_PORTS) { + for (i = 0; i < NR_PORTS; i++) + if ((rs_table[i].type == PORT_UNKNOWN) && + (rs_table[i].count == 0)) + break; + } + if (i == NR_PORTS) { + restore_flags(flags); + return -1; + } + state = &rs_table[i]; + if (rs_table[i].count) { + restore_flags(flags); + printk("Couldn't configure serial #%d (port=%d,irq=%d): " + "device already open\n", i, req->port, req->irq); + return -1; + } + state->irq = req->irq; + state->port = req->port; + state->flags = req->flags; + state->io_type = req->io_type; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + state->iomem_base = req->iomem_base; + state->iomem_reg_shift = req->iomem_reg_shift; +#endif + if (req->baud_base) + state->baud_base = req->baud_base; + + autoconfig(state); + if (state->type == PORT_UNKNOWN) { + restore_flags(flags); + printk("register_serial(): autoconfig failed\n"); + return -1; + } + restore_flags(flags); + + if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state)) + state->irq = detect_uart_irq(state); + + printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n", + state->line + SERIAL_DEV_OFFSET, + state->iomem_base ? "iomem" : "port", + state->iomem_base ? (unsigned long)state->iomem_base : + (unsigned long)state->port, + state->irq, uart_config[state->type].name); + return state->line + SERIAL_DEV_OFFSET; +} + +void unregister_serial(int line) +{ + unsigned long flags; + struct serial_state *state = &rs_table[line]; + + save_flags(flags); + cli(); + if (state->info && state->info->tty) + tty_hangup(state->info->tty); + state->type = PORT_UNKNOWN; + printk(KERN_INFO "tty%02d unloaded\n", state->line); + restore_flags(flags); +} + +#ifdef MODULE +int init_module(void) +{ + return rs_init(); +} + +void cleanup_module(void) +{ + unsigned long flags; + int e1, e2; + int i; + struct async_struct *info; + + /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ + save_flags(flags); + cli(); + timer_active &= ~(1 << RS_TIMER); + timer_table[RS_TIMER].fn = NULL; + timer_table[RS_TIMER].expires = 0; + remove_bh(SERIAL_BH); + if ((e1 = tty_unregister_driver(&serial_driver))) + printk("SERIAL: failed to unregister serial driver (%d)\n", + e1); + if ((e2 = tty_unregister_driver(&callout_driver))) + printk("SERIAL: failed to unregister callout driver (%d)\n", + e2); + restore_flags(flags); + + for (i = 0; i < NR_PORTS; i++) { + if ((info = rs_table[i].info)) { + rs_table[i].info = NULL; + kfree_s(info, sizeof(struct async_struct)); + } + if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) + release_region(rs_table[i].port, 8); +#if defined(ENABLE_SERIAL_PCI) && defined (CONFIG_SERIAL_PCI_MEMMAPPED) + if (rs_table[i].iomem_base) + iounmap(rs_table[i].iomem_base); +#endif + } +#ifdef ENABLE_SERIAL_PCI + for (i=0; i < serial_pci_board_idx; i++) { + struct pci_board_inst *brd = &serial_pci_board[i]; + + if (brd->board->init_fn) + (brd->board->init_fn)(brd->dev, brd->board, 0); + } +#endif + if (tmp_buf) { + free_page((unsigned long) tmp_buf); + tmp_buf = NULL; + } +} +#endif /* MODULE */ + + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_SERIAL_CONSOLE + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +static struct async_struct async_sercons; + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct async_struct *info) +{ + unsigned int tmout = 1000000; + + while (--tmout && + ((serial_in(info, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)); +} + + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + static struct async_struct *info = &async_sercons; + int ier; + unsigned i; + + /* + * First save the IER then disable the interrupts + */ + ier = serial_in(info, UART_IER); + serial_out(info, UART_IER, 0x00); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + wait_for_xmitr(info); + + /* + * Send the character out. + * If a LF, also do CR... + */ + serial_out(info, UART_TX, *s); + if (*s == 10) { + wait_for_xmitr(info); + serial_out(info, UART_TX, 13); + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + wait_for_xmitr(info); + serial_out(info, UART_IER, ier); +} + +/* + * Receive character from the serial port + */ +static int serial_console_wait_key(struct console *co) +{ + static struct async_struct *info; + int ier, c; + + info = &async_sercons; + + /* + * First save the IER then disable the interrupts so + * that the real driver for the port does not get the + * character. + */ + ier = serial_in(info, UART_IER); + serial_out(info, UART_IER, 0x00); + + while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0); + c = serial_in(info, UART_RX); + + /* + * Restore the interrupts + */ + serial_out(info, UART_IER, ier); + + return c; +} + +static kdev_t serial_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init serial_console_setup(struct console *co, char *options) +{ + static struct async_struct *info; + struct serial_state *state; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; +#if defined(CONFIG_KDB) + extern int kdb_port; +#endif + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* + * Divisor, bytesize and parity + */ + state = rs_table + co->index; + info = &async_sercons; + info->magic = SERIAL_MAGIC; + info->state = state; + info->port = state->port; + info->flags = state->flags; +#ifdef CONFIG_HUB6 + info->hub6 = state->hub6; +#endif + info->io_type = state->io_type; +#ifdef CONFIG_SERIAL_PCI_MEMMAPPED + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; +#endif + quot = state->baud_base / baud; + cval = cflag & (CSIZE | CSTOPB); +#if defined(__powerpc__) || defined(__alpha__) + cval >>= 8; +#else /* !__powerpc__ && !__alpha__ */ + cval >>= 4; +#endif /* !__powerpc__ && !__alpha__ */ + if (cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; + + /* + * Disable UART interrupts, set DTR and RTS high + * and set speed. + */ + serial_out(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + serial_out(info, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_out(info, UART_DLM, quot >> 8); /* MS of divisor */ + serial_out(info, UART_LCR, cval); /* reset DLAB */ + serial_out(info, UART_IER, 0); + serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + + /* + * If we read 0xff from the LSR, there is no UART here. + */ + if (serial_in(info, UART_LSR) == 0xff) + return -1; + +#if defined(CONFIG_KDB) + /* + * Remember I/O port for kdb + */ + if (kdb_port == 0 ) + kdb_port = ser->port; +#endif /* CONFIG_KDB */ + + return 0; +} + +static struct console sercons = { + "ttyS", + serial_console_write, + NULL, + serial_console_device, + serial_console_wait_key, + NULL, + serial_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ +void __init serial_console_init(void) +{ + register_console(&sercons); +} +#endif + +/* + Local variables: + compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -DCPU=686 -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" + End: +*/ diff -urN 2.3.29pre1/drivers/char/sysrq.c 2.3.29pre1-ikd/drivers/char/sysrq.c --- 2.3.29pre1/drivers/char/sysrq.c Sun Nov 7 17:33:36 1999 +++ 2.3.29pre1-ikd/drivers/char/sysrq.c Mon Nov 22 17:05:14 1999 @@ -6,6 +6,8 @@ * * (c) 1997 Martin Mares * based on ideas by Pavel Machek + * Add dumploGs. Keith Owens 12/04/1998. + * Add Oops, changed Off to oFf. Keith Owens 26/04/1998. */ #include @@ -27,7 +29,12 @@ extern void wakeup_bdflush(int); extern void reset_vc(unsigned int); extern int console_loglevel; +extern void syslog_to_console(void); extern struct vfsmount *vfsmntlist; +#ifdef CONFIG_TRACE +#include +extern void ktrace_to_console(void); +#endif /* Machine specific power off function */ void (*sysrq_power_off)(void) = NULL; @@ -81,7 +88,7 @@ printk("Resetting\n"); machine_restart(NULL); break; - case 'o': /* O -- power off */ + case 'f': /* O -- power off */ if (sysrq_power_off) { printk("Power off\n"); sysrq_power_off(); @@ -129,6 +136,27 @@ send_sig_all(SIGKILL, 1); orig_log_level = 8; break; + case 'g': /* G -- dump all logs */ +#ifdef CONFIG_TRACE + SUSPEND_MCOUNT_TRACE; /* no point in tracing this section */ +#endif + printk("Dump All Logs\n"); + printk(KERN_INFO "DAL: syslog start\n"); + syslog_to_console(); + printk(KERN_INFO "DAL: syslog end\n"); + /* add any other log dumps here */ +#ifdef CONFIG_TRACE + printk(KERN_INFO "DAL: ktrace start\n"); + ktrace_to_console(); + printk(KERN_INFO "DAL: ktrace end\n"); + RESUME_MCOUNT_TRACE; +#endif + printk("\n"); + break; + case 'o': /* O -- oops */ + printk("Forcing Oops\n"); + *(char *)NULL = '\0'; + break; default: /* Unknown: help */ if (kbd) printk("unRaw "); @@ -138,8 +166,8 @@ #endif printk("Boot "); if (sysrq_power_off) - printk("Off "); - printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n"); + printk("oFf "); + printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL dumploGs Oops\n"); /* Don't use 'A' as it's handled specially on the Sparc */ } diff -urN 2.3.29pre1/drivers/char/sysrq.c.orig 2.3.29pre1-ikd/drivers/char/sysrq.c.orig --- 2.3.29pre1/drivers/char/sysrq.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/drivers/char/sysrq.c.orig Sun Nov 7 17:33:36 1999 @@ -0,0 +1,252 @@ +/* -*- linux-c -*- + * + * $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $ + * + * Linux Magic System Request Key Hacks + * + * (c) 1997 Martin Mares + * based on ideas by Pavel Machek + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern void wakeup_bdflush(int); +extern void reset_vc(unsigned int); +extern int console_loglevel; +extern struct vfsmount *vfsmntlist; + +/* Machine specific power off function */ +void (*sysrq_power_off)(void) = NULL; + +/* Send a signal to all user processes */ + +static void send_sig_all(int sig, int even_init) +{ + struct task_struct *p; + + for_each_task(p) { + if (p->mm) { /* Not swapper nor kernel thread */ + if (p->pid == 1 && even_init) /* Ugly hack to kill init */ + p->pid = 0x8000; + force_sig(sig, p); + } + } +} + +/* + * This function is called by the keyboard handler when SysRq is pressed + * and any other keycode arrives. + */ + +void handle_sysrq(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) +{ + int orig_log_level = console_loglevel; + + if (!key) + return; + + console_loglevel = 7; + printk(KERN_INFO "SysRq: "); + switch (key) { + case 'r': /* R -- Reset raw mode */ + if (kbd) { + kbd->kbdmode = VC_XLATE; + printk("Keyboard mode set to XLATE\n"); + } + break; +#ifdef CONFIG_VT + case 'k': /* K -- SAK */ + printk("SAK\n"); + if (tty) + do_SAK(tty); + reset_vc(fg_console); + break; +#endif + case 'b': /* B -- boot immediately */ + printk("Resetting\n"); + machine_restart(NULL); + break; + case 'o': /* O -- power off */ + if (sysrq_power_off) { + printk("Power off\n"); + sysrq_power_off(); + } + break; + case 's': /* S -- emergency sync */ + printk("Emergency Sync\n"); + emergency_sync_scheduled = EMERG_SYNC; + wakeup_bdflush(0); + break; + case 'u': /* U -- emergency remount R/O */ + printk("Emergency Remount R/O\n"); + emergency_sync_scheduled = EMERG_REMOUNT; + wakeup_bdflush(0); + break; + case 'p': /* P -- show PC */ + printk("Show Regs\n"); + if (pt_regs) + show_regs(pt_regs); + break; + case 't': /* T -- show task info */ + printk("Show State\n"); + show_state(); + break; + case 'm': /* M -- show memory info */ + printk("Show Memory\n"); + show_mem(); + break; + case '0' ... '9': /* 0-9 -- set console logging level */ + orig_log_level = key - '0'; + printk("Log level set to %d\n", orig_log_level); + break; + case 'e': /* E -- terminate all user processes */ + printk("Terminate All Tasks\n"); + send_sig_all(SIGTERM, 0); + orig_log_level = 8; /* We probably have killed syslogd */ + break; + case 'i': /* I -- kill all user processes */ + printk("Kill All Tasks\n"); + send_sig_all(SIGKILL, 0); + orig_log_level = 8; + break; + case 'l': /* L -- kill all processes including init */ + printk("Kill ALL Tasks (even init)\n"); + send_sig_all(SIGKILL, 1); + orig_log_level = 8; + break; + default: /* Unknown: help */ + if (kbd) + printk("unRaw "); +#ifdef CONFIG_VT + if (tty) + printk("saK "); +#endif + printk("Boot "); + if (sysrq_power_off) + printk("Off "); + printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n"); + /* Don't use 'A' as it's handled specially on the Sparc */ + } + + console_loglevel = orig_log_level; +} + +/* Aux routines for the syncer */ + +static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard drive */ +{ + unsigned int major = MAJOR(dev); + + switch (major) { + case IDE0_MAJOR: + case IDE1_MAJOR: + case IDE2_MAJOR: + case IDE3_MAJOR: + case SCSI_DISK0_MAJOR: + case SCSI_DISK1_MAJOR: + case SCSI_DISK2_MAJOR: + case SCSI_DISK3_MAJOR: + case SCSI_DISK4_MAJOR: + case SCSI_DISK5_MAJOR: + case SCSI_DISK6_MAJOR: + case SCSI_DISK7_MAJOR: + return 1; + default: + return 0; + } +} + +static void go_sync(kdev_t dev, int remount_flag) +{ + printk(KERN_INFO "%sing device %s ... ", + remount_flag ? "Remount" : "Sync", + kdevname(dev)); + + if (remount_flag) { /* Remount R/O */ + struct super_block *sb = get_super(dev); + struct vfsmount *vfsmnt; + int ret, flags; + struct list_head *p; + + if (!sb) { + printk("Superblock not found\n"); + return; + } + if (sb->s_flags & MS_RDONLY) { + printk("R/O\n"); + return; + } + + file_list_lock(); + for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { + struct file *file = list_entry(p, struct file, f_list); + if (file->f_dentry && file_count(file) + && S_ISREG(file->f_dentry->d_inode->i_mode)) + file->f_mode &= ~2; + } + file_list_unlock(); + DQUOT_OFF(dev); + fsync_dev(dev); + flags = MS_RDONLY; + if (sb->s_op && sb->s_op->remount_fs) { + ret = sb->s_op->remount_fs(sb, &flags, NULL); + if (ret) + printk("error %d\n", ret); + else { + sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); + if ((vfsmnt = lookup_vfsmnt(sb->s_dev))) + vfsmnt->mnt_flags = sb->s_flags; + printk("OK\n"); + } + } else + printk("nothing to do\n"); + } else { + fsync_dev(dev); /* Sync only */ + printk("OK\n"); + } +} + +/* + * Emergency Sync or Unmount. We cannot do it directly, so we set a special + * flag and wake up the bdflush kernel thread which immediately calls this function. + * We process all mounted hard drives first to recover from crashed experimental + * block devices and malfunctional network filesystems. + */ + +int emergency_sync_scheduled; + +void do_emergency_sync(void) +{ + struct vfsmount *mnt; + int remount_flag; + + lock_kernel(); + remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT); + emergency_sync_scheduled = 0; + + for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next) + if (is_local_disk(mnt->mnt_dev)) + go_sync(mnt->mnt_dev, remount_flag); + + for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next) + if (!is_local_disk(mnt->mnt_dev) && MAJOR(mnt->mnt_dev)) + go_sync(mnt->mnt_dev, remount_flag); + + unlock_kernel(); + printk(KERN_INFO "Done.\n"); +} diff -urN 2.3.29pre1/drivers/char/sysrq.c.rej 2.3.29pre1-ikd/drivers/char/sysrq.c.rej --- 2.3.29pre1/drivers/char/sysrq.c.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/drivers/char/sysrq.c.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,38 @@ +*************** +*** 79,85 **** + machine_restart(NULL); + break; + #ifdef CONFIG_APM +- case 'o': /* O -- power off */ + printk("Power off\n"); + apm_power_off(); + break; +--- 86,92 ---- + machine_restart(NULL); + break; + #ifdef CONFIG_APM ++ case 'f': /* F -- power off */ + printk("Power off\n"); + apm_power_off(); + break; +*************** +*** 142,150 **** + #endif + printk("Boot " + #ifdef CONFIG_APM +- "Off " + #endif +- "Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n"); + /* Don't use 'A' as it's handled specially on the Sparc */ + } + +--- 170,178 ---- + #endif + printk("Boot " + #ifdef CONFIG_APM ++ "oFf " + #endif ++ "Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL dumploGs Oops\n"); + /* Don't use 'A' as it's handled specially on the Sparc */ + } + diff -urN 2.3.29pre1/drivers/char/sysrq.c.~1~ 2.3.29pre1-ikd/drivers/char/sysrq.c.~1~ --- 2.3.29pre1/drivers/char/sysrq.c.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/drivers/char/sysrq.c.~1~ Mon Nov 22 16:56:24 1999 @@ -0,0 +1,280 @@ +/* -*- linux-c -*- + * + * $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $ + * + * Linux Magic System Request Key Hacks + * + * (c) 1997 Martin Mares + * based on ideas by Pavel Machek + * Add dumploGs. Keith Owens 12/04/1998. + * Add Oops, changed Off to oFf. Keith Owens 26/04/1998. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern void wakeup_bdflush(int); +extern void reset_vc(unsigned int); +extern int console_loglevel; +extern void syslog_to_console(void); +extern struct vfsmount *vfsmntlist; +#ifdef CONFIG_TRACE +#include +extern void ktrace_to_console(void); +#endif + +/* Machine specific power off function */ +void (*sysrq_power_off)(void) = NULL; + +/* Send a signal to all user processes */ + +static void send_sig_all(int sig, int even_init) +{ + struct task_struct *p; + + for_each_task(p) { + if (p->mm) { /* Not swapper nor kernel thread */ + if (p->pid == 1 && even_init) /* Ugly hack to kill init */ + p->pid = 0x8000; + force_sig(sig, p); + } + } +} + +/* + * This function is called by the keyboard handler when SysRq is pressed + * and any other keycode arrives. + */ + +void handle_sysrq(int key, struct pt_regs *pt_regs, + struct kbd_struct *kbd, struct tty_struct *tty) +{ + int orig_log_level = console_loglevel; + + if (!key) + return; + + console_loglevel = 7; + printk(KERN_INFO "SysRq: "); + switch (key) { + case 'r': /* R -- Reset raw mode */ + if (kbd) { + kbd->kbdmode = VC_XLATE; + printk("Keyboard mode set to XLATE\n"); + } + break; +#ifdef CONFIG_VT + case 'k': /* K -- SAK */ + printk("SAK\n"); + if (tty) + do_SAK(tty); + reset_vc(fg_console); + break; +#endif + case 'b': /* B -- boot immediately */ + printk("Resetting\n"); + machine_restart(NULL); + break; + case 'o': /* O -- power off */ + if (sysrq_power_off) { + printk("Power off\n"); + sysrq_power_off(); + } + break; + case 's': /* S -- emergency sync */ + printk("Emergency Sync\n"); + emergency_sync_scheduled = EMERG_SYNC; + wakeup_bdflush(0); + break; + case 'u': /* U -- emergency remount R/O */ + printk("Emergency Remount R/O\n"); + emergency_sync_scheduled = EMERG_REMOUNT; + wakeup_bdflush(0); + break; + case 'p': /* P -- show PC */ + printk("Show Regs\n"); + if (pt_regs) + show_regs(pt_regs); + break; + case 't': /* T -- show task info */ + printk("Show State\n"); + show_state(); + break; + case 'm': /* M -- show memory info */ + printk("Show Memory\n"); + show_mem(); + break; + case '0' ... '9': /* 0-9 -- set console logging level */ + orig_log_level = key - '0'; + printk("Log level set to %d\n", orig_log_level); + break; + case 'e': /* E -- terminate all user processes */ + printk("Terminate All Tasks\n"); + send_sig_all(SIGTERM, 0); + orig_log_level = 8; /* We probably have killed syslogd */ + break; + case 'i': /* I -- kill all user processes */ + printk("Kill All Tasks\n"); + send_sig_all(SIGKILL, 0); + orig_log_level = 8; + break; + case 'l': /* L -- kill all processes including init */ + printk("Kill ALL Tasks (even init)\n"); + send_sig_all(SIGKILL, 1); + orig_log_level = 8; + break; + case 'g': /* G -- dump all logs */ +#ifdef CONFIG_TRACE + SUSPEND_MCOUNT_TRACE; /* no point in tracing this section */ +#endif + printk("Dump All Logs\n"); + printk(KERN_INFO "DAL: syslog start\n"); + syslog_to_console(); + printk(KERN_INFO "DAL: syslog end\n"); + /* add any other log dumps here */ +#ifdef CONFIG_TRACE + printk(KERN_INFO "DAL: ktrace start\n"); + ktrace_to_console(); + printk(KERN_INFO "DAL: ktrace end\n"); + RESUME_MCOUNT_TRACE; +#endif + printk("\n"); + break; + case 'o': /* O -- oops */ + printk("Forcing Oops\n"); + *(char *)NULL = '\0'; + break; + default: /* Unknown: help */ + if (kbd) + printk("unRaw "); +#ifdef CONFIG_VT + if (tty) + printk("saK "); +#endif + printk("Boot "); + if (sysrq_power_off) + printk("Off "); + printk("Sync Unmount showPc showTasks showMem loglevel0-8 tErm kIll killalL\n"); + /* Don't use 'A' as it's handled specially on the Sparc */ + } + + console_loglevel = orig_log_level; +} + +/* Aux routines for the syncer */ + +static int is_local_disk(kdev_t dev) /* Guess if the device is a local hard drive */ +{ + unsigned int major = MAJOR(dev); + + switch (major) { + case IDE0_MAJOR: + case IDE1_MAJOR: + case IDE2_MAJOR: + case IDE3_MAJOR: + case SCSI_DISK0_MAJOR: + case SCSI_DISK1_MAJOR: + case SCSI_DISK2_MAJOR: + case SCSI_DISK3_MAJOR: + case SCSI_DISK4_MAJOR: + case SCSI_DISK5_MAJOR: + case SCSI_DISK6_MAJOR: + case SCSI_DISK7_MAJOR: + return 1; + default: + return 0; + } +} + +static void go_sync(kdev_t dev, int remount_flag) +{ + printk(KERN_INFO "%sing device %s ... ", + remount_flag ? "Remount" : "Sync", + kdevname(dev)); + + if (remount_flag) { /* Remount R/O */ + struct super_block *sb = get_super(dev); + struct vfsmount *vfsmnt; + int ret, flags; + struct list_head *p; + + if (!sb) { + printk("Superblock not found\n"); + return; + } + if (sb->s_flags & MS_RDONLY) { + printk("R/O\n"); + return; + } + + file_list_lock(); + for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { + struct file *file = list_entry(p, struct file, f_list); + if (file->f_dentry && file_count(file) + && S_ISREG(file->f_dentry->d_inode->i_mode)) + file->f_mode &= ~2; + } + file_list_unlock(); + DQUOT_OFF(dev); + fsync_dev(dev); + flags = MS_RDONLY; + if (sb->s_op && sb->s_op->remount_fs) { + ret = sb->s_op->remount_fs(sb, &flags, NULL); + if (ret) + printk("error %d\n", ret); + else { + sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); + if ((vfsmnt = lookup_vfsmnt(sb->s_dev))) + vfsmnt->mnt_flags = sb->s_flags; + printk("OK\n"); + } + } else + printk("nothing to do\n"); + } else { + fsync_dev(dev); /* Sync only */ + printk("OK\n"); + } +} + +/* + * Emergency Sync or Unmount. We cannot do it directly, so we set a special + * flag and wake up the bdflush kernel thread which immediately calls this function. + * We process all mounted hard drives first to recover from crashed experimental + * block devices and malfunctional network filesystems. + */ + +int emergency_sync_scheduled; + +void do_emergency_sync(void) +{ + struct vfsmount *mnt; + int remount_flag; + + lock_kernel(); + remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT); + emergency_sync_scheduled = 0; + + for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next) + if (is_local_disk(mnt->mnt_dev)) + go_sync(mnt->mnt_dev, remount_flag); + + for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next) + if (!is_local_disk(mnt->mnt_dev) && MAJOR(mnt->mnt_dev)) + go_sync(mnt->mnt_dev, remount_flag); + + unlock_kernel(); + printk(KERN_INFO "Done.\n"); +} diff -urN 2.3.29pre1/fs/proc/array.c 2.3.29pre1-ikd/fs/proc/array.c --- 2.3.29pre1/fs/proc/array.c Sun Nov 21 03:20:24 1999 +++ 2.3.29pre1-ikd/fs/proc/array.c Mon Nov 22 17:12:43 1999 @@ -262,7 +262,6 @@ cap_t(p->cap_effective)); } - /* task is locked, so we are safe here */ int proc_pid_status(struct task_struct *task, char * buffer) diff -urN 2.3.29pre1/fs/proc/array.c.orig 2.3.29pre1-ikd/fs/proc/array.c.orig --- 2.3.29pre1/fs/proc/array.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/fs/proc/array.c.orig Sun Nov 21 03:20:24 1999 @@ -0,0 +1,655 @@ +/* + * linux/fs/proc/array.c + * + * Copyright (C) 1992 by Linus Torvalds + * based on ideas by Darren Senn + * + * Fixes: + * Michael. K. Johnson: stat,statm extensions. + * + * + * Pauline Middelink : Made cmdline,envline only break at '\0's, to + * make sure SET_PROCTITLE works. Also removed + * bad '!' which forced address recalculation for + * EVERY character on the current page. + * + * + * Danny ter Haar : added cpuinfo + * + * + * Alessandro Rubini : profile extension. + * + * + * Jeff Tranter : added BogoMips field to cpuinfo + * + * + * Bruno Haible : remove 4K limit for the maps file + * + * + * Yves Arrouye : remove removal of trailing spaces in get_array. + * + * + * Jerome Forissier : added per-CPU time information to /proc/stat + * and /proc//cpu extension + * + * - Incorporation and non-SMP safe operation + * of forissier patch in 2.1.78 by + * Hans Marcus + * + * aeb@cwi.nl : /proc/partitions + * + * + * Alan Cox : security fixes. + * + * + * Al Viro : safe handling of mm_struct + * + * Gerhard Wichert : added BIGMEM support + * Siemens AG + * + * Al Viro & Jeff Garzik : moved most of the thing into base.c and + * : proc_misc.c. The rest may eventually go into + * : base.c too. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Gcc optimizes away "strlen(x)" for constant x */ +#define ADDBUF(buffer, string) \ +do { memcpy(buffer, string, strlen(string)); \ + buffer += strlen(string); } while (0) + +static inline char * task_name(struct task_struct *p, char * buf) +{ + int i; + char * name; + + ADDBUF(buf, "Name:\t"); + name = p->comm; + i = sizeof(p->comm); + do { + unsigned char c = *name; + name++; + i--; + *buf = c; + if (!c) + break; + if (c == '\\') { + buf[1] = c; + buf += 2; + continue; + } + if (c == '\n') { + buf[0] = '\\'; + buf[1] = 'n'; + buf += 2; + continue; + } + buf++; + } while (i); + *buf = '\n'; + return buf+1; +} + +/* + * The task state array is a strange "bitmap" of + * reasons to sleep. Thus "running" is zero, and + * you can test for combinations of others with + * simple bit tests. + */ +static const char *task_state_array[] = { + "R (running)", /* 0 */ + "S (sleeping)", /* 1 */ + "D (disk sleep)", /* 2 */ + "Z (zombie)", /* 4 */ + "T (stopped)", /* 8 */ + "W (paging)" /* 16 */ +}; + +static inline const char * get_task_state(struct task_struct *tsk) +{ + unsigned int state = tsk->state & (TASK_RUNNING | + TASK_INTERRUPTIBLE | + TASK_UNINTERRUPTIBLE | + TASK_ZOMBIE | + TASK_STOPPED | + TASK_SWAPPING); + const char **p = &task_state_array[0]; + + while (state) { + p++; + state >>= 1; + } + return *p; +} + +static inline char * task_state(struct task_struct *p, char *buffer) +{ + int g; + + buffer += sprintf(buffer, + "State:\t%s\n" + "Pid:\t%d\n" + "PPid:\t%d\n" + "Uid:\t%d\t%d\t%d\t%d\n" + "Gid:\t%d\t%d\t%d\t%d\n" + "FDSize:\t%d\n" + "Groups:\t", + get_task_state(p), + p->pid, p->p_pptr->pid, + p->uid, p->euid, p->suid, p->fsuid, + p->gid, p->egid, p->sgid, p->fsgid, + p->files ? p->files->max_fds : 0); + + for (g = 0; g < p->ngroups; g++) + buffer += sprintf(buffer, "%d ", p->groups[g]); + + buffer += sprintf(buffer, "\n"); + return buffer; +} + +static inline char * task_mem(struct mm_struct *mm, char *buffer) +{ + struct vm_area_struct * vma; + unsigned long data = 0, stack = 0; + unsigned long exec = 0, lib = 0; + + down(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long len = (vma->vm_end - vma->vm_start) >> 10; + if (!vma->vm_file) { + data += len; + if (vma->vm_flags & VM_GROWSDOWN) + stack += len; + continue; + } + if (vma->vm_flags & VM_WRITE) + continue; + if (vma->vm_flags & VM_EXEC) { + exec += len; + if (vma->vm_flags & VM_EXECUTABLE) + continue; + lib += len; + } + } + buffer += sprintf(buffer, + "VmSize:\t%8lu kB\n" + "VmLck:\t%8lu kB\n" + "VmRSS:\t%8lu kB\n" + "VmData:\t%8lu kB\n" + "VmStk:\t%8lu kB\n" + "VmExe:\t%8lu kB\n" + "VmLib:\t%8lu kB\n", + mm->total_vm << (PAGE_SHIFT-10), + mm->locked_vm << (PAGE_SHIFT-10), + mm->rss << (PAGE_SHIFT-10), + data - stack, stack, + exec - lib, lib); + up(&mm->mmap_sem); + return buffer; +} + +static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, + sigset_t *catch) +{ + struct k_sigaction *k; + int i; + + sigemptyset(ign); + sigemptyset(catch); + + if (p->sig) { + k = p->sig->action; + for (i = 1; i <= _NSIG; ++i, ++k) { + if (k->sa.sa_handler == SIG_IGN) + sigaddset(ign, i); + else if (k->sa.sa_handler != SIG_DFL) + sigaddset(catch, i); + } + } +} + +static inline char * task_sig(struct task_struct *p, char *buffer) +{ + sigset_t ign, catch; + + buffer += sprintf(buffer, "SigPnd:\t"); + buffer = render_sigset_t(&p->signal, buffer); + *buffer++ = '\n'; + buffer += sprintf(buffer, "SigBlk:\t"); + buffer = render_sigset_t(&p->blocked, buffer); + *buffer++ = '\n'; + + collect_sigign_sigcatch(p, &ign, &catch); + buffer += sprintf(buffer, "SigIgn:\t"); + buffer = render_sigset_t(&ign, buffer); + *buffer++ = '\n'; + buffer += sprintf(buffer, "SigCgt:\t"); /* Linux 2.0 uses "SigCgt" */ + buffer = render_sigset_t(&catch, buffer); + *buffer++ = '\n'; + + return buffer; +} + +extern inline char *task_cap(struct task_struct *p, char *buffer) +{ + return buffer + sprintf(buffer, "CapInh:\t%016x\n" + "CapPrm:\t%016x\n" + "CapEff:\t%016x\n", + cap_t(p->cap_inheritable), + cap_t(p->cap_permitted), + cap_t(p->cap_effective)); +} + + +/* task is locked, so we are safe here */ + +int proc_pid_status(struct task_struct *task, char * buffer) +{ + char * orig = buffer; + struct mm_struct *mm = task->mm; + + buffer = task_name(task, buffer); + buffer = task_state(task, buffer); + if (mm) + buffer = task_mem(mm, buffer); + buffer = task_sig(task, buffer); + buffer = task_cap(task, buffer); + return buffer - orig; +} + +/* task is locked, so we are safe here */ + +int proc_pid_stat(struct task_struct *task, char * buffer) +{ + struct mm_struct *mm = task->mm; + unsigned long vsize, eip, esp, wchan; + long priority, nice; + int tty_pgrp; + sigset_t sigign, sigcatch; + char state; + int res; + + state = *get_task_state(task); + vsize = eip = esp = 0; + if (mm) { + struct vm_area_struct *vma; + down(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + vsize += vma->vm_end - vma->vm_start; + vma = vma->vm_next; + } + eip = KSTK_EIP(task); + esp = KSTK_ESP(task); + up(&mm->mmap_sem); + } + + wchan = get_wchan(task); + + collect_sigign_sigcatch(task, &sigign, &sigcatch); + + if (task->tty) + tty_pgrp = task->tty->pgrp; + else + tty_pgrp = -1; + + /* scale priority and nice values from timeslices to -20..20 */ + /* to make it look like a "normal" Unix priority/nice value */ + priority = task->counter; + priority = 20 - (priority * 10 + DEF_PRIORITY / 2) / DEF_PRIORITY; + nice = task->priority; + nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY; + + res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ +%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ +%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n", + task->pid, + task->comm, + state, + task->p_pptr->pid, + task->pgrp, + task->session, + task->tty ? kdev_t_to_nr(task->tty->device) : 0, + tty_pgrp, + task->flags, + task->min_flt, + task->cmin_flt, + task->maj_flt, + task->cmaj_flt, + task->times.tms_utime, + task->times.tms_stime, + task->times.tms_cutime, + task->times.tms_cstime, + priority, + nice, + 0UL /* removed */, + task->it_real_value, + task->start_time, + vsize, + mm ? mm->rss : 0, /* you might want to shift this left 3 */ + task->rlim ? task->rlim[RLIMIT_RSS].rlim_cur : 0, + mm ? mm->start_code : 0, + mm ? mm->end_code : 0, + mm ? mm->start_stack : 0, + esp, + eip, + /* The signal information here is obsolete. + * It must be decimal for Linux 2.0 compatibility. + * Use /proc/#/status for real-time signals. + */ + task->signal .sig[0] & 0x7fffffffUL, + task->blocked.sig[0] & 0x7fffffffUL, + sigign .sig[0] & 0x7fffffffUL, + sigcatch .sig[0] & 0x7fffffffUL, + wchan, + task->nswap, + task->cnswap, + task->exit_signal, + task->processor); + return res; +} + +static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t page = *pte; + + address += PAGE_SIZE; + pte++; + if (pte_none(page)) + continue; + ++*total; + if (!pte_present(page)) + continue; + ++*pages; + if (pte_dirty(page)) + ++*dirty; + if (pte_pagenr(page) >= max_mapnr) + continue; + if (page_count(pte_page(page)) > 1) + ++*shared; + } while (address < end); +} + +static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pmd_t * pmd; + unsigned long end; + + if (pgd_none(*pgd)) + return; + if (pgd_bad(*pgd)) { + pgd_ERROR(*pgd); + pgd_clear(pgd); + return; + } + pmd = pmd_offset(pgd, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + statm_pte_range(pmd, address, end - address, pages, shared, dirty, total); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); +} + +static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end, + int * pages, int * shared, int * dirty, int * total) +{ + while (address < end) { + statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + pgd++; + } +} + +int proc_pid_statm(struct task_struct *task, char * buffer) +{ + struct mm_struct *mm = task->mm; + int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + + if (mm) { + struct vm_area_struct * vma; + down(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + pgd_t *pgd = pgd_offset(mm, vma->vm_start); + int pages = 0, shared = 0, dirty = 0, total = 0; + + statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total); + resident += pages; + share += shared; + dt += dirty; + size += total; + if (vma->vm_flags & VM_EXECUTABLE) + trs += pages; /* text */ + else if (vma->vm_flags & VM_GROWSDOWN) + drs += pages; /* stack */ + else if (vma->vm_end > 0x60000000) + lrs += pages; /* library */ + else + drs += pages; + vma = vma->vm_next; + } + up(&mm->mmap_sem); + } + return sprintf(buffer,"%d %d %d %d %d %d %d\n", + size, resident, share, trs, lrs, drs, dt); +} + +/* + * The way we support synthetic files > 4K + * - without storing their contents in some buffer and + * - without walking through the entire synthetic file until we reach the + * position of the requested data + * is to cleverly encode the current position in the file's f_pos field. + * There is no requirement that a read() call which returns `count' bytes + * of data increases f_pos by exactly `count'. + * + * This idea is Linus' one. Bruno implemented it. + */ + +/* + * For the /proc//maps file, we use fixed length records, each containing + * a single line. + */ +#define MAPS_LINE_LENGTH 4096 +#define MAPS_LINE_SHIFT 12 +/* + * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH + * + (index into the line) + */ +/* for systems with sizeof(void*) == 4: */ +#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %s %lu" +#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */ + +/* for systems with sizeof(void*) == 8: */ +#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %s %lu" +#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */ + +#define MAPS_LINE_MAX MAPS_LINE_MAX8 + + +ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct * map, * next; + char * destptr = buf, * buffer; + loff_t lineno; + ssize_t column, i; + int volatile_task; + long retval; + + /* + * We might sleep getting the page, so get it first. + */ + retval = -ENOMEM; + buffer = (char*)__get_free_page(GFP_KERNEL); + if (!buffer) + goto out; + + if (!mm || count == 0) + goto getlen_out; + + /* Check whether the mmaps could change if we sleep */ + volatile_task = (task != current || atomic_read(&mm->mm_users) > 1); + + /* decode f_pos */ + lineno = *ppos >> MAPS_LINE_SHIFT; + column = *ppos & (MAPS_LINE_LENGTH-1); + + /* quickly go to line lineno */ + down(&mm->mmap_sem); + for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++) + continue; + + for ( ; map ; map = next ) { + /* produce the next line */ + char *line; + char str[5], *cp = str; + int flags; + kdev_t dev; + unsigned long ino; + int maxlen = (sizeof(void*) == 4) ? + MAPS_LINE_MAX4 : MAPS_LINE_MAX8; + int len; + + /* + * Get the next vma now (but it won't be used if we sleep). + */ + next = map->vm_next; + flags = map->vm_flags; + + *cp++ = flags & VM_READ ? 'r' : '-'; + *cp++ = flags & VM_WRITE ? 'w' : '-'; + *cp++ = flags & VM_EXEC ? 'x' : '-'; + *cp++ = flags & VM_MAYSHARE ? 's' : 'p'; + *cp++ = 0; + + dev = 0; + ino = 0; + if (map->vm_file != NULL) { + dev = map->vm_file->f_dentry->d_inode->i_dev; + ino = map->vm_file->f_dentry->d_inode->i_ino; + line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE); + buffer[PAGE_SIZE-1] = '\n'; + line -= maxlen; + if(line < buffer) + line = buffer; + } else + line = buffer; + + len = sprintf(line, + sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8, + map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT, + kdevname(dev), ino); + + if(map->vm_file) { + for(i = len; i < maxlen; i++) + line[i] = ' '; + len = buffer + PAGE_SIZE - line; + } else + line[len++] = '\n'; + if (column >= len) { + column = 0; /* continue with next line at column 0 */ + lineno++; + continue; /* we haven't slept */ + } + + i = len-column; + if (i > count) + i = count; + up(&mm->mmap_sem); + copy_to_user(destptr, line+column, i); /* may have slept */ + down(&mm->mmap_sem); + destptr += i; + count -= i; + column += i; + if (column >= len) { + column = 0; /* next time: next line at column 0 */ + lineno++; + } + + /* done? */ + if (count == 0) + break; + + /* By writing to user space, we might have slept. + * Stop the loop, to avoid a race condition. + */ + if (volatile_task) + break; + } + up(&mm->mmap_sem); + + /* encode f_pos */ + *ppos = (lineno << MAPS_LINE_SHIFT) + column; + +getlen_out: + retval = destptr - buf; + free_page((unsigned long)buffer); +out: + return retval; +} + +#ifdef __SMP__ +int proc_pid_cpu(struct task_struct *task, char * buffer) +{ + int i, len; + + len = sprintf(buffer, + "cpu %lu %lu\n", + task->times.tms_utime, + task->times.tms_stime); + + for (i = 0 ; i < smp_num_cpus; i++) + len += sprintf(buffer + len, "cpu%d %lu %lu\n", + i, + task->per_cpu_utime[cpu_logical_map(i)], + task->per_cpu_stime[cpu_logical_map(i)]); + + return len; +} +#endif diff -urN 2.3.29pre1/fs/proc/array.c.rej 2.3.29pre1-ikd/fs/proc/array.c.rej --- 2.3.29pre1/fs/proc/array.c.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/fs/proc/array.c.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,16 @@ +*************** +*** 72,77 **** + #include + #include + #include + + #include + #include +--- 72,78 ---- + #include + #include + #include ++ #include + + #include + #include diff -urN 2.3.29pre1/fs/proc/array.c.~1~ 2.3.29pre1-ikd/fs/proc/array.c.~1~ --- 2.3.29pre1/fs/proc/array.c.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/fs/proc/array.c.~1~ Mon Nov 22 16:56:24 1999 @@ -0,0 +1,766 @@ +/* + * linux/fs/proc/array.c + * + * Copyright (C) 1992 by Linus Torvalds + * based on ideas by Darren Senn + * + * Fixes: + * Michael. K. Johnson: stat,statm extensions. + * + * + * Pauline Middelink : Made cmdline,envline only break at '\0's, to + * make sure SET_PROCTITLE works. Also removed + * bad '!' which forced address recalculation for + * EVERY character on the current page. + * + * + * Danny ter Haar : added cpuinfo + * + * + * Alessandro Rubini : profile extension. + * + * + * Jeff Tranter : added BogoMips field to cpuinfo + * + * + * Bruno Haible : remove 4K limit for the maps file + * + * + * Yves Arrouye : remove removal of trailing spaces in get_array. + * + * + * Jerome Forissier : added per-CPU time information to /proc/stat + * and /proc//cpu extension + * + * - Incorporation and non-SMP safe operation + * of forissier patch in 2.1.78 by + * Hans Marcus + * + * aeb@cwi.nl : /proc/partitions + * + * + * Alan Cox : security fixes. + * + * + * Al Viro : safe handling of mm_struct + * + * Gerhard Wichert : added BIGMEM support + * Siemens AG + * + * Al Viro & Jeff Garzik : moved most of the thing into base.c and + * : proc_misc.c. The rest may eventually go into + * : base.c too. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Gcc optimizes away "strlen(x)" for constant x */ +#define ADDBUF(buffer, string) \ +do { memcpy(buffer, string, strlen(string)); \ + buffer += strlen(string); } while (0) + +static inline char * task_name(struct task_struct *p, char * buf) +{ + int i; + char * name; + + ADDBUF(buf, "Name:\t"); + name = p->comm; + i = sizeof(p->comm); + do { + unsigned char c = *name; + name++; + i--; + *buf = c; + if (!c) + break; + if (c == '\\') { + buf[1] = c; + buf += 2; + continue; + } + if (c == '\n') { + buf[0] = '\\'; + buf[1] = 'n'; + buf += 2; + continue; + } + buf++; + } while (i); + *buf = '\n'; + return buf+1; +} + +/* + * The task state array is a strange "bitmap" of + * reasons to sleep. Thus "running" is zero, and + * you can test for combinations of others with + * simple bit tests. + */ +static const char *task_state_array[] = { + "R (running)", /* 0 */ + "S (sleeping)", /* 1 */ + "D (disk sleep)", /* 2 */ + "Z (zombie)", /* 4 */ + "T (stopped)", /* 8 */ + "W (paging)" /* 16 */ +}; + +static inline const char * get_task_state(struct task_struct *tsk) +{ + unsigned int state = tsk->state & (TASK_RUNNING | + TASK_INTERRUPTIBLE | + TASK_UNINTERRUPTIBLE | + TASK_ZOMBIE | + TASK_STOPPED | + TASK_SWAPPING); + const char **p = &task_state_array[0]; + + while (state) { + p++; + state >>= 1; + } + return *p; +} + +static inline char * task_state(struct task_struct *p, char *buffer) +{ + int g; + + buffer += sprintf(buffer, + "State:\t%s\n" + "Pid:\t%d\n" + "PPid:\t%d\n" + "Uid:\t%d\t%d\t%d\t%d\n" + "Gid:\t%d\t%d\t%d\t%d\n" + "FDSize:\t%d\n" + "Groups:\t", + get_task_state(p), + p->pid, p->p_pptr->pid, + p->uid, p->euid, p->suid, p->fsuid, + p->gid, p->egid, p->sgid, p->fsgid, + p->files ? p->files->max_fds : 0); + + for (g = 0; g < p->ngroups; g++) + buffer += sprintf(buffer, "%d ", p->groups[g]); + + buffer += sprintf(buffer, "\n"); + return buffer; +} + +static inline char * task_mem(struct mm_struct *mm, char *buffer) +{ + struct vm_area_struct * vma; + unsigned long data = 0, stack = 0; + unsigned long exec = 0, lib = 0; + + down(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long len = (vma->vm_end - vma->vm_start) >> 10; + if (!vma->vm_file) { + data += len; + if (vma->vm_flags & VM_GROWSDOWN) + stack += len; + continue; + } + if (vma->vm_flags & VM_WRITE) + continue; + if (vma->vm_flags & VM_EXEC) { + exec += len; + if (vma->vm_flags & VM_EXECUTABLE) + continue; + lib += len; + } + } + buffer += sprintf(buffer, + "VmSize:\t%8lu kB\n" + "VmLck:\t%8lu kB\n" + "VmRSS:\t%8lu kB\n" + "VmData:\t%8lu kB\n" + "VmStk:\t%8lu kB\n" + "VmExe:\t%8lu kB\n" + "VmLib:\t%8lu kB\n", + mm->total_vm << (PAGE_SHIFT-10), + mm->locked_vm << (PAGE_SHIFT-10), + mm->rss << (PAGE_SHIFT-10), + data - stack, stack, + exec - lib, lib); + up(&mm->mmap_sem); + return buffer; +} + +static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, + sigset_t *catch) +{ + struct k_sigaction *k; + int i; + + sigemptyset(ign); + sigemptyset(catch); + + if (p->sig) { + k = p->sig->action; + for (i = 1; i <= _NSIG; ++i, ++k) { + if (k->sa.sa_handler == SIG_IGN) + sigaddset(ign, i); + else if (k->sa.sa_handler != SIG_DFL) + sigaddset(catch, i); + } + } +} + +static inline char * task_sig(struct task_struct *p, char *buffer) +{ + sigset_t ign, catch; + + buffer += sprintf(buffer, "SigPnd:\t"); + buffer = render_sigset_t(&p->signal, buffer); + *buffer++ = '\n'; + buffer += sprintf(buffer, "SigBlk:\t"); + buffer = render_sigset_t(&p->blocked, buffer); + *buffer++ = '\n'; + + collect_sigign_sigcatch(p, &ign, &catch); + buffer += sprintf(buffer, "SigIgn:\t"); + buffer = render_sigset_t(&ign, buffer); + *buffer++ = '\n'; + buffer += sprintf(buffer, "SigCgt:\t"); /* Linux 2.0 uses "SigCgt" */ + buffer = render_sigset_t(&catch, buffer); + *buffer++ = '\n'; + + return buffer; +} + +extern inline char *task_cap(struct task_struct *p, char *buffer) +{ + return buffer + sprintf(buffer, "CapInh:\t%016x\n" + "CapPrm:\t%016x\n" + "CapEff:\t%016x\n", + cap_t(p->cap_inheritable), + cap_t(p->cap_permitted), + cap_t(p->cap_effective)); +} + +#ifdef CONFIG_TRACE + +/* + * This function accesses kernel tracer information. The returned data is + * binary: the sampling step and the actual contents of the trace + * ringbuffer. Use of the program 'ktrace' is recommended in order to + * get meaningful info out of these data. + */ +static ssize_t read_trace(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + loff_t p = *ppos, left; + unsigned long flags; + int i; + + SUSPEND_MCOUNT_TRACE; + LOCK_MCOUNT_TRACE(flags); + + /* Calibrate the tracer */ + for (i = 1; i <= TRACE_CALIBRATION_CALLS; ++i) + mcount_internal(-1); + + UNLOCK_MCOUNT_TRACE(flags); + + if (p >= sizeof(*trace_table)) + count = 0; + else if (count > sizeof(*trace_table) - p) + count = sizeof(*trace_table) - p; + + left = copy_to_user(buf, p + (char *)trace_table, count); + + RESUME_MCOUNT_TRACE; + + if (count && left == count) + return -EFAULT; + + *ppos += count - left; + return count - left; +} + +/* + * Writing to /proc/trace resets the counters. Doesnt make much sense + * as it's a ringbuffer, but we do it anyways, it might make sense for + * doing short term traces. + */ + +static ssize_t write_trace(struct file * file, const char * buf, size_t count, loff_t *ppos) +{ + unsigned long flags; + SUSPEND_MCOUNT_TRACE; + LOCK_MCOUNT_TRACE(flags); + memset(trace_table->entries, 0, sizeof(trace_table->entries)); + trace_table->curr_call = CONFIG_TRACE_SIZE-1; + UNLOCK_MCOUNT_TRACE(flags); + RESUME_MCOUNT_TRACE; + return count; +} + +static struct file_operations proc_trace_operations = { + NULL, /* lseek */ + read_trace, + write_trace, +}; + +struct inode_operations proc_trace_inode_operations = { + &proc_trace_operations, +}; + +/* + * Dump the kernel trace table in hex to all registered consoles. + * A method of getting the trace table when all else fails. + * This is a raw dump, the entire table is printed in hex, 80 hex digits + * to a line. Capture the output via a serial console and feed into + * ktrace with the "-d filename" option. + * Not recommended for a large trace table over a slow serial line. + */ +#define TRACE_LINE_WIDTH 80 +void ktrace_to_console(void) +{ + static const char hexchar[] = "0123456789abcdef"; + int i; + unsigned c; + char buf[TRACE_LINE_WIDTH+3], *p; + + SUSPEND_MCOUNT_TRACE; + /* Should LOCK_MCOUNT_TRACE here but that might stop output. + * Live with the risk of dumping garbage. Cannot calibrate + * without the lock, OTOH accurate timing figures are probably + * the least of our worries at this point. + */ + + for (i = 0, p = buf; i < sizeof(*trace_table); ++i) { + /* hex convert inline, 200,000+ calls to vsprintf is slow */ + c = *((unsigned char *)(trace_table)+i); + *p++ = hexchar[c>>4]; + *p++ = hexchar[c&0xf]; + if (p - buf >= TRACE_LINE_WIDTH) { + *p++ = '\n'; + *p++ = '\0'; + console_print(buf); + p = buf; + } + } + if (p != buf) { + *p++ = '\n'; + *p++ = '\0'; + console_print(buf); + } + + RESUME_MCOUNT_TRACE; +} +#endif /* CONFIG_TRACE */ + +/* task is locked, so we are safe here */ + +int proc_pid_status(struct task_struct *task, char * buffer) +{ + char * orig = buffer; + struct mm_struct *mm = task->mm; + + buffer = task_name(task, buffer); + buffer = task_state(task, buffer); + if (mm) + buffer = task_mem(mm, buffer); + buffer = task_sig(task, buffer); + buffer = task_cap(task, buffer); + return buffer - orig; +} + +/* task is locked, so we are safe here */ + +int proc_pid_stat(struct task_struct *task, char * buffer) +{ + struct mm_struct *mm = task->mm; + unsigned long vsize, eip, esp, wchan; + long priority, nice; + int tty_pgrp; + sigset_t sigign, sigcatch; + char state; + int res; + + state = *get_task_state(task); + vsize = eip = esp = 0; + if (mm) { + struct vm_area_struct *vma; + down(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + vsize += vma->vm_end - vma->vm_start; + vma = vma->vm_next; + } + eip = KSTK_EIP(task); + esp = KSTK_ESP(task); + up(&mm->mmap_sem); + } + + wchan = get_wchan(task); + + collect_sigign_sigcatch(task, &sigign, &sigcatch); + + if (task->tty) + tty_pgrp = task->tty->pgrp; + else + tty_pgrp = -1; + + /* scale priority and nice values from timeslices to -20..20 */ + /* to make it look like a "normal" Unix priority/nice value */ + priority = task->counter; + priority = 20 - (priority * 10 + DEF_PRIORITY / 2) / DEF_PRIORITY; + nice = task->priority; + nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY; + + res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ +%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ +%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n", + task->pid, + task->comm, + state, + task->p_pptr->pid, + task->pgrp, + task->session, + task->tty ? kdev_t_to_nr(task->tty->device) : 0, + tty_pgrp, + task->flags, + task->min_flt, + task->cmin_flt, + task->maj_flt, + task->cmaj_flt, + task->times.tms_utime, + task->times.tms_stime, + task->times.tms_cutime, + task->times.tms_cstime, + priority, + nice, + 0UL /* removed */, + task->it_real_value, + task->start_time, + vsize, + mm ? mm->rss : 0, /* you might want to shift this left 3 */ + task->rlim ? task->rlim[RLIMIT_RSS].rlim_cur : 0, + mm ? mm->start_code : 0, + mm ? mm->end_code : 0, + mm ? mm->start_stack : 0, + esp, + eip, + /* The signal information here is obsolete. + * It must be decimal for Linux 2.0 compatibility. + * Use /proc/#/status for real-time signals. + */ + task->signal .sig[0] & 0x7fffffffUL, + task->blocked.sig[0] & 0x7fffffffUL, + sigign .sig[0] & 0x7fffffffUL, + sigcatch .sig[0] & 0x7fffffffUL, + wchan, + task->nswap, + task->cnswap, + task->exit_signal, + task->processor); + return res; +} + +static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t page = *pte; + + address += PAGE_SIZE; + pte++; + if (pte_none(page)) + continue; + ++*total; + if (!pte_present(page)) + continue; + ++*pages; + if (pte_dirty(page)) + ++*dirty; + if (pte_pagenr(page) >= max_mapnr) + continue; + if (page_count(pte_page(page)) > 1) + ++*shared; + } while (address < end); +} + +static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pmd_t * pmd; + unsigned long end; + + if (pgd_none(*pgd)) + return; + if (pgd_bad(*pgd)) { + pgd_ERROR(*pgd); + pgd_clear(pgd); + return; + } + pmd = pmd_offset(pgd, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + statm_pte_range(pmd, address, end - address, pages, shared, dirty, total); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); +} + +static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end, + int * pages, int * shared, int * dirty, int * total) +{ + while (address < end) { + statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + pgd++; + } +} + +int proc_pid_statm(struct task_struct *task, char * buffer) +{ + struct mm_struct *mm = task->mm; + int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + + if (mm) { + struct vm_area_struct * vma; + down(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + pgd_t *pgd = pgd_offset(mm, vma->vm_start); + int pages = 0, shared = 0, dirty = 0, total = 0; + + statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total); + resident += pages; + share += shared; + dt += dirty; + size += total; + if (vma->vm_flags & VM_EXECUTABLE) + trs += pages; /* text */ + else if (vma->vm_flags & VM_GROWSDOWN) + drs += pages; /* stack */ + else if (vma->vm_end > 0x60000000) + lrs += pages; /* library */ + else + drs += pages; + vma = vma->vm_next; + } + up(&mm->mmap_sem); + } + return sprintf(buffer,"%d %d %d %d %d %d %d\n", + size, resident, share, trs, lrs, drs, dt); +} + +/* + * The way we support synthetic files > 4K + * - without storing their contents in some buffer and + * - without walking through the entire synthetic file until we reach the + * position of the requested data + * is to cleverly encode the current position in the file's f_pos field. + * There is no requirement that a read() call which returns `count' bytes + * of data increases f_pos by exactly `count'. + * + * This idea is Linus' one. Bruno implemented it. + */ + +/* + * For the /proc//maps file, we use fixed length records, each containing + * a single line. + */ +#define MAPS_LINE_LENGTH 4096 +#define MAPS_LINE_SHIFT 12 +/* + * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH + * + (index into the line) + */ +/* for systems with sizeof(void*) == 4: */ +#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %s %lu" +#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */ + +/* for systems with sizeof(void*) == 8: */ +#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %s %lu" +#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */ + +#define MAPS_LINE_MAX MAPS_LINE_MAX8 + + +ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct * map, * next; + char * destptr = buf, * buffer; + loff_t lineno; + ssize_t column, i; + int volatile_task; + long retval; + + /* + * We might sleep getting the page, so get it first. + */ + retval = -ENOMEM; + buffer = (char*)__get_free_page(GFP_KERNEL); + if (!buffer) + goto out; + + if (!mm || count == 0) + goto getlen_out; + + /* Check whether the mmaps could change if we sleep */ + volatile_task = (task != current || atomic_read(&mm->mm_users) > 1); + + /* decode f_pos */ + lineno = *ppos >> MAPS_LINE_SHIFT; + column = *ppos & (MAPS_LINE_LENGTH-1); + + /* quickly go to line lineno */ + down(&mm->mmap_sem); + for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++) + continue; + + for ( ; map ; map = next ) { + /* produce the next line */ + char *line; + char str[5], *cp = str; + int flags; + kdev_t dev; + unsigned long ino; + int maxlen = (sizeof(void*) == 4) ? + MAPS_LINE_MAX4 : MAPS_LINE_MAX8; + int len; + + /* + * Get the next vma now (but it won't be used if we sleep). + */ + next = map->vm_next; + flags = map->vm_flags; + + *cp++ = flags & VM_READ ? 'r' : '-'; + *cp++ = flags & VM_WRITE ? 'w' : '-'; + *cp++ = flags & VM_EXEC ? 'x' : '-'; + *cp++ = flags & VM_MAYSHARE ? 's' : 'p'; + *cp++ = 0; + + dev = 0; + ino = 0; + if (map->vm_file != NULL) { + dev = map->vm_file->f_dentry->d_inode->i_dev; + ino = map->vm_file->f_dentry->d_inode->i_ino; + line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE); + buffer[PAGE_SIZE-1] = '\n'; + line -= maxlen; + if(line < buffer) + line = buffer; + } else + line = buffer; + + len = sprintf(line, + sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8, + map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT, + kdevname(dev), ino); + + if(map->vm_file) { + for(i = len; i < maxlen; i++) + line[i] = ' '; + len = buffer + PAGE_SIZE - line; + } else + line[len++] = '\n'; + if (column >= len) { + column = 0; /* continue with next line at column 0 */ + lineno++; + continue; /* we haven't slept */ + } + + i = len-column; + if (i > count) + i = count; + up(&mm->mmap_sem); + copy_to_user(destptr, line+column, i); /* may have slept */ + down(&mm->mmap_sem); + destptr += i; + count -= i; + column += i; + if (column >= len) { + column = 0; /* next time: next line at column 0 */ + lineno++; + } + + /* done? */ + if (count == 0) + break; + + /* By writing to user space, we might have slept. + * Stop the loop, to avoid a race condition. + */ + if (volatile_task) + break; + } + up(&mm->mmap_sem); + + /* encode f_pos */ + *ppos = (lineno << MAPS_LINE_SHIFT) + column; + +getlen_out: + retval = destptr - buf; + free_page((unsigned long)buffer); +out: + return retval; +} + +#ifdef __SMP__ +int proc_pid_cpu(struct task_struct *task, char * buffer) +{ + int i, len; + + len = sprintf(buffer, + "cpu %lu %lu\n", + task->times.tms_utime, + task->times.tms_stime); + + for (i = 0 ; i < smp_num_cpus; i++) + len += sprintf(buffer + len, "cpu%d %lu %lu\n", + i, + task->per_cpu_utime[cpu_logical_map(i)], + task->per_cpu_stime[cpu_logical_map(i)]); + + return len; +} +#endif diff -urN 2.3.29pre1/fs/proc/array.c.~2~ 2.3.29pre1-ikd/fs/proc/array.c.~2~ --- 2.3.29pre1/fs/proc/array.c.~2~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/fs/proc/array.c.~2~ Mon Nov 22 17:05:40 1999 @@ -0,0 +1,767 @@ +/* + * linux/fs/proc/array.c + * + * Copyright (C) 1992 by Linus Torvalds + * based on ideas by Darren Senn + * + * Fixes: + * Michael. K. Johnson: stat,statm extensions. + * + * + * Pauline Middelink : Made cmdline,envline only break at '\0's, to + * make sure SET_PROCTITLE works. Also removed + * bad '!' which forced address recalculation for + * EVERY character on the current page. + * + * + * Danny ter Haar : added cpuinfo + * + * + * Alessandro Rubini : profile extension. + * + * + * Jeff Tranter : added BogoMips field to cpuinfo + * + * + * Bruno Haible : remove 4K limit for the maps file + * + * + * Yves Arrouye : remove removal of trailing spaces in get_array. + * + * + * Jerome Forissier : added per-CPU time information to /proc/stat + * and /proc//cpu extension + * + * - Incorporation and non-SMP safe operation + * of forissier patch in 2.1.78 by + * Hans Marcus + * + * aeb@cwi.nl : /proc/partitions + * + * + * Alan Cox : security fixes. + * + * + * Al Viro : safe handling of mm_struct + * + * Gerhard Wichert : added BIGMEM support + * Siemens AG + * + * Al Viro & Jeff Garzik : moved most of the thing into base.c and + * : proc_misc.c. The rest may eventually go into + * : base.c too. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Gcc optimizes away "strlen(x)" for constant x */ +#define ADDBUF(buffer, string) \ +do { memcpy(buffer, string, strlen(string)); \ + buffer += strlen(string); } while (0) + +static inline char * task_name(struct task_struct *p, char * buf) +{ + int i; + char * name; + + ADDBUF(buf, "Name:\t"); + name = p->comm; + i = sizeof(p->comm); + do { + unsigned char c = *name; + name++; + i--; + *buf = c; + if (!c) + break; + if (c == '\\') { + buf[1] = c; + buf += 2; + continue; + } + if (c == '\n') { + buf[0] = '\\'; + buf[1] = 'n'; + buf += 2; + continue; + } + buf++; + } while (i); + *buf = '\n'; + return buf+1; +} + +/* + * The task state array is a strange "bitmap" of + * reasons to sleep. Thus "running" is zero, and + * you can test for combinations of others with + * simple bit tests. + */ +static const char *task_state_array[] = { + "R (running)", /* 0 */ + "S (sleeping)", /* 1 */ + "D (disk sleep)", /* 2 */ + "Z (zombie)", /* 4 */ + "T (stopped)", /* 8 */ + "W (paging)" /* 16 */ +}; + +static inline const char * get_task_state(struct task_struct *tsk) +{ + unsigned int state = tsk->state & (TASK_RUNNING | + TASK_INTERRUPTIBLE | + TASK_UNINTERRUPTIBLE | + TASK_ZOMBIE | + TASK_STOPPED | + TASK_SWAPPING); + const char **p = &task_state_array[0]; + + while (state) { + p++; + state >>= 1; + } + return *p; +} + +static inline char * task_state(struct task_struct *p, char *buffer) +{ + int g; + + buffer += sprintf(buffer, + "State:\t%s\n" + "Pid:\t%d\n" + "PPid:\t%d\n" + "Uid:\t%d\t%d\t%d\t%d\n" + "Gid:\t%d\t%d\t%d\t%d\n" + "FDSize:\t%d\n" + "Groups:\t", + get_task_state(p), + p->pid, p->p_pptr->pid, + p->uid, p->euid, p->suid, p->fsuid, + p->gid, p->egid, p->sgid, p->fsgid, + p->files ? p->files->max_fds : 0); + + for (g = 0; g < p->ngroups; g++) + buffer += sprintf(buffer, "%d ", p->groups[g]); + + buffer += sprintf(buffer, "\n"); + return buffer; +} + +static inline char * task_mem(struct mm_struct *mm, char *buffer) +{ + struct vm_area_struct * vma; + unsigned long data = 0, stack = 0; + unsigned long exec = 0, lib = 0; + + down(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) { + unsigned long len = (vma->vm_end - vma->vm_start) >> 10; + if (!vma->vm_file) { + data += len; + if (vma->vm_flags & VM_GROWSDOWN) + stack += len; + continue; + } + if (vma->vm_flags & VM_WRITE) + continue; + if (vma->vm_flags & VM_EXEC) { + exec += len; + if (vma->vm_flags & VM_EXECUTABLE) + continue; + lib += len; + } + } + buffer += sprintf(buffer, + "VmSize:\t%8lu kB\n" + "VmLck:\t%8lu kB\n" + "VmRSS:\t%8lu kB\n" + "VmData:\t%8lu kB\n" + "VmStk:\t%8lu kB\n" + "VmExe:\t%8lu kB\n" + "VmLib:\t%8lu kB\n", + mm->total_vm << (PAGE_SHIFT-10), + mm->locked_vm << (PAGE_SHIFT-10), + mm->rss << (PAGE_SHIFT-10), + data - stack, stack, + exec - lib, lib); + up(&mm->mmap_sem); + return buffer; +} + +static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, + sigset_t *catch) +{ + struct k_sigaction *k; + int i; + + sigemptyset(ign); + sigemptyset(catch); + + if (p->sig) { + k = p->sig->action; + for (i = 1; i <= _NSIG; ++i, ++k) { + if (k->sa.sa_handler == SIG_IGN) + sigaddset(ign, i); + else if (k->sa.sa_handler != SIG_DFL) + sigaddset(catch, i); + } + } +} + +static inline char * task_sig(struct task_struct *p, char *buffer) +{ + sigset_t ign, catch; + + buffer += sprintf(buffer, "SigPnd:\t"); + buffer = render_sigset_t(&p->signal, buffer); + *buffer++ = '\n'; + buffer += sprintf(buffer, "SigBlk:\t"); + buffer = render_sigset_t(&p->blocked, buffer); + *buffer++ = '\n'; + + collect_sigign_sigcatch(p, &ign, &catch); + buffer += sprintf(buffer, "SigIgn:\t"); + buffer = render_sigset_t(&ign, buffer); + *buffer++ = '\n'; + buffer += sprintf(buffer, "SigCgt:\t"); /* Linux 2.0 uses "SigCgt" */ + buffer = render_sigset_t(&catch, buffer); + *buffer++ = '\n'; + + return buffer; +} + +extern inline char *task_cap(struct task_struct *p, char *buffer) +{ + return buffer + sprintf(buffer, "CapInh:\t%016x\n" + "CapPrm:\t%016x\n" + "CapEff:\t%016x\n", + cap_t(p->cap_inheritable), + cap_t(p->cap_permitted), + cap_t(p->cap_effective)); +} + +#ifdef CONFIG_TRACE + +/* + * This function accesses kernel tracer information. The returned data is + * binary: the sampling step and the actual contents of the trace + * ringbuffer. Use of the program 'ktrace' is recommended in order to + * get meaningful info out of these data. + */ +static ssize_t read_trace(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + loff_t p = *ppos, left; + unsigned long flags; + int i; + + SUSPEND_MCOUNT_TRACE; + LOCK_MCOUNT_TRACE(flags); + + /* Calibrate the tracer */ + for (i = 1; i <= TRACE_CALIBRATION_CALLS; ++i) + mcount_internal(-1); + + UNLOCK_MCOUNT_TRACE(flags); + + if (p >= sizeof(*trace_table)) + count = 0; + else if (count > sizeof(*trace_table) - p) + count = sizeof(*trace_table) - p; + + left = copy_to_user(buf, p + (char *)trace_table, count); + + RESUME_MCOUNT_TRACE; + + if (count && left == count) + return -EFAULT; + + *ppos += count - left; + return count - left; +} + +/* + * Writing to /proc/trace resets the counters. Doesnt make much sense + * as it's a ringbuffer, but we do it anyways, it might make sense for + * doing short term traces. + */ + +static ssize_t write_trace(struct file * file, const char * buf, size_t count, loff_t *ppos) +{ + unsigned long flags; + SUSPEND_MCOUNT_TRACE; + LOCK_MCOUNT_TRACE(flags); + memset(trace_table->entries, 0, sizeof(trace_table->entries)); + trace_table->curr_call = CONFIG_TRACE_SIZE-1; + UNLOCK_MCOUNT_TRACE(flags); + RESUME_MCOUNT_TRACE; + return count; +} + +static struct file_operations proc_trace_operations = { + NULL, /* lseek */ + read_trace, + write_trace, +}; + +struct inode_operations proc_trace_inode_operations = { + &proc_trace_operations, +}; + +/* + * Dump the kernel trace table in hex to all registered consoles. + * A method of getting the trace table when all else fails. + * This is a raw dump, the entire table is printed in hex, 80 hex digits + * to a line. Capture the output via a serial console and feed into + * ktrace with the "-d filename" option. + * Not recommended for a large trace table over a slow serial line. + */ +#define TRACE_LINE_WIDTH 80 +void ktrace_to_console(void) +{ + static const char hexchar[] = "0123456789abcdef"; + int i; + unsigned c; + char buf[TRACE_LINE_WIDTH+3], *p; + + SUSPEND_MCOUNT_TRACE; + /* Should LOCK_MCOUNT_TRACE here but that might stop output. + * Live with the risk of dumping garbage. Cannot calibrate + * without the lock, OTOH accurate timing figures are probably + * the least of our worries at this point. + */ + + for (i = 0, p = buf; i < sizeof(*trace_table); ++i) { + /* hex convert inline, 200,000+ calls to vsprintf is slow */ + c = *((unsigned char *)(trace_table)+i); + *p++ = hexchar[c>>4]; + *p++ = hexchar[c&0xf]; + if (p - buf >= TRACE_LINE_WIDTH) { + *p++ = '\n'; + *p++ = '\0'; + console_print(buf); + p = buf; + } + } + if (p != buf) { + *p++ = '\n'; + *p++ = '\0'; + console_print(buf); + } + + RESUME_MCOUNT_TRACE; +} +#endif /* CONFIG_TRACE */ + +/* task is locked, so we are safe here */ + +int proc_pid_status(struct task_struct *task, char * buffer) +{ + char * orig = buffer; + struct mm_struct *mm = task->mm; + + buffer = task_name(task, buffer); + buffer = task_state(task, buffer); + if (mm) + buffer = task_mem(mm, buffer); + buffer = task_sig(task, buffer); + buffer = task_cap(task, buffer); + return buffer - orig; +} + +/* task is locked, so we are safe here */ + +int proc_pid_stat(struct task_struct *task, char * buffer) +{ + struct mm_struct *mm = task->mm; + unsigned long vsize, eip, esp, wchan; + long priority, nice; + int tty_pgrp; + sigset_t sigign, sigcatch; + char state; + int res; + + state = *get_task_state(task); + vsize = eip = esp = 0; + if (mm) { + struct vm_area_struct *vma; + down(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + vsize += vma->vm_end - vma->vm_start; + vma = vma->vm_next; + } + eip = KSTK_EIP(task); + esp = KSTK_ESP(task); + up(&mm->mmap_sem); + } + + wchan = get_wchan(task); + + collect_sigign_sigcatch(task, &sigign, &sigcatch); + + if (task->tty) + tty_pgrp = task->tty->pgrp; + else + tty_pgrp = -1; + + /* scale priority and nice values from timeslices to -20..20 */ + /* to make it look like a "normal" Unix priority/nice value */ + priority = task->counter; + priority = 20 - (priority * 10 + DEF_PRIORITY / 2) / DEF_PRIORITY; + nice = task->priority; + nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY; + + res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ +%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ +%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n", + task->pid, + task->comm, + state, + task->p_pptr->pid, + task->pgrp, + task->session, + task->tty ? kdev_t_to_nr(task->tty->device) : 0, + tty_pgrp, + task->flags, + task->min_flt, + task->cmin_flt, + task->maj_flt, + task->cmaj_flt, + task->times.tms_utime, + task->times.tms_stime, + task->times.tms_cutime, + task->times.tms_cstime, + priority, + nice, + 0UL /* removed */, + task->it_real_value, + task->start_time, + vsize, + mm ? mm->rss : 0, /* you might want to shift this left 3 */ + task->rlim ? task->rlim[RLIMIT_RSS].rlim_cur : 0, + mm ? mm->start_code : 0, + mm ? mm->end_code : 0, + mm ? mm->start_stack : 0, + esp, + eip, + /* The signal information here is obsolete. + * It must be decimal for Linux 2.0 compatibility. + * Use /proc/#/status for real-time signals. + */ + task->signal .sig[0] & 0x7fffffffUL, + task->blocked.sig[0] & 0x7fffffffUL, + sigign .sig[0] & 0x7fffffffUL, + sigcatch .sig[0] & 0x7fffffffUL, + wchan, + task->nswap, + task->cnswap, + task->exit_signal, + task->processor); + return res; +} + +static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t page = *pte; + + address += PAGE_SIZE; + pte++; + if (pte_none(page)) + continue; + ++*total; + if (!pte_present(page)) + continue; + ++*pages; + if (pte_dirty(page)) + ++*dirty; + if (pte_pagenr(page) >= max_mapnr) + continue; + if (page_count(pte_page(page)) > 1) + ++*shared; + } while (address < end); +} + +static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size, + int * pages, int * shared, int * dirty, int * total) +{ + pmd_t * pmd; + unsigned long end; + + if (pgd_none(*pgd)) + return; + if (pgd_bad(*pgd)) { + pgd_ERROR(*pgd); + pgd_clear(pgd); + return; + } + pmd = pmd_offset(pgd, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + statm_pte_range(pmd, address, end - address, pages, shared, dirty, total); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); +} + +static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end, + int * pages, int * shared, int * dirty, int * total) +{ + while (address < end) { + statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + pgd++; + } +} + +int proc_pid_statm(struct task_struct *task, char * buffer) +{ + struct mm_struct *mm = task->mm; + int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + + if (mm) { + struct vm_area_struct * vma; + down(&mm->mmap_sem); + vma = mm->mmap; + while (vma) { + pgd_t *pgd = pgd_offset(mm, vma->vm_start); + int pages = 0, shared = 0, dirty = 0, total = 0; + + statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total); + resident += pages; + share += shared; + dt += dirty; + size += total; + if (vma->vm_flags & VM_EXECUTABLE) + trs += pages; /* text */ + else if (vma->vm_flags & VM_GROWSDOWN) + drs += pages; /* stack */ + else if (vma->vm_end > 0x60000000) + lrs += pages; /* library */ + else + drs += pages; + vma = vma->vm_next; + } + up(&mm->mmap_sem); + } + return sprintf(buffer,"%d %d %d %d %d %d %d\n", + size, resident, share, trs, lrs, drs, dt); +} + +/* + * The way we support synthetic files > 4K + * - without storing their contents in some buffer and + * - without walking through the entire synthetic file until we reach the + * position of the requested data + * is to cleverly encode the current position in the file's f_pos field. + * There is no requirement that a read() call which returns `count' bytes + * of data increases f_pos by exactly `count'. + * + * This idea is Linus' one. Bruno implemented it. + */ + +/* + * For the /proc//maps file, we use fixed length records, each containing + * a single line. + */ +#define MAPS_LINE_LENGTH 4096 +#define MAPS_LINE_SHIFT 12 +/* + * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH + * + (index into the line) + */ +/* for systems with sizeof(void*) == 4: */ +#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %s %lu" +#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */ + +/* for systems with sizeof(void*) == 8: */ +#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %s %lu" +#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */ + +#define MAPS_LINE_MAX MAPS_LINE_MAX8 + + +ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct * map, * next; + char * destptr = buf, * buffer; + loff_t lineno; + ssize_t column, i; + int volatile_task; + long retval; + + /* + * We might sleep getting the page, so get it first. + */ + retval = -ENOMEM; + buffer = (char*)__get_free_page(GFP_KERNEL); + if (!buffer) + goto out; + + if (!mm || count == 0) + goto getlen_out; + + /* Check whether the mmaps could change if we sleep */ + volatile_task = (task != current || atomic_read(&mm->mm_users) > 1); + + /* decode f_pos */ + lineno = *ppos >> MAPS_LINE_SHIFT; + column = *ppos & (MAPS_LINE_LENGTH-1); + + /* quickly go to line lineno */ + down(&mm->mmap_sem); + for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++) + continue; + + for ( ; map ; map = next ) { + /* produce the next line */ + char *line; + char str[5], *cp = str; + int flags; + kdev_t dev; + unsigned long ino; + int maxlen = (sizeof(void*) == 4) ? + MAPS_LINE_MAX4 : MAPS_LINE_MAX8; + int len; + + /* + * Get the next vma now (but it won't be used if we sleep). + */ + next = map->vm_next; + flags = map->vm_flags; + + *cp++ = flags & VM_READ ? 'r' : '-'; + *cp++ = flags & VM_WRITE ? 'w' : '-'; + *cp++ = flags & VM_EXEC ? 'x' : '-'; + *cp++ = flags & VM_MAYSHARE ? 's' : 'p'; + *cp++ = 0; + + dev = 0; + ino = 0; + if (map->vm_file != NULL) { + dev = map->vm_file->f_dentry->d_inode->i_dev; + ino = map->vm_file->f_dentry->d_inode->i_ino; + line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE); + buffer[PAGE_SIZE-1] = '\n'; + line -= maxlen; + if(line < buffer) + line = buffer; + } else + line = buffer; + + len = sprintf(line, + sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8, + map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT, + kdevname(dev), ino); + + if(map->vm_file) { + for(i = len; i < maxlen; i++) + line[i] = ' '; + len = buffer + PAGE_SIZE - line; + } else + line[len++] = '\n'; + if (column >= len) { + column = 0; /* continue with next line at column 0 */ + lineno++; + continue; /* we haven't slept */ + } + + i = len-column; + if (i > count) + i = count; + up(&mm->mmap_sem); + copy_to_user(destptr, line+column, i); /* may have slept */ + down(&mm->mmap_sem); + destptr += i; + count -= i; + column += i; + if (column >= len) { + column = 0; /* next time: next line at column 0 */ + lineno++; + } + + /* done? */ + if (count == 0) + break; + + /* By writing to user space, we might have slept. + * Stop the loop, to avoid a race condition. + */ + if (volatile_task) + break; + } + up(&mm->mmap_sem); + + /* encode f_pos */ + *ppos = (lineno << MAPS_LINE_SHIFT) + column; + +getlen_out: + retval = destptr - buf; + free_page((unsigned long)buffer); +out: + return retval; +} + +#ifdef __SMP__ +int proc_pid_cpu(struct task_struct *task, char * buffer) +{ + int i, len; + + len = sprintf(buffer, + "cpu %lu %lu\n", + task->times.tms_utime, + task->times.tms_stime); + + for (i = 0 ; i < smp_num_cpus; i++) + len += sprintf(buffer + len, "cpu%d %lu %lu\n", + i, + task->per_cpu_utime[cpu_logical_map(i)], + task->per_cpu_stime[cpu_logical_map(i)]); + + return len; +} +#endif diff -urN 2.3.29pre1/fs/proc/proc_misc.c 2.3.29pre1-ikd/fs/proc/proc_misc.c --- 2.3.29pre1/fs/proc/proc_misc.c Sun Nov 21 03:20:20 1999 +++ 2.3.29pre1-ikd/fs/proc/proc_misc.c Mon Nov 22 17:12:55 1999 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -632,6 +633,131 @@ 0, &proc_profile_inode_operations }; +#ifdef CONFIG_TRACE +/* + * This function accesses kernel tracer information. The returned data is + * binary: the sampling step and the actual contents of the trace + * ringbuffer. Use of the program 'ktrace' is recommended in order to + * get meaningful info out of these data. + */ +static ssize_t read_trace(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + loff_t p = *ppos, left; + unsigned long flags; + int i; + + SUSPEND_MCOUNT_TRACE; + LOCK_MCOUNT_TRACE(flags); + + /* Calibrate the tracer */ + for (i = 1; i <= TRACE_CALIBRATION_CALLS; ++i) + mcount_internal(-1); + + UNLOCK_MCOUNT_TRACE(flags); + + if (p >= sizeof(*trace_table)) + count = 0; + else if (count > sizeof(*trace_table) - p) + count = sizeof(*trace_table) - p; + + left = copy_to_user(buf, p + (char *)trace_table, count); + + RESUME_MCOUNT_TRACE; + + if (count && left == count) + return -EFAULT; + + *ppos += count - left; + return count - left; +} + +/* + * Writing to /proc/trace resets the counters. Doesnt make much sense + * as it's a ringbuffer, but we do it anyways, it might make sense for + * doing short term traces. + */ + +static ssize_t write_trace(struct file * file, const char * buf, size_t count, loff_t *ppos) +{ + unsigned long flags; + SUSPEND_MCOUNT_TRACE; + LOCK_MCOUNT_TRACE(flags); + memset(trace_table->entries, 0, sizeof(trace_table->entries)); + trace_table->curr_call = CONFIG_TRACE_SIZE-1; + UNLOCK_MCOUNT_TRACE(flags); + RESUME_MCOUNT_TRACE; + return count; +} + +static struct file_operations proc_trace_operations = { + NULL, /* lseek */ + read_trace, + write_trace, +}; + +struct inode_operations proc_trace_inode_operations = { + &proc_trace_operations, +}; + +/* + * Dump the kernel trace table in hex to all registered consoles. + * A method of getting the trace table when all else fails. + * This is a raw dump, the entire table is printed in hex, 80 hex digits + * to a line. Capture the output via a serial console and feed into + * ktrace with the "-d filename" option. + * Not recommended for a large trace table over a slow serial line. + */ +#define TRACE_LINE_WIDTH 80 +void ktrace_to_console(void) +{ + static const char hexchar[] = "0123456789abcdef"; + int i; + unsigned c; + char buf[TRACE_LINE_WIDTH+3], *p; + + SUSPEND_MCOUNT_TRACE; + /* Should LOCK_MCOUNT_TRACE here but that might stop output. + * Live with the risk of dumping garbage. Cannot calibrate + * without the lock, OTOH accurate timing figures are probably + * the least of our worries at this point. + */ + + for (i = 0, p = buf; i < sizeof(*trace_table); ++i) { + /* hex convert inline, 200,000+ calls to vsprintf is slow */ + c = *((unsigned char *)(trace_table)+i); + *p++ = hexchar[c>>4]; + *p++ = hexchar[c&0xf]; + if (p - buf >= TRACE_LINE_WIDTH) { + *p++ = '\n'; + *p++ = '\0'; + console_print(buf); + p = buf; + } + } + if (p != buf) { + *p++ = '\n'; + *p++ = '\0'; + console_print(buf); + } + + RESUME_MCOUNT_TRACE; +} + +static struct proc_dir_entry proc_root_trace = { + PROC_TRACE, 5, "trace", + S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, + 0, &proc_trace_inode_operations +}; +#endif + +#ifdef CONFIG_MEMLEAK +static struct proc_dir_entry proc_root_memleak = { + PROC_MEMLEAK, 7, "memleak", + S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, + 0, &proc_memleak_inode_operations +}; +#endif + void proc_misc_init(void) { static struct { @@ -685,6 +811,16 @@ proc_register(&proc_root, &proc_root_kmsg); proc_register(&proc_root, &proc_root_kcore); proc_root_kcore.size = (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; + +#ifdef CONFIG_MEMLEAK + proc_register(&proc_root, &proc_root_memleak); +#endif + +#ifdef CONFIG_TRACE + proc_register(&proc_root, &proc_root_trace); + proc_root_trace.size = sizeof(*trace_table); +#endif + if (prof_shift) { proc_register(&proc_root, &proc_root_profile); proc_root_profile.size = (1+prof_len) * sizeof(unsigned int); diff -urN 2.3.29pre1/fs/proc/proc_misc.c.~1~ 2.3.29pre1-ikd/fs/proc/proc_misc.c.~1~ --- 2.3.29pre1/fs/proc/proc_misc.c.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/fs/proc/proc_misc.c.~1~ Sun Nov 21 03:20:20 1999 @@ -0,0 +1,692 @@ +/* + * linux/fs/proc/proc_misc.c + * + * linux/fs/proc/array.c + * Copyright (C) 1992 by Linus Torvalds + * based on ideas by Darren Senn + * + * This used to be the part of array.c. See the rest of history and credits + * there. I took this into a separate file and switched the thing to generic + * proc_file_inode_operations, leaving in array.c only per-process stuff. + * Inumbers allocation made dynamic (via create_proc_entry()). AV, May 1999. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#define LOAD_INT(x) ((x) >> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) +/* + * Warning: stuff below (imported functions) assumes that its output will fit + * into one page. For some of those functions it may be wrong. Moreover, we + * have a way to deal with that gracefully. Right now I used straightforward + * wrappers, but this needs further analysis wrt potential overflows. + */ +extern int get_cpuinfo(char *); +extern int get_hardware_list(char *); +extern int get_stram_list(char *); +#ifdef CONFIG_DEBUG_MALLOC +extern int get_malloc(char * buffer); +#endif +#ifdef CONFIG_MODULES +extern int get_module_list(char *); +extern int get_ksyms_list(char *, char **, off_t, int); +#endif +extern int get_device_list(char *); +extern int get_partition_list(char *); +extern int get_filesystem_list(char *); +extern int get_filesystem_info(char *); +extern int get_exec_domain_list(char *); +extern int get_irq_list(char *); +extern int get_dma_list(char *); +extern int get_rtc_status (char *); +extern int get_locks_status (char *, char **, off_t, int); +extern int get_swaparea_info (char *); +#ifdef CONFIG_SGI_DS1286 +extern int get_ds1286_status(char *); +#endif + +static int loadavg_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int a, b, c; + int len; + + a = avenrun[0] + (FIXED_1/200); + b = avenrun[1] + (FIXED_1/200); + c = avenrun[2] + (FIXED_1/200); + len = sprintf(page,"%d.%02d %d.%02d %d.%02d %d/%d %d\n", + LOAD_INT(a), LOAD_FRAC(a), + LOAD_INT(b), LOAD_FRAC(b), + LOAD_INT(c), LOAD_FRAC(c), + nr_running, nr_threads, last_pid); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int uptime_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long uptime; + unsigned long idle; + int len; + + uptime = jiffies; + idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime; + + /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but + that would overflow about every five days at HZ == 100. + Therefore the identity a = (a / b) * b + a % b is used so that it is + calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100. + The part in front of the '+' always evaluates as 0 (mod 100). All divisions + in the above formulas are truncating. For HZ being a power of 10, the + calculations simplify to the version in the #else part (if the printf + format is adapted to the same number of digits as zeroes in HZ. + */ +#if HZ!=100 + len = sprintf(page,"%lu.%02lu %lu.%02lu\n", + uptime / HZ, + (((uptime % HZ) * 100) / HZ) % 100, + idle / HZ, + (((idle % HZ) * 100) / HZ) % 100); +#else + len = sprintf(page,"%lu.%02lu %lu.%02lu\n", + uptime / HZ, + uptime % HZ, + idle / HZ, + idle % HZ); +#endif + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int meminfo_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct sysinfo i; + int len; + +/* + * display in kilobytes. + */ +#define K(x) ((x) << (PAGE_SHIFT - 10)) +#define B(x) ((x) << PAGE_SHIFT) + si_meminfo(&i); + si_swapinfo(&i); + len = sprintf(page, " total: used: free: shared: buffers: cached:\n" + "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n" + "Swap: %8lu %8lu %8lu\n", + B(i.totalram), B(i.totalram-i.freeram), B(i.freeram), + B(i.sharedram), B(i.bufferram), + B(atomic_read(&page_cache_size)), B(i.totalswap), + B(i.totalswap-i.freeswap), B(i.freeswap)); + /* + * Tagged format, for easy grepping and expansion. + * The above will go away eventually, once the tools + * have been updated. + */ + len += sprintf(page+len, + "MemTotal: %8lu kB\n" + "MemFree: %8lu kB\n" + "MemShared: %8lu kB\n" + "Buffers: %8lu kB\n" + "Cached: %8u kB\n" + "HighTotal: %8lu kB\n" + "HighFree: %8lu kB\n" + "LowTotal: %8lu kB\n" + "LowFree: %8lu kB\n" + "SwapTotal: %8lu kB\n" + "SwapFree: %8lu kB\n", + K(i.totalram), + K(i.freeram), + K(i.sharedram), + K(i.bufferram), + K(atomic_read(&page_cache_size)), + K(i.totalhigh), + K(i.freehigh), + K(i.totalram-i.totalhigh), + K(i.freeram-i.freehigh), + K(i.totalswap), + K(i.freeswap)); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +#undef B +#undef K +} + +static int version_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + extern char *linux_banner; + int len; + + strcpy(page, linux_banner); + len = strlen(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int cpuinfo_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_cpuinfo(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +#ifdef CONFIG_PROC_HARDWARE +static int hardware_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_hardware_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} +#endif + +#ifdef CONFIG_STRAM_PROC +static int stram_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_stram_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} +#endif + +#ifdef CONFIG_DEBUG_MALLOC +static int malloc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_malloc(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} +#endif + +#ifdef CONFIG_MODULES +static int modules_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_module_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int ksyms_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_ksyms_list(page, start, off, count); + if (len < count) *eof = 1; + return len; +} +#endif + +static int kstat_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int i, len; + unsigned sum = 0; + extern unsigned long total_forks; + unsigned long jif = jiffies; + + for (i = 0 ; i < NR_IRQS ; i++) + sum += kstat_irqs(i); + +#ifdef __SMP__ + len = sprintf(page, + "cpu %u %u %u %lu\n", + kstat.cpu_user, + kstat.cpu_nice, + kstat.cpu_system, + jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system)); + for (i = 0 ; i < smp_num_cpus; i++) + len += sprintf(page + len, "cpu%d %u %u %u %lu\n", + i, + kstat.per_cpu_user[cpu_logical_map(i)], + kstat.per_cpu_nice[cpu_logical_map(i)], + kstat.per_cpu_system[cpu_logical_map(i)], + jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \ + + kstat.per_cpu_nice[cpu_logical_map(i)] \ + + kstat.per_cpu_system[cpu_logical_map(i)])); + len += sprintf(page + len, + "disk %u %u %u %u\n" + "disk_rio %u %u %u %u\n" + "disk_wio %u %u %u %u\n" + "disk_rblk %u %u %u %u\n" + "disk_wblk %u %u %u %u\n" + "page %u %u\n" + "swap %u %u\n" + "intr %u", +#else + len = sprintf(page, + "cpu %u %u %u %lu\n" + "disk %u %u %u %u\n" + "disk_rio %u %u %u %u\n" + "disk_wio %u %u %u %u\n" + "disk_rblk %u %u %u %u\n" + "disk_wblk %u %u %u %u\n" + "page %u %u\n" + "swap %u %u\n" + "intr %u", + kstat.cpu_user, + kstat.cpu_nice, + kstat.cpu_system, + jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system), +#endif + kstat.dk_drive[0], kstat.dk_drive[1], + kstat.dk_drive[2], kstat.dk_drive[3], + kstat.dk_drive_rio[0], kstat.dk_drive_rio[1], + kstat.dk_drive_rio[2], kstat.dk_drive_rio[3], + kstat.dk_drive_wio[0], kstat.dk_drive_wio[1], + kstat.dk_drive_wio[2], kstat.dk_drive_wio[3], + kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1], + kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3], + kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1], + kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3], + kstat.pgpgin, + kstat.pgpgout, + kstat.pswpin, + kstat.pswpout, + sum); + for (i = 0 ; i < NR_IRQS ; i++) + len += sprintf(page + len, " %u", kstat_irqs(i)); + len += sprintf(page + len, + "\nctxt %u\n" + "btime %lu\n" + "processes %lu\n", + kstat.context_swtch, + xtime.tv_sec - jif / HZ, + total_forks); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int devices_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_device_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int partitions_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_partition_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int interrupts_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_irq_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int filesystems_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_filesystem_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int dma_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_dma_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int ioports_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_ioport_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int cmdline_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + extern char saved_command_line[]; + int len; + + len = sprintf(page, "%s\n", saved_command_line); + len = strlen(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +#ifdef CONFIG_RTC +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_rtc_status(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} +#endif + +#ifdef CONFIG_SGI_DS1286 +static int ds1286_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_ds1286_status(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} +#endif + +static int locks_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_locks_status(page, start, off, count); + if (len < count) *eof = 1; + return len; +} + +static int mounts_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_filesystem_info(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int execdomains_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_exec_domain_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int swaps_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_swaparea_info(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int slabinfo_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_slabinfo(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int memory_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = get_mem_list(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +/* + * This function accesses profiling information. The returned data is + * binary: the sampling step and the actual contents of the profile + * buffer. Use of the program readprofile is recommended in order to + * get meaningful info out of these data. + */ +static ssize_t read_profile(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + ssize_t read; + char * pnt; + unsigned int sample_step = 1 << prof_shift; + + if (p >= (prof_len+1)*sizeof(unsigned int)) + return 0; + if (count > (prof_len+1)*sizeof(unsigned int) - p) + count = (prof_len+1)*sizeof(unsigned int) - p; + read = 0; + + while (p < sizeof(unsigned int) && count > 0) { + put_user(*((char *)(&sample_step)+p),buf); + buf++; p++; count--; read++; + } + pnt = (char *)prof_buffer + p - sizeof(unsigned int); + copy_to_user(buf,(void *)pnt,count); + read += count; + *ppos += read; + return read; +} + +/* + * Writing to /proc/profile resets the counters + * + * Writing a 'profiling multiplier' value into it also re-sets the profiling + * interrupt frequency, on architectures that support this. + */ +static ssize_t write_profile(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ +#ifdef __SMP__ + extern int setup_profiling_timer (unsigned int multiplier); + + if (count==sizeof(int)) { + unsigned int multiplier; + + if (copy_from_user(&multiplier, buf, sizeof(int))) + return -EFAULT; + + if (setup_profiling_timer(multiplier)) + return -EINVAL; + } +#endif + + memset(prof_buffer, 0, prof_len * sizeof(*prof_buffer)); + return count; +} + +static struct file_operations proc_profile_operations = { + NULL, /* lseek */ + read_profile, + write_profile, +}; + +static struct inode_operations proc_profile_inode_operations = { + &proc_profile_operations, +}; + +static struct proc_dir_entry proc_root_kmsg = { + 0, 4, "kmsg", + S_IFREG | S_IRUSR, 1, 0, 0, + 0, &proc_kmsg_inode_operations +}; +struct proc_dir_entry proc_root_kcore = { + 0, 5, "kcore", + S_IFREG | S_IRUSR, 1, 0, 0, + 0, &proc_kcore_inode_operations +}; +static struct proc_dir_entry proc_root_profile = { + 0, 7, "profile", + S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, + 0, &proc_profile_inode_operations +}; + +void proc_misc_init(void) +{ + static struct { + char *name; + int (*read_proc)(char*,char**,off_t,int,int*,void*); + } *p, simple_ones[] = { + {"loadavg", loadavg_read_proc}, + {"uptime", uptime_read_proc}, + {"meminfo", meminfo_read_proc}, + {"version", version_read_proc}, + {"cpuinfo", cpuinfo_read_proc}, +#ifdef CONFIG_PROC_HARDWARE + {"hardware", hardware_read_proc}, +#endif +#ifdef CONFIG_STRAM_PROC + {"stram", stram_read_proc}, +#endif +#ifdef CONFIG_DEBUG_MALLOC + {"malloc", malloc_read_proc}, +#endif +#ifdef CONFIG_MODULES + {"modules", modules_read_proc}, + {"ksyms", ksyms_read_proc}, +#endif + {"stat", kstat_read_proc}, + {"devices", devices_read_proc}, + {"partitions", partitions_read_proc}, + {"interrupts", interrupts_read_proc}, + {"filesystems", filesystems_read_proc}, + {"dma", dma_read_proc}, + {"ioports", ioports_read_proc}, + {"cmdline", cmdline_read_proc}, +#ifdef CONFIG_RTC + {"rtc", rtc_read_proc}, +#endif +#ifdef CONFIG_SGI_DS1286 + {"rtc", ds1286_read_proc}, +#endif + {"locks", locks_read_proc}, + {"mounts", mounts_read_proc}, + {"swaps", swaps_read_proc}, + {"slabinfo", slabinfo_read_proc}, + {"iomem", memory_read_proc}, + {"execdomains", execdomains_read_proc}, + {NULL,NULL} + }; + for(p=simple_ones;p->name;p++) + create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL); + + /* And now for trickier ones */ + proc_register(&proc_root, &proc_root_kmsg); + proc_register(&proc_root, &proc_root_kcore); + proc_root_kcore.size = (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; + if (prof_shift) { + proc_register(&proc_root, &proc_root_profile); + proc_root_profile.size = (1+prof_len) * sizeof(unsigned int); + } +} diff -urN 2.3.29pre1/fs/proc/root.c.orig 2.3.29pre1-ikd/fs/proc/root.c.orig --- 2.3.29pre1/fs/proc/root.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/fs/proc/root.c.orig Sun Nov 21 03:20:44 1999 @@ -0,0 +1,531 @@ +/* + * linux/fs/proc/root.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * proc root directory handling functions + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +static int proc_root_readdir(struct file *, void *, filldir_t); +static struct dentry *proc_root_lookup(struct inode *,struct dentry *); +static int proc_unlink(struct inode *, struct dentry *); + +static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0}; + +/* + * These are the generic /proc directory operations. They + * use the in-memory "struct proc_dir_entry" tree to parse + * the /proc directory. + */ +static struct file_operations proc_dir_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readdir, /* readdir */ +}; + +/* + * proc directories can do almost nothing.. + */ +struct inode_operations proc_dir_inode_operations = { + &proc_dir_operations, /* default net directory file-ops */ + NULL, /* create */ + proc_lookup, /* lookup */ +}; + +/* + * /proc dynamic directories now support unlinking + */ +struct inode_operations proc_dyna_dir_inode_operations = { + &proc_dir_operations, /* default proc dir ops */ + NULL, /* create */ + proc_lookup, /* lookup */ + NULL, /* link */ + proc_unlink, /* unlink(struct inode *, struct dentry *) */ +}; + +/* + * The root /proc directory is special, as it has the + * directories. Thus we don't use the generic + * directory handling functions for that.. + */ +static struct file_operations proc_root_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_root_readdir, /* readdir */ +}; + +/* + * proc root can do almost nothing.. + */ +static struct inode_operations proc_root_inode_operations = { + &proc_root_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_root_lookup, /* lookup */ +}; + +/* + * This is the root "inode" in the /proc tree.. + */ +struct proc_dir_entry proc_root = { + PROC_ROOT_INO, 5, "/proc", + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, + 0, &proc_root_inode_operations, + NULL, NULL, + NULL, + &proc_root, NULL +}; + +struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver; + +#ifdef CONFIG_MCA +struct proc_dir_entry *proc_mca; +#endif + +#ifdef CONFIG_SYSCTL +struct proc_dir_entry *proc_sys_root; +#endif + +static int make_inode_number(void) +{ + int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC); + if (i<0 || i>=PROC_NDYNAMIC) + return -1; + set_bit(i, (void *) proc_alloc_map); + return PROC_DYNAMIC_FIRST + i; +} + +int proc_readlink(struct dentry * dentry, char * buffer, int buflen) +{ + struct inode *inode = dentry->d_inode; + struct proc_dir_entry * de; + char *page; + int len = 0; + + de = (struct proc_dir_entry *) inode->u.generic_ip; + if (!de) + return -ENOENT; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + + if (de->readlink_proc) + len = de->readlink_proc(de, page); + + if (len > buflen) + len = buflen; + + copy_to_user(buffer, page, len); + free_page((unsigned long) page); + return len; +} + +struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow) +{ + struct inode *inode = dentry->d_inode; + struct proc_dir_entry * de; + char *page; + struct dentry *d; + int len = 0; + + de = (struct proc_dir_entry *) inode->u.generic_ip; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return NULL; + + if (de->readlink_proc) + len = de->readlink_proc(de, page); + + d = lookup_dentry(page, base, follow); + free_page((unsigned long) page); + return d; +} + +static struct inode_operations proc_link_inode_operations = { + NULL, /* no file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + proc_readlink, /* readlink */ + proc_follow_link, /* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* flushpage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) +{ + int i; + + if (dp->low_ino == 0) { + i = make_inode_number(); + if (i < 0) + return -EAGAIN; + dp->low_ino = i; + } + dp->next = dir->subdir; + dp->parent = dir; + dir->subdir = dp; + if (S_ISDIR(dp->mode)) { + if (dp->ops == NULL) + dp->ops = &proc_dir_inode_operations; + dir->nlink++; + } else if (S_ISLNK(dp->mode)) { + if (dp->ops == NULL) + dp->ops = &proc_link_inode_operations; + } else { + if (dp->ops == NULL) + dp->ops = &proc_file_inode_operations; + } + return 0; +} + +/* + * Kill an inode that got unregistered.. + */ +static void proc_kill_inodes(int ino) +{ + struct list_head *p; + struct super_block *sb; + + /* + * Actually it's a partial revoke(). We have to go through all + * copies of procfs. proc_super_blocks is protected by the big + * lock for the time being. + */ + for (sb = proc_super_blocks; + sb; + sb = (struct super_block*)sb->u.generic_sbp) { + file_list_lock(); + for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { + struct file * filp = list_entry(p, struct file, f_list); + struct dentry * dentry; + struct inode * inode; + + dentry = filp->f_dentry; + if (!dentry) + continue; + if (dentry->d_op != &proc_dentry_operations) + continue; + inode = dentry->d_inode; + if (!inode) + continue; + if (inode->i_ino != ino) + continue; + filp->f_op = NULL; + } + file_list_unlock(); + } +} + +int proc_unregister(struct proc_dir_entry * dir, int ino) +{ + struct proc_dir_entry **p = &dir->subdir, *dp; + + while ((dp = *p) != NULL) { + if (dp->low_ino == ino) { + *p = dp->next; + dp->next = NULL; + if (S_ISDIR(dp->mode)) + dir->nlink--; + if (ino >= PROC_DYNAMIC_FIRST && + ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC) + clear_bit(ino-PROC_DYNAMIC_FIRST, + (void *) proc_alloc_map); + proc_kill_inodes(ino); + return 0; + } + p = &dp->next; + } + return -EINVAL; +} + +/* + * /proc/self: + */ +static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + int len; + char tmp[30]; + + len = sprintf(tmp, "%d", current->pid); + if (buflen < len) + len = buflen; + copy_to_user(buffer, tmp, len); + return len; +} + +static struct dentry * proc_self_follow_link(struct dentry *dentry, + struct dentry *base, + unsigned int follow) +{ + char tmp[30]; + + sprintf(tmp, "%d", current->pid); + return lookup_dentry(tmp, base, follow); +} + +static struct inode_operations proc_self_inode_operations = { + NULL, /* no file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + proc_self_readlink, /* readlink */ + proc_self_follow_link, /* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* flushpage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +static struct proc_dir_entry proc_root_self = { + 0, 4, "self", + S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0, + 64, &proc_self_inode_operations, +}; +#ifdef __powerpc__ +static struct proc_dir_entry proc_root_ppc_htab = { + 0, 8, "ppc_htab", + S_IFREG | S_IRUGO|S_IWUSR, 1, 0, 0, + 0, &proc_ppc_htab_inode_operations, +}; +#endif + +void __init proc_root_init(void) +{ + proc_misc_init(); + proc_register(&proc_root, &proc_root_self); + proc_net = create_proc_entry("net", S_IFDIR, 0); +#ifdef CONFIG_SYSVIPC + create_proc_entry("sysvipc", S_IFDIR, 0); +#endif +#ifdef CONFIG_SYSCTL + proc_sys_root = create_proc_entry("sys", S_IFDIR, 0); +#endif +#ifdef CONFIG_MCA + proc_mca = create_proc_entry("mca", S_IFDIR, 0); +#endif + proc_root_fs = create_proc_entry("fs", S_IFDIR, 0); + proc_root_driver = create_proc_entry("driver", S_IFDIR, 0); +#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) +#ifdef CONFIG_SUN_OPENPROMFS + openpromfs_init (); +#endif + /* just give it a mountpoint */ + create_proc_entry("openprom", S_IFDIR, 0); +#endif + proc_tty_init(); +#ifdef __powerpc__ + proc_register(&proc_root, &proc_root_ppc_htab); +#endif +#ifdef CONFIG_PROC_DEVICETREE + proc_device_tree_init(); +#endif + proc_bus = create_proc_entry("bus", S_IFDIR, 0); +} + +/* + * As some entries in /proc are volatile, we want to + * get rid of unused dentries. This could be made + * smarter: we could keep a "volatile" flag in the + * inode to indicate which ones to keep. + */ +static void +proc_delete_dentry(struct dentry * dentry) +{ + d_drop(dentry); +} + +struct dentry_operations proc_dentry_operations = +{ + NULL, /* revalidate */ + NULL, /* d_hash */ + NULL, /* d_compare */ + proc_delete_dentry /* d_delete(struct dentry *) */ +}; + +/* + * Don't create negative dentries here, return -ENOENT by hand + * instead. + */ +struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry) +{ + struct inode *inode; + struct proc_dir_entry * de; + int error; + + error = -ENOENT; + inode = NULL; + de = (struct proc_dir_entry *) dir->u.generic_ip; + if (de) { + for (de = de->subdir; de ; de = de->next) { + if (!de || !de->low_ino) + continue; + if (de->namelen != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { + int ino = de->low_ino; + error = -EINVAL; + inode = proc_get_inode(dir->i_sb, ino, de); + break; + } + } + } + + if (inode) { + dentry->d_op = &proc_dentry_operations; + d_add(dentry, inode); + return NULL; + } + return ERR_PTR(error); +} + +static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry) +{ + struct task_struct *p; + + if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */ + extern unsigned long total_forks; + static int last_timestamp = 0; + + /* + * this one can be a serious 'ps' performance problem if + * there are many threads running - thus we do 'lazy' + * link-recalculation - we change it only if the number + * of threads has increased. + */ + if (total_forks != last_timestamp) { + int nlink = proc_root.nlink; + + read_lock(&tasklist_lock); + last_timestamp = total_forks; + for_each_task(p) + nlink++; + read_unlock(&tasklist_lock); + /* + * subtract the # of idle threads which + * do not show up in /proc: + */ + dir->i_nlink = nlink - smp_num_cpus; + } + } + + if (!proc_lookup(dir, dentry)) + return NULL; + + return proc_pid_lookup(dir, dentry); +} + +/* + * This returns non-zero if at EOF, so that the /proc + * root directory can use this and check if it should + * continue with the entries.. + * + * Note that the VFS-layer doesn't care about the return + * value of the readdir() call, as long as it's non-negative + * for success.. + */ +int proc_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + struct proc_dir_entry * de; + unsigned int ino; + int i; + struct inode *inode = filp->f_dentry->d_inode; + + ino = inode->i_ino; + de = (struct proc_dir_entry *) inode->u.generic_ip; + if (!de) + return -EINVAL; + i = filp->f_pos; + switch (i) { + case 0: + if (filldir(dirent, ".", 1, i, ino) < 0) + return 0; + i++; + filp->f_pos++; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0) + return 0; + i++; + filp->f_pos++; + /* fall through */ + default: + de = de->subdir; + i -= 2; + for (;;) { + if (!de) + return 1; + if (!i) + break; + de = de->next; + i--; + } + + do { + if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0) + return 0; + filp->f_pos++; + de = de->next; + } while (de); + } + return 1; +} + +static int proc_root_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + unsigned int nr = filp->f_pos; + + if (nr < FIRST_PROCESS_ENTRY) { + int error = proc_readdir(filp, dirent, filldir); + if (error <= 0) + return error; + filp->f_pos = FIRST_PROCESS_ENTRY; + } + + return proc_pid_readdir(filp, dirent, filldir); +} + +static int proc_unlink(struct inode *dir, struct dentry *dentry) +{ + struct proc_dir_entry * dp = dir->u.generic_ip; + +printk("proc_file_unlink: deleting %s/%s\n", dp->name, dentry->d_name.name); + + remove_proc_entry(dentry->d_name.name, dp); + dentry->d_inode->i_nlink = 0; + d_delete(dentry); + return 0; +} diff -urN 2.3.29pre1/fs/proc/root.c.rej 2.3.29pre1-ikd/fs/proc/root.c.rej --- 2.3.29pre1/fs/proc/root.c.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/fs/proc/root.c.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,55 @@ +*************** +*** 606,611 **** + NULL /* revalidate */ + }; + + static struct proc_dir_entry proc_root_loadavg = { + PROC_LOADAVG, 7, "loadavg", + S_IFREG | S_IRUGO, 1, 0, 0, +--- 607,628 ---- + NULL /* revalidate */ + }; + ++ #ifdef CONFIG_TRACE ++ static struct proc_dir_entry proc_root_trace = { ++ PROC_TRACE, 5, "trace", ++ S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, ++ 0, &proc_trace_inode_operations ++ }; ++ #endif ++ ++ #ifdef CONFIG_MEMLEAK ++ static struct proc_dir_entry proc_root_memleak = { ++ PROC_MEMLEAK, 7, "memleak", ++ S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, ++ 0, &proc_memleak_inode_operations ++ }; ++ #endif ++ + static struct proc_dir_entry proc_root_loadavg = { + PROC_LOADAVG, 7, "loadavg", + S_IFREG | S_IRUGO, 1, 0, 0, +*************** +*** 847,852 **** + proc_register(&proc_root, &proc_root_stram); + #endif + proc_register(&proc_root, &proc_root_slab); + + if (prof_shift) { + proc_register(&proc_root, &proc_root_profile); +--- 864,878 ---- + proc_register(&proc_root, &proc_root_stram); + #endif + proc_register(&proc_root, &proc_root_slab); ++ ++ #ifdef CONFIG_MEMLEAK ++ proc_register(&proc_root, &proc_root_memleak); ++ #endif ++ ++ #ifdef CONFIG_TRACE ++ proc_register(&proc_root, &proc_root_trace); ++ proc_root_trace.size = sizeof(*trace_table); ++ #endif + + if (prof_shift) { + proc_register(&proc_root, &proc_root_profile); diff -urN 2.3.29pre1/fs/proc/root.c.~1~ 2.3.29pre1-ikd/fs/proc/root.c.~1~ --- 2.3.29pre1/fs/proc/root.c.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/fs/proc/root.c.~1~ Mon Nov 22 16:56:24 1999 @@ -0,0 +1,532 @@ +/* + * linux/fs/proc/root.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * proc root directory handling functions + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +static int proc_root_readdir(struct file *, void *, filldir_t); +static struct dentry *proc_root_lookup(struct inode *,struct dentry *); +static int proc_unlink(struct inode *, struct dentry *); + +static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0}; + +/* + * These are the generic /proc directory operations. They + * use the in-memory "struct proc_dir_entry" tree to parse + * the /proc directory. + */ +static struct file_operations proc_dir_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readdir, /* readdir */ +}; + +/* + * proc directories can do almost nothing.. + */ +struct inode_operations proc_dir_inode_operations = { + &proc_dir_operations, /* default net directory file-ops */ + NULL, /* create */ + proc_lookup, /* lookup */ +}; + +/* + * /proc dynamic directories now support unlinking + */ +struct inode_operations proc_dyna_dir_inode_operations = { + &proc_dir_operations, /* default proc dir ops */ + NULL, /* create */ + proc_lookup, /* lookup */ + NULL, /* link */ + proc_unlink, /* unlink(struct inode *, struct dentry *) */ +}; + +/* + * The root /proc directory is special, as it has the + * directories. Thus we don't use the generic + * directory handling functions for that.. + */ +static struct file_operations proc_root_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_root_readdir, /* readdir */ +}; + +/* + * proc root can do almost nothing.. + */ +static struct inode_operations proc_root_inode_operations = { + &proc_root_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_root_lookup, /* lookup */ +}; + +/* + * This is the root "inode" in the /proc tree.. + */ +struct proc_dir_entry proc_root = { + PROC_ROOT_INO, 5, "/proc", + S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, + 0, &proc_root_inode_operations, + NULL, NULL, + NULL, + &proc_root, NULL +}; + +struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver; + +#ifdef CONFIG_MCA +struct proc_dir_entry *proc_mca; +#endif +#include + +#ifdef CONFIG_SYSCTL +struct proc_dir_entry *proc_sys_root; +#endif + +static int make_inode_number(void) +{ + int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC); + if (i<0 || i>=PROC_NDYNAMIC) + return -1; + set_bit(i, (void *) proc_alloc_map); + return PROC_DYNAMIC_FIRST + i; +} + +int proc_readlink(struct dentry * dentry, char * buffer, int buflen) +{ + struct inode *inode = dentry->d_inode; + struct proc_dir_entry * de; + char *page; + int len = 0; + + de = (struct proc_dir_entry *) inode->u.generic_ip; + if (!de) + return -ENOENT; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + + if (de->readlink_proc) + len = de->readlink_proc(de, page); + + if (len > buflen) + len = buflen; + + copy_to_user(buffer, page, len); + free_page((unsigned long) page); + return len; +} + +struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow) +{ + struct inode *inode = dentry->d_inode; + struct proc_dir_entry * de; + char *page; + struct dentry *d; + int len = 0; + + de = (struct proc_dir_entry *) inode->u.generic_ip; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return NULL; + + if (de->readlink_proc) + len = de->readlink_proc(de, page); + + d = lookup_dentry(page, base, follow); + free_page((unsigned long) page); + return d; +} + +static struct inode_operations proc_link_inode_operations = { + NULL, /* no file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + proc_readlink, /* readlink */ + proc_follow_link, /* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* flushpage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) +{ + int i; + + if (dp->low_ino == 0) { + i = make_inode_number(); + if (i < 0) + return -EAGAIN; + dp->low_ino = i; + } + dp->next = dir->subdir; + dp->parent = dir; + dir->subdir = dp; + if (S_ISDIR(dp->mode)) { + if (dp->ops == NULL) + dp->ops = &proc_dir_inode_operations; + dir->nlink++; + } else if (S_ISLNK(dp->mode)) { + if (dp->ops == NULL) + dp->ops = &proc_link_inode_operations; + } else { + if (dp->ops == NULL) + dp->ops = &proc_file_inode_operations; + } + return 0; +} + +/* + * Kill an inode that got unregistered.. + */ +static void proc_kill_inodes(int ino) +{ + struct list_head *p; + struct super_block *sb; + + /* + * Actually it's a partial revoke(). We have to go through all + * copies of procfs. proc_super_blocks is protected by the big + * lock for the time being. + */ + for (sb = proc_super_blocks; + sb; + sb = (struct super_block*)sb->u.generic_sbp) { + file_list_lock(); + for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { + struct file * filp = list_entry(p, struct file, f_list); + struct dentry * dentry; + struct inode * inode; + + dentry = filp->f_dentry; + if (!dentry) + continue; + if (dentry->d_op != &proc_dentry_operations) + continue; + inode = dentry->d_inode; + if (!inode) + continue; + if (inode->i_ino != ino) + continue; + filp->f_op = NULL; + } + file_list_unlock(); + } +} + +int proc_unregister(struct proc_dir_entry * dir, int ino) +{ + struct proc_dir_entry **p = &dir->subdir, *dp; + + while ((dp = *p) != NULL) { + if (dp->low_ino == ino) { + *p = dp->next; + dp->next = NULL; + if (S_ISDIR(dp->mode)) + dir->nlink--; + if (ino >= PROC_DYNAMIC_FIRST && + ino < PROC_DYNAMIC_FIRST+PROC_NDYNAMIC) + clear_bit(ino-PROC_DYNAMIC_FIRST, + (void *) proc_alloc_map); + proc_kill_inodes(ino); + return 0; + } + p = &dp->next; + } + return -EINVAL; +} + +/* + * /proc/self: + */ +static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + int len; + char tmp[30]; + + len = sprintf(tmp, "%d", current->pid); + if (buflen < len) + len = buflen; + copy_to_user(buffer, tmp, len); + return len; +} + +static struct dentry * proc_self_follow_link(struct dentry *dentry, + struct dentry *base, + unsigned int follow) +{ + char tmp[30]; + + sprintf(tmp, "%d", current->pid); + return lookup_dentry(tmp, base, follow); +} + +static struct inode_operations proc_self_inode_operations = { + NULL, /* no file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + proc_self_readlink, /* readlink */ + proc_self_follow_link, /* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* flushpage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +static struct proc_dir_entry proc_root_self = { + 0, 4, "self", + S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0, + 64, &proc_self_inode_operations, +}; +#ifdef __powerpc__ +static struct proc_dir_entry proc_root_ppc_htab = { + 0, 8, "ppc_htab", + S_IFREG | S_IRUGO|S_IWUSR, 1, 0, 0, + 0, &proc_ppc_htab_inode_operations, +}; +#endif + +void __init proc_root_init(void) +{ + proc_misc_init(); + proc_register(&proc_root, &proc_root_self); + proc_net = create_proc_entry("net", S_IFDIR, 0); +#ifdef CONFIG_SYSVIPC + create_proc_entry("sysvipc", S_IFDIR, 0); +#endif +#ifdef CONFIG_SYSCTL + proc_sys_root = create_proc_entry("sys", S_IFDIR, 0); +#endif +#ifdef CONFIG_MCA + proc_mca = create_proc_entry("mca", S_IFDIR, 0); +#endif + proc_root_fs = create_proc_entry("fs", S_IFDIR, 0); + proc_root_driver = create_proc_entry("driver", S_IFDIR, 0); +#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) +#ifdef CONFIG_SUN_OPENPROMFS + openpromfs_init (); +#endif + /* just give it a mountpoint */ + create_proc_entry("openprom", S_IFDIR, 0); +#endif + proc_tty_init(); +#ifdef __powerpc__ + proc_register(&proc_root, &proc_root_ppc_htab); +#endif +#ifdef CONFIG_PROC_DEVICETREE + proc_device_tree_init(); +#endif + proc_bus = create_proc_entry("bus", S_IFDIR, 0); +} + +/* + * As some entries in /proc are volatile, we want to + * get rid of unused dentries. This could be made + * smarter: we could keep a "volatile" flag in the + * inode to indicate which ones to keep. + */ +static void +proc_delete_dentry(struct dentry * dentry) +{ + d_drop(dentry); +} + +struct dentry_operations proc_dentry_operations = +{ + NULL, /* revalidate */ + NULL, /* d_hash */ + NULL, /* d_compare */ + proc_delete_dentry /* d_delete(struct dentry *) */ +}; + +/* + * Don't create negative dentries here, return -ENOENT by hand + * instead. + */ +struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry) +{ + struct inode *inode; + struct proc_dir_entry * de; + int error; + + error = -ENOENT; + inode = NULL; + de = (struct proc_dir_entry *) dir->u.generic_ip; + if (de) { + for (de = de->subdir; de ; de = de->next) { + if (!de || !de->low_ino) + continue; + if (de->namelen != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { + int ino = de->low_ino; + error = -EINVAL; + inode = proc_get_inode(dir->i_sb, ino, de); + break; + } + } + } + + if (inode) { + dentry->d_op = &proc_dentry_operations; + d_add(dentry, inode); + return NULL; + } + return ERR_PTR(error); +} + +static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry) +{ + struct task_struct *p; + + if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */ + extern unsigned long total_forks; + static int last_timestamp = 0; + + /* + * this one can be a serious 'ps' performance problem if + * there are many threads running - thus we do 'lazy' + * link-recalculation - we change it only if the number + * of threads has increased. + */ + if (total_forks != last_timestamp) { + int nlink = proc_root.nlink; + + read_lock(&tasklist_lock); + last_timestamp = total_forks; + for_each_task(p) + nlink++; + read_unlock(&tasklist_lock); + /* + * subtract the # of idle threads which + * do not show up in /proc: + */ + dir->i_nlink = nlink - smp_num_cpus; + } + } + + if (!proc_lookup(dir, dentry)) + return NULL; + + return proc_pid_lookup(dir, dentry); +} + +/* + * This returns non-zero if at EOF, so that the /proc + * root directory can use this and check if it should + * continue with the entries.. + * + * Note that the VFS-layer doesn't care about the return + * value of the readdir() call, as long as it's non-negative + * for success.. + */ +int proc_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + struct proc_dir_entry * de; + unsigned int ino; + int i; + struct inode *inode = filp->f_dentry->d_inode; + + ino = inode->i_ino; + de = (struct proc_dir_entry *) inode->u.generic_ip; + if (!de) + return -EINVAL; + i = filp->f_pos; + switch (i) { + case 0: + if (filldir(dirent, ".", 1, i, ino) < 0) + return 0; + i++; + filp->f_pos++; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0) + return 0; + i++; + filp->f_pos++; + /* fall through */ + default: + de = de->subdir; + i -= 2; + for (;;) { + if (!de) + return 1; + if (!i) + break; + de = de->next; + i--; + } + + do { + if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0) + return 0; + filp->f_pos++; + de = de->next; + } while (de); + } + return 1; +} + +static int proc_root_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + unsigned int nr = filp->f_pos; + + if (nr < FIRST_PROCESS_ENTRY) { + int error = proc_readdir(filp, dirent, filldir); + if (error <= 0) + return error; + filp->f_pos = FIRST_PROCESS_ENTRY; + } + + return proc_pid_readdir(filp, dirent, filldir); +} + +static int proc_unlink(struct inode *dir, struct dentry *dentry) +{ + struct proc_dir_entry * dp = dir->u.generic_ip; + +printk("proc_file_unlink: deleting %s/%s\n", dp->name, dentry->d_name.name); + + remove_proc_entry(dentry->d_name.name, dp); + dentry->d_inode->i_nlink = 0; + d_delete(dentry); + return 0; +} diff -urN 2.3.29pre1/include/asm-alpha/profiler.h 2.3.29pre1-ikd/include/asm-alpha/profiler.h --- 2.3.29pre1/include/asm-alpha/profiler.h Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/asm-alpha/profiler.h Mon Nov 22 16:56:24 1999 @@ -0,0 +1,49 @@ +#ifndef _LINUX_PROFILER_ASM_H +#define _LINUX_PROFILER_ASM_H + +#include + +#ifdef CONFIG_DEBUG_MCOUNT + +/* + * You've got to define two macros if you port the profiling stuff: + */ + +/* + * [kernel stack overflow profiling] + * + * this says how much kernel stack space is >left<. If this goes + * below a certain treshold then we generate an artificial oops. + * + * we do not assume anything about stack growth direction + */ + +/* Dummy for now. Anybody care to supply code to get the stack size on + * an Alpha? KAO */ +#warning No real support for KSTACK on Alpha +#define get_stack_left() 4095 + +/* + * [kernel tracer] + * + * this macro gets fast an accurate time and puts it into a 'u32' + * variable. It's used as a tracer timestamp. + */ + +#ifdef CONFIG_TRACE_TIMESTAMP +#define get_profiler_timestamp() \ + ( { \ + register u32 __res; \ + asm volatile ("rpcc %0" : "r="(__res)); \ + __res; \ + } ) + +/* Always u32, even when CONFIG_TRACE_TRUNCTIME */ +typedef u32 profiler_timestamp_t; +#endif /* CONFIG_TRACE_TIMESTAMP */ + +typedef unsigned long profiler_pc_t; + +#endif /* CONFIG_DEBUG_MCOUNT */ + +#endif /* _LINUX_PROFILER_ASM_H */ diff -urN 2.3.29pre1/include/asm-i386/hw_irq.h 2.3.29pre1-ikd/include/asm-i386/hw_irq.h --- 2.3.29pre1/include/asm-i386/hw_irq.h Thu Nov 11 19:01:05 1999 +++ 2.3.29pre1-ikd/include/asm-i386/hw_irq.h Mon Nov 22 16:56:24 1999 @@ -21,6 +21,9 @@ #define FIRST_EXTERNAL_VECTOR 0x20 #define SYSCALL_VECTOR 0x80 +#if defined(CONFIG_KDB) +#define KDBENTER_VECTOR 0x81 +#endif /* * Vectors 0x20-0x2f are used for ISA interrupts. @@ -36,6 +39,9 @@ #define INVALIDATE_TLB_VECTOR 0x30 #define LOCAL_TIMER_VECTOR 0x31 #define RESCHEDULE_VECTOR 0x40 +#if defined(CONFIG_KDB) +#define KDB_VECTOR 0x42 +#endif /* CONFIG_KDB */ /* 'rare' vectors: */ #define CALL_FUNCTION_VECTOR 0x41 diff -urN 2.3.29pre1/include/asm-i386/keyboard.h 2.3.29pre1-ikd/include/asm-i386/keyboard.h --- 2.3.29pre1/include/asm-i386/keyboard.h Thu Nov 11 18:23:13 1999 +++ 2.3.29pre1-ikd/include/asm-i386/keyboard.h Mon Nov 22 16:56:24 1999 @@ -38,6 +38,9 @@ #define kbd_sysrq_xlate pckbd_sysrq_xlate #define SYSRQ_KEY 0x54 +#if defined(CONFIG_KDB) +#define E1_PAUSE 119 /* PAUSE key */ +#endif /* resource allocation */ #define kbd_request_region() diff -urN 2.3.29pre1/include/asm-i386/pgtable.h 2.3.29pre1-ikd/include/asm-i386/pgtable.h --- 2.3.29pre1/include/asm-i386/pgtable.h Thu Nov 11 18:23:09 1999 +++ 2.3.29pre1-ikd/include/asm-i386/pgtable.h Mon Nov 22 16:56:24 1999 @@ -153,7 +153,11 @@ * The vmalloc() routines leaves a hole of 4kB between each vmalloced * area for the same reason. ;) */ +#ifndef CONFIG_MEMLEAK #define VMALLOC_OFFSET (8*1024*1024) +#else +#define VMALLOC_OFFSET (128*1024*1024) +#endif #define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) #define VMALLOC_END (FIXADDR_START) @@ -322,6 +326,7 @@ * if any. */ +#ifndef CONFIG_MEMLEAK extern __inline__ pgd_t *get_pgd_slow(void) { pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); @@ -403,6 +408,7 @@ #define pgd_free(pgd) free_pgd_slow(pgd) #define pgd_alloc() get_pgd_fast() +#ifndef CONFIG_MEMLEAK extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) { if (!pmd) @@ -445,6 +451,59 @@ __handle_bad_pmd(pmd); return NULL; } +#else /* CONFIG_MEMLEAK */ +#define pte_alloc_kernel(pmd, address) \ +({ \ + pte_t * _ret; \ + unsigned long _address = ((unsigned long)(address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); \ + if (pmd_none(*((pmd_t *)(pmd)))) { \ + pte_t * _page = (pte_t *) get_pte_fast(); \ + if (!_page) { \ + _ret = get_pte_kernel_slow(((pmd_t *)(pmd)), _address); \ + goto out_pte_alloc_kernel; \ + } \ + pmd_val(*((pmd_t *)(pmd))) = _KERNPG_TABLE + __pa(_page); \ + _ret = _page + _address; \ + goto out_pte_alloc_kernel; \ + } \ + if (pmd_bad(*((pmd_t *)(pmd)))) { \ + __bad_pte_kernel(((pmd_t *)(pmd))); \ + _ret = NULL; \ + goto out_pte_alloc_kernel; \ + } \ + _ret = (pte_t *) pmd_page(*((pmd_t *)(pmd))) + _address; \ +out_pte_alloc_kernel: \ + _ret; \ +}) + +#define pte_alloc(pmd, address) \ +({ \ + pte_t *_ret; \ + unsigned long _address = ((unsigned long)(address) >> (PAGE_SHIFT-2)) & 4*(PTRS_PER_PTE - 1); \ + if (pmd_none(*((pmd_t *)(pmd)))) \ + goto getnew; \ + if (pmd_bad(*((pmd_t *)(pmd)))) \ + goto fix; \ + _ret = (pte_t *) (pmd_page(*((pmd_t *)(pmd))) + _address); \ + goto out_pte_alloc; \ +getnew: \ +{ \ + unsigned long _page = (unsigned long) get_pte_fast(); \ + if (!_page) { \ + _ret = get_pte_slow(((pmd_t *)(pmd)), _address); \ + goto out_pte_alloc; \ + } \ + pmd_val(*((pmd_t *)(pmd))) = _PAGE_TABLE + __pa(_page); \ + _ret = (pte_t *) (_page + _address); \ + goto out_pte_alloc; \ +} \ +fix: \ + __bad_pte(((pmd_t *)(pmd))); \ + _ret = NULL; \ +out_pte_alloc: \ + _ret; \ +}) +#endif /* CONFIG_MEMLEAK */ /* * allocating and freeing a pmd is trivial: the 1-entry pmd is diff -urN 2.3.29pre1/include/asm-i386/pgtable.h.orig 2.3.29pre1-ikd/include/asm-i386/pgtable.h.orig --- 2.3.29pre1/include/asm-i386/pgtable.h.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/asm-i386/pgtable.h.orig Thu Nov 11 18:23:09 1999 @@ -0,0 +1,515 @@ +#ifndef _I386_PGTABLE_H +#define _I386_PGTABLE_H + +#include + +/* + * The Linux memory management assumes a three-level page table setup. On + * the i386, we use that, but "fold" the mid level into the top-level page + * table, so that we physically have the same two-level page table as the + * i386 mmu expects. + * + * This file contains the functions and defines necessary to modify and use + * the i386 page table tree. + */ +#ifndef __ASSEMBLY__ +#include +#include +#include + +extern pgd_t swapper_pg_dir[1024]; + +/* Caches aren't brain-dead on the intel. */ +#define flush_cache_all() do { } while (0) +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_range(mm, start, end) do { } while (0) +#define flush_cache_page(vma, vmaddr) do { } while (0) +#define flush_page_to_ram(page) do { } while (0) +#define flush_icache_range(start, end) do { } while (0) + +/* + * TLB flushing: + * + * - flush_tlb() flushes the current mm struct TLBs + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(mm, start, end) flushes a range of pages + * + * ..but the i386 has somewhat limited tlb flushing capabilities, + * and page-granular flushes are available only on i486 and up. + */ + +#define __flush_tlb() \ +do { unsigned long tmpreg; __asm__ __volatile__("movl %%cr3,%0\n\tmovl %0,%%cr3":"=r" (tmpreg) : :"memory"); } while (0) + +#ifndef CONFIG_X86_INVLPG +#define __flush_tlb_one(addr) __flush_tlb() +#else +#define __flush_tlb_one(addr) \ +__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr)) +#endif + +#ifndef __SMP__ + +#define flush_tlb() __flush_tlb() +#define flush_tlb_all() __flush_tlb() +#define local_flush_tlb() __flush_tlb() + +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + if (mm == current->active_mm) + __flush_tlb(); +} + +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + if (vma->vm_mm == current->active_mm) + __flush_tlb_one(addr); +} + +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + if (mm == current->active_mm) + __flush_tlb(); +} + +#else + +/* + * We aren't very clever about this yet - SMP could certainly + * avoid some global flushes.. + */ + +#include + +#define local_flush_tlb() \ + __flush_tlb() + +extern void flush_tlb_all(void); +extern void flush_tlb_current_task(void); +extern void flush_tlb_mm(struct mm_struct *); +extern void flush_tlb_page(struct vm_area_struct *, unsigned long); + +#define flush_tlb() flush_tlb_current_task() + +static inline void flush_tlb_range(struct mm_struct * mm, unsigned long start, unsigned long end) +{ + flush_tlb_mm(mm); +} + +#endif +#endif /* !__ASSEMBLY__ */ + +#define pgd_quicklist (current_cpu_data.pgd_quick) +#define pmd_quicklist (current_cpu_data.pmd_quick) +#define pte_quicklist (current_cpu_data.pte_quick) +#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) + +/* + * The Linux x86 paging architecture is 'compile-time dual-mode', it + * implements both the traditional 2-level x86 page tables and the + * newer 3-level PAE-mode page tables. + */ +#ifndef __ASSEMBLY__ +#if CONFIG_X86_PAE +# include +#else +# include +#endif +#endif + +/* + * Certain architectures need to do special things when PTEs + * within a page table are directly modified. Thus, the following + * hook is made available. + */ +#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) + +#define __beep() asm("movb $0x3,%al; outb %al,$0x61") + +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) + +#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT) +#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS) + +#define TWOLEVEL_PGDIR_SHIFT 22 +#define BOOT_USER_PGD_PTRS (__PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT) +#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS) + + +#ifndef __ASSEMBLY__ +/* Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (FIXADDR_START) + +/* + * The 4MB page is guessing.. Detailed in the infamous "Chapter H" + * of the Pentium details, but assuming intel did the straightforward + * thing, this bit set in the page directory entry just means that + * the page directory entry points directly to a 4MB-aligned block of + * memory. + */ +#define _PAGE_PRESENT 0x001 +#define _PAGE_RW 0x002 +#define _PAGE_USER 0x004 +#define _PAGE_PWT 0x008 +#define _PAGE_PCD 0x010 +#define _PAGE_ACCESSED 0x020 +#define _PAGE_DIRTY 0x040 +#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */ +#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */ + +#define _PAGE_PROTNONE 0x080 /* If not present */ + +#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) + +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED) + +/* + * The i386 can't do page protection for execute, and considers that the same are read. + * Also, write permissions imply read permissions. This is the closest we can get.. + */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED + +/* + * Define this if things work differently on an i386 and an i486: + * it will (on an i486) warn about kernel memory accesses that are + * done without a 'verify_area(VERIFY_WRITE,..)' + */ +#undef TEST_VERIFY_AREA + +/* page table for 0-4MB for everybody */ +extern unsigned long pg0[1024]; + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern unsigned long empty_zero_page[1024]; +#define ZERO_PAGE(vaddr) (mem_map + MAP_NR(empty_zero_page)) + +/* + * Handling allocation failures during page table setup. + */ +extern void __handle_bad_pmd(pmd_t * pmd); +extern void __handle_bad_pmd_kernel(pmd_t * pmd); + +#define pte_none(x) (!pte_val(x)) +#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) +#define pte_clear(xp) do { pte_val(*(xp)) = 0; } while (0) +#define pte_pagenr(x) ((unsigned long)((pte_val(x) >> PAGE_SHIFT))) + +#define pmd_none(x) (!pmd_val(x)) +#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) +#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) +#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) + +/* + * Permanent address of a page. Obviously must never be + * called on a highmem page. + */ +#define page_address(page) ({ if (PageHighMem(page)) BUG(); PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT); }) +#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) +#define pte_page(x) (mem_map+pte_pagenr(x)) + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; } +extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; } +extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } +extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } + +extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; } +extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; } +extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; } +extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } +extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_RW; return pte; } +extern inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; } +extern inline pte_t pte_mkexec(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; } +extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; } +extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; } +extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_RW; return pte; } + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ + +extern inline pte_t mk_pte(struct page *page, pgprot_t pgprot) +{ + pte_t __pte; + + pte_val(__pte) = (page-mem_map)*(unsigned long long)PAGE_SIZE + + pgprot_val(pgprot); + return __pte; +} + +/* This takes a physical page address that is used by the remapping functions */ +#define mk_pte_phys(physpage, pgprot) \ +({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; }) + +extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } + +#define page_pte(page) page_pte_prot(page, __pgprot(0)) + +#define pmd_page(pmd) \ +((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + +/* to find an entry in a page-table-directory. */ +#define __pgd_offset(address) \ + ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) + +#define pgd_offset(mm, address) ((mm)->pgd+__pgd_offset(address)) + +/* to find an entry in a kernel page-table-directory */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +#define __pmd_offset(address) \ + (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) + +/* Find an entry in the third-level page table.. */ +#define __pte_offset(address) \ + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset(dir, address) ((pte_t *) pmd_page(*(dir)) + \ + __pte_offset(address)) + +/* + * Allocate and free page tables. The xxx_kernel() versions are + * used to allocate a kernel page table - this turns on ASN bits + * if any. + */ + +extern __inline__ pgd_t *get_pgd_slow(void) +{ + pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); + + if (ret) { +#if 0 + /* + * On PAE allocating a whole page is overkill - we will + * either embedd this in mm_struct, or do a SLAB cache. + */ + memcpy(ret, swapper_pg_dir, PTRS_PER_PGD * sizeof(pgd_t)); +#endif +#if CONFIG_X86_PAE + int i; + for (i = 0; i < USER_PTRS_PER_PGD; i++) + __pgd_clear(ret + i); +#else + memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); +#endif + memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + } + return ret; +} + +extern __inline__ pgd_t *get_pgd_fast(void) +{ + unsigned long *ret; + + if ((ret = pgd_quicklist) != NULL) { + pgd_quicklist = (unsigned long *)(*ret); + ret[0] = 0; + pgtable_cache_size--; + } else + ret = (unsigned long *)get_pgd_slow(); + return (pgd_t *)ret; +} + +extern __inline__ void free_pgd_fast(pgd_t *pgd) +{ + *(unsigned long *)pgd = (unsigned long) pgd_quicklist; + pgd_quicklist = (unsigned long *) pgd; + pgtable_cache_size++; +} + +extern __inline__ void free_pgd_slow(pgd_t *pgd) +{ + free_page((unsigned long)pgd); +} + +extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); +extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); + +extern __inline__ pte_t *get_pte_fast(void) +{ + unsigned long *ret; + + if((ret = (unsigned long *)pte_quicklist) != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pte_t *)ret; +} + +extern __inline__ void free_pte_fast(pte_t *pte) +{ + *(unsigned long *)pte = (unsigned long) pte_quicklist; + pte_quicklist = (unsigned long *) pte; + pgtable_cache_size++; +} + +extern __inline__ void free_pte_slow(pte_t *pte) +{ + free_page((unsigned long)pte); +} + +#define pte_free_kernel(pte) free_pte_slow(pte) +#define pte_free(pte) free_pte_slow(pte) +#define pgd_free(pgd) free_pgd_slow(pgd) +#define pgd_alloc() get_pgd_fast() + +extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) +{ + if (!pmd) + BUG(); + address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + if (pmd_none(*pmd)) { + pte_t * page = (pte_t *) get_pte_fast(); + + if (!page) + return get_pte_kernel_slow(pmd, address); + pmd_val(*pmd) = _KERNPG_TABLE + __pa(page); + return page + address; + } + if (pmd_bad(*pmd)) { + __handle_bad_pmd_kernel(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + address; +} + +extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address) +{ + address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + + if (pmd_none(*pmd)) + goto getnew; + if (pmd_bad(*pmd)) + goto fix; + return (pte_t *)pmd_page(*pmd) + address; +getnew: +{ + unsigned long page = (unsigned long) get_pte_fast(); + + if (!page) + return get_pte_slow(pmd, address); + pmd_val(*pmd) = _PAGE_TABLE + __pa(page); + return (pte_t *)page + address; +} +fix: + __handle_bad_pmd(pmd); + return NULL; +} + +/* + * allocating and freeing a pmd is trivial: the 1-entry pmd is + * inside the pgd, so has no extra memory associated with it. + * (In the PAE case we free the page.) + */ +#define pmd_free(pmd) free_pmd_slow(pmd) + +#define pmd_free_kernel pmd_free +#define pmd_alloc_kernel pmd_alloc + +extern int do_check_pgt_cache(int, int); + +extern inline void set_pgdir(unsigned long address, pgd_t entry) +{ + struct task_struct * p; + pgd_t *pgd; +#ifdef __SMP__ + int i; +#endif + + read_lock(&tasklist_lock); + for_each_task(p) { + if (!p->mm) + continue; + *pgd_offset(p->mm,address) = entry; + } + read_unlock(&tasklist_lock); +#ifndef __SMP__ + for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; +#else + /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can + modify pgd caches of other CPUs as well. -jj */ + for (i = 0; i < NR_CPUS; i++) + for (pgd = (pgd_t *)cpu_data[i].pgd_quick; pgd; pgd = (pgd_t *)*(unsigned long *)pgd) + pgd[address >> PGDIR_SHIFT] = entry; +#endif +} + +/* + * The i386 doesn't have any external MMU info: the kernel page + * tables contain all the necessary information. + */ +extern inline void update_mmu_cache(struct vm_area_struct * vma, + unsigned long address, pte_t pte) +{ +} + +/* Encode and de-code a swap entry */ +#define SWP_TYPE(x) (((x).val >> 1) & 0x3f) +#define SWP_OFFSET(x) ((x).val >> 8) +#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val }) + +#define module_map vmalloc +#define module_unmap vfree + +#endif /* !__ASSEMBLY__ */ + +/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ +#define PageSkip(page) (0) +#define kern_addr_valid(addr) (1) + +#define io_remap_page_range remap_page_range + +#endif /* _I386_PGTABLE_H */ diff -urN 2.3.29pre1/include/asm-i386/pgtable.h.rej 2.3.29pre1-ikd/include/asm-i386/pgtable.h.rej --- 2.3.29pre1/include/asm-i386/pgtable.h.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/asm-i386/pgtable.h.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,128 @@ +*************** +*** 379,384 **** + free_page((unsigned long)pte); + } + + /* We don't use pmd cache, so these are dummy routines */ + extern __inline__ pmd_t *get_pmd_fast(void) + { +--- 384,502 ---- + free_page((unsigned long)pte); + } + ++ #else /* CONFIG_MEMLEAK */ ++ ++ #define get_pgd_slow() \ ++ ({ \ ++ pgd_t *_ret = (pgd_t *) __get_free_page(GFP_KERNEL); \ ++ if (_ret) { \ ++ memset (_ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); \ ++ memcpy (_ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, \ ++ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); \ ++ } \ ++ _ret; \ ++ }) ++ ++ #define get_pgd_fast() \ ++ ({ \ ++ unsigned long *_ret; \ ++ if((_ret = pgd_quicklist) != NULL) { \ ++ pgd_quicklist = (unsigned long *)(*_ret); \ ++ _ret[0] = 0; \ ++ pgtable_cache_size--; \ ++ } else \ ++ _ret = (unsigned long *)get_pgd_slow(); \ ++ (pgd_t *)_ret; \ ++ }) ++ ++ #define free_pgd_fast(pgd) \ ++ ({ \ ++ *(unsigned long *)(pgd) = (unsigned long) pgd_quicklist; \ ++ pgd_quicklist = (unsigned long *) (pgd); \ ++ pgtable_cache_size++; \ ++ }) ++ ++ #define free_pgd_slow(pgd) \ ++ ({ \ ++ free_page((unsigned long)(pgd)); \ ++ }) ++ ++ #define get_pte_slow(pmd, offset) \ ++ ({ \ ++ pte_t *_ret; \ ++ unsigned long _pte = (unsigned long) __get_free_page(GFP_KERNEL); \ ++ if (pmd_none(*((pmd_t *)(pmd)))) { \ ++ if (_pte) { \ ++ clear_page(_pte); \ ++ pmd_val(*((pmd_t *)(pmd))) = _PAGE_TABLE + __pa(_pte); \ ++ _ret = (pte_t *)(_pte + (unsigned long)(offset)); \ ++ goto out_get_pte_slow; \ ++ } \ ++ pmd_val(*((pmd_t *)(pmd))) = _PAGE_TABLE + __pa(BAD_PAGETABLE); \ ++ _ret = NULL; \ ++ goto out_get_pte_slow; \ ++ } \ ++ free_page(_pte); \ ++ if (pmd_bad(*((pmd_t *)(pmd)))) { \ ++ __bad_pte((pmd_t *)(pmd)); \ ++ _ret = NULL; \ ++ goto out_get_pte_slow; \ ++ } \ ++ _ret = (pte_t *) (pmd_page(*((pmd_t *)(pmd))) + (unsigned long)(offset)); \ ++ out_get_pte_slow: \ ++ _ret; \ ++ }) ++ ++ #define get_pte_kernel_slow(pmd, offset) \ ++ ({ \ ++ pte_t *_ret, *_pte = (pte_t *) __get_free_page(GFP_KERNEL); \ ++ if (pmd_none(*((pmd_t *)(pmd)))) { \ ++ if (_pte) { \ ++ clear_page((unsigned long)_pte); \ ++ pmd_val(*((pmd_t *)(pmd))) = _KERNPG_TABLE + __pa(_pte); \ ++ _ret = _pte + (unsigned long)(offset); \ ++ goto out_get_pte_kernel_slow; \ ++ } \ ++ pmd_val(*((pmd_t *)(pmd))) = _KERNPG_TABLE + __pa(BAD_PAGETABLE); \ ++ _ret = NULL; \ ++ goto out_get_pte_kernel_slow; \ ++ } \ ++ free_page((unsigned long)_pte); \ ++ if (pmd_bad(*((pmd_t *)(pmd)))) { \ ++ __bad_pte_kernel((pmd_t *)(pmd)); \ ++ _ret = NULL; \ ++ goto out_get_pte_kernel_slow; \ ++ } \ ++ _ret = (pte_t *)(pmd_page(*((pmd_t *)(pmd))) + (unsigned long)(offset)); \ ++ out_get_pte_kernel_slow: \ ++ _ret; \ ++ }) ++ ++ #define get_pte_fast() \ ++ ({ \ ++ unsigned long *_ret; \ ++ if((_ret = (unsigned long *)pte_quicklist) != NULL) { \ ++ pte_quicklist = (unsigned long *)(*_ret); \ ++ _ret[0] = _ret[1]; \ ++ pgtable_cache_size--; \ ++ } \ ++ (pte_t *)_ret; \ ++ }) ++ ++ #define free_pte_fast(pte) \ ++ ({ \ ++ *(unsigned long *)(pte) = (unsigned long) pte_quicklist; \ ++ pte_quicklist = (unsigned long *) (pte); \ ++ pgtable_cache_size++; \ ++ }) ++ ++ #define free_pte_slow(pte) \ ++ ({ \ ++ free_page((unsigned long)(pte)); \ ++ }) ++ ++ #endif /* CONFIG_MEMLEAK */ ++ + /* We don't use pmd cache, so these are dummy routines */ + extern __inline__ pmd_t *get_pmd_fast(void) + { diff -urN 2.3.29pre1/include/asm-i386/profiler.h 2.3.29pre1-ikd/include/asm-i386/profiler.h --- 2.3.29pre1/include/asm-i386/profiler.h Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/asm-i386/profiler.h Mon Nov 22 16:56:24 1999 @@ -0,0 +1,61 @@ +#ifndef _LINUX_PROFILER_ASM_H +#define _LINUX_PROFILER_ASM_H + +#include + +#ifdef CONFIG_DEBUG_MCOUNT + +/* + * You've got to define two macros if you port the profiling stuff: + */ + +/* + * [kernel stack overflow profiling] + * + * this says how much kernel stack space is >left<. If this goes + * below a certain treshold then we generate an artificial oops. + * + * we do not assume anything about stack growth direction + */ + +#define get_stack_left() \ +({ register unsigned long __res; \ + __asm__("movl %%esp, %0" : "=r" (__res)); \ + __res & 0x1fff; \ +}) + +/* + * [kernel tracer] + * + * this macro gets fast an accurate time and puts it into a 'long long' + * variable. It's used as a tracer timestamp. + */ + +#ifdef CONFIG_TRACE_TIMESTAMP +#define get_profiler_timestamp() \ + ( { \ + register u64 __res; \ + if (boot_cpu_data.x86_capability & 0x10) { \ + __asm__ __volatile__( \ + "rdtsc" : "=A"(__res) \ + ); \ + } \ + else { \ + /* no rdtsc, use jiffies instead */ \ + __res = jiffies; \ + } \ + __res; \ + } ) + +#ifdef CONFIG_TRACE_TRUNCTIME +typedef u32 profiler_timestamp_t; +#else +typedef u64 profiler_timestamp_t; +#endif /* CONFIG_TRACE_TRUNCTIME */ +#endif /* CONFIG_TRACE_TIMESTAMP */ + +typedef unsigned long profiler_pc_t; + +#endif /* CONFIG_DEBUG_MCOUNT */ + +#endif /* _LINUX_PROFILER_ASM_H */ diff -urN 2.3.29pre1/include/asm-i386/ptrace.h 2.3.29pre1-ikd/include/asm-i386/ptrace.h --- 2.3.29pre1/include/asm-i386/ptrace.h Mon Jan 18 02:27:15 1999 +++ 2.3.29pre1-ikd/include/asm-i386/ptrace.h Mon Nov 22 16:56:24 1999 @@ -47,6 +47,29 @@ #define PTRACE_GETFPREGS 14 #define PTRACE_SETFPREGS 15 +enum EFLAGS { + EF_CF = 0x00000001, + EF_PF = 0x00000004, + EF_AF = 0x00000010, + EF_ZF = 0x00000040, + EF_SF = 0x00000080, + EF_TF = 0x00000100, + EF_IE = 0x00000200, + EF_DF = 0x00000400, + EF_OF = 0x00000800, + EF_IOPL = 0x00003000, + EF_IOPL_RING0 = 0x00000000, + EF_IOPL_RING1 = 0x00001000, + EF_IOPL_RING2 = 0x00002000, + EF_NT = 0x00004000, // nested task + EF_RF = 0x00010000, // resume + EF_VM = 0x00020000, // virtual mode + EF_AC = 0x00040000, // alignment + EF_VIF = 0x00080000, // virtual interrupt + EF_VIP = 0x00100000, // virtual interrupt pending + EF_ID = 0x00200000, // id +}; + #ifdef __KERNEL__ #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define instruction_pointer(regs) ((regs)->eip) diff -urN 2.3.29pre1/include/asm-i386/system.h 2.3.29pre1-ikd/include/asm-i386/system.h --- 2.3.29pre1/include/asm-i386/system.h Thu Nov 11 18:23:09 1999 +++ 2.3.29pre1-ikd/include/asm-i386/system.h Mon Nov 22 16:56:24 1999 @@ -7,9 +7,38 @@ #ifdef __KERNEL__ struct task_struct; /* one of the stranger aspects of C forward declarations.. */ + +#include +#ifndef CONFIG_KERNEL_DEBUGGING /* Fix the FASTCALL thing -Andrea */ extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); +#else +extern void STDCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); +#endif #define prepare_to_switch() do { } while(0) +#ifdef CONFIG_KERNEL_DEBUGGING /* we can' t use FASTCALL -Andrea */ +#define switch_to(prev,next,last) do { \ + asm volatile("pushl %%esi\n\t" \ + "pushl %%edi\n\t" \ + "pushl %%ebp\n\t" \ + "movl %%esp,%0\n\t" /* save ESP */ \ + "movl %3,%%esp\n\t" /* restore ESP */ \ + "movl $1f,%1\n\t" /* save EIP */ \ + "pushl %6\n\t" /* pass args throught the stack */ \ + "pushl %5\n\t" /* pass args throught the stack */ \ + "pushl %4\n\t" /* restore EIP */ \ + "jmp __switch_to\n" \ + "1:\t" \ + "popl %%ebp\n\t" \ + "popl %%edi\n\t" \ + "popl %%esi\n\t" \ + :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \ + "=b" (last) \ + :"m" (next->thread.esp),"m" (next->thread.eip), \ + "a" (prev), "d" (next), \ + "b" (prev)); \ +} while (0) +#else /* original */ #define switch_to(prev,next,last) do { \ asm volatile("pushl %%esi\n\t" \ "pushl %%edi\n\t" \ @@ -29,6 +58,7 @@ "a" (prev), "d" (next), \ "b" (prev)); \ } while (0) +#endif #define _set_base(addr,base) do { unsigned long __pr; \ __asm__ __volatile__ ("movw %%dx,%1\n\t" \ diff -urN 2.3.29pre1/include/linux/kdb.h 2.3.29pre1-ikd/include/linux/kdb.h --- 2.3.29pre1/include/linux/kdb.h Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/kdb.h Mon Nov 22 16:56:24 1999 @@ -0,0 +1,177 @@ +/* + * Kernel Debugger + * + * Copyright 1999, Silicon Graphics, Inc. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + */ + +#if !defined(__KDB_H) +#define __KDB_H + +#include "bfd.h" + +#define KDB_MAJOR_VERSION 0 +#define KDB_MINOR_VERSION 5 + +/* + * Kernel Debugger Error codes + */ + +#define KDB_NOTFOUND -1 +#define KDB_GO -2 +#define KDB_ARGCOUNT -3 +#define KDB_BADWIDTH -4 +#define KDB_BADRADIX -5 +#define KDB_NOTENV -6 +#define KDB_NOENVVALUE -7 +#define KDB_NOTIMP -8 +#define KDB_ENVFULL -9 +#define KDB_ENVBUFFULL -10 +#define KDB_TOOMANYBPT -11 +#define KDB_TOOMANYDBREGS -12 +#define KDB_DUPBPT -13 +#define KDB_BPTNOTFOUND -14 +#define KDB_BADMODE -15 +#define KDB_BADINT -16 +#define KDB_INVADDRFMT -17 +#define KDB_BADREG -18 +#define KDB_CPUSWITCH -19 +#define KDB_BADCPUNUM -20 +#define KDB_BADLENGTH -21 +#define KDB_NOBP -22 + + /* + * XXX - machine dependent. + */ +#define KDB_ENTER() asm("\tint $129\n") + + /* + * kdb_active is initialized to zero, and is set + * to KDB_REASON_xxx whenever the kernel debugger is entered. + */ +extern int kdb_active; + + /* + * KDB_FLAG_EARLYKDB is set when the 'kdb' option is specified + * as a boot parameter (e.g. via lilo). It indicates that the + * kernel debugger should be entered as soon as practical. + */ +#define KDB_FLAG_EARLYKDB 0x00000001 + /* + * KDB_FLAG_SSB is set when the 'ssb' command is in progress. It + * indicates to the debug fault trap code that a trace fault + * (single step) should be continued rather than the debugger + * be entered. + */ +#define KDB_FLAG_SSB 0x00000002 + /* + * KDB_FLAG_SUPRESS is set when an error message is printed + * by a helper function such as kdbgetword. No further error messages + * will be printed until this flag is reset. Used to prevent + * an illegal address from causing voluminous error messages. + */ +#define KDB_FLAG_SUPRESS 0x00000004 + /* + * KDB_FLAG_FAULT is set when handling a debug register instruction + * fault. The backtrace code needs to know. + */ +#define KDB_FLAG_FAULT 0x00000008 + +extern int kdb_flags; + +extern int kdb_nextline; + + /* + * External entry point for the kernel debugger. The pt_regs + * at the time of entry are supplied along with the reason for + * entry to the kernel debugger. + */ + +struct pt_regs; +extern int kdb(int reason, int error_code, struct pt_regs *); +#define KDB_REASON_ENTER 1 /* call debugger from source */ +#define KDB_REASON_FAULT 2 /* called from fault, eframe valid */ +#define KDB_REASON_BREAK 3 /* called from int 3, eframe valid */ +#define KDB_REASON_DEBUG 4 /* Called from int #DB, eframe valid */ +#define KDB_REASON_PANIC 5 /* Called from panic(), eframe valid */ +#define KDB_REASON_SWITCH 6 /* Called via CPU switch */ +#define KDB_REASON_INT 7 /* Called via int 129 */ +#define KDB_REASON_KEYBOARD 8 /* Called via keyboard interrupt */ + + /* + * The entire contents of this file from this point forward are + * private to the kernel debugger. They are subject to change + * without notice. + */ + + /* + * Breakpoint state + */ + +typedef struct _kdb_bp { + bfd_vma bp_addr; /* Address breakpoint is present at */ + unsigned char bp_prevbyte; /* Byte which the int3 replaced */ + + unsigned int bp_regtype:1; /* Uses a debug register (0-4) */ + unsigned int bp_enabled:1; /* Breakpoint is active in register */ + unsigned int bp_global:1; /* Global to all processors */ + unsigned int bp_free:1; /* This entry is available */ + unsigned int bp_data:1; /* Data breakpoint */ + unsigned int bp_write:1; /* Write data breakpoint */ + unsigned int bp_mode:2; /* 0=inst, 1=write, 2=io, 3=read */ + unsigned int bp_length:2; /* 0=1 byte, 1=2 bytes, 2=BAD, 3=4 */ + + int bp_reg; /* Register that this breakpoint uses */ + int bp_cpu; /* Cpu # (if bp_global == 0) */ +} kdb_bp_t; + +extern void kdb_global(int); /* Set global actions */ + + /* + * External Function Declarations + */ +extern char *kdbgetenv(const char *); +extern int kdbgetintenv(const char *, int *); +extern int kdbgetularg(const char *, unsigned long *); +extern int kdbgetaddrarg(int, const char**, int*, unsigned long *, long *, char **, struct pt_regs *); +extern unsigned long kdbgetword(unsigned long, int); +extern void kdb_id1(unsigned long); +extern void kdb_disinit(void); + + + /* + * External command function declarations + */ + +extern int kdb_id (int argc, const char **argv, const char **envp, struct pt_regs *); +extern int kdb_bp (int argc, const char **argv, const char **envp, struct pt_regs *); +extern int kdb_bc (int argc, const char **argv, const char **envp, struct pt_regs *); +extern int kdb_bt (int argc, const char **argv, const char **envp, struct pt_regs *); +extern int kdb_ss (int argc, const char **argv, const char **envp, struct pt_regs *); + + /* + * Symbol table format + */ + +typedef struct __symtab { + char *name; + unsigned long value; + } __ksymtab_t; + +extern __ksymtab_t __kdbsymtab[]; +extern int __kdbsymtabsize; +extern int __kdbmaxsymtabsize; + +extern unsigned long kdbgetsymval(const char *); +extern char * kdbnearsym(unsigned long); +extern int kdbaddmodsym(char *, unsigned long); +extern int kdbdelmodsym(const char *); + +typedef int (*kdb_func)(int, const char **, const char **, struct pt_regs*); + +extern int kdb_register(char *, kdb_func, char *, char *, short); +extern int kdb_unregister(char *); + +extern int kdb_printf(const char *,...); +#endif /* __KDB_H */ diff -urN 2.3.29pre1/include/linux/kernel.h 2.3.29pre1-ikd/include/linux/kernel.h --- 2.3.29pre1/include/linux/kernel.h Tue Oct 26 21:30:51 1999 +++ 2.3.29pre1-ikd/include/linux/kernel.h Mon Nov 22 16:56:24 1999 @@ -8,6 +8,7 @@ #ifdef __KERNEL__ #include +#include #include /* Optimization barrier */ @@ -19,7 +20,11 @@ #define LONG_MAX ((long)(~0UL>>1)) #define ULONG_MAX (~0UL) -#define STACK_MAGIC 0xdeadbeef +#if BITS_PER_LONG < 64 +# define STACK_MAGIC 0xdeadbeef +#else +# define STACK_MAGIC 0xfeedbabedeadbeef +#endif #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -36,10 +41,12 @@ # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, -#ifdef __i386__ +#if defined(__i386__) && !defined(CONFIG_KERNEL_DEBUGGING) #define FASTCALL(x) x __attribute__((regparm(3))) +#define STDCALL(x) x #else #define FASTCALL(x) x +#define STDCALL(x) __attribute__((stdcall)) x #endif extern void math_error(void); diff -urN 2.3.29pre1/include/linux/memleak_unwrap.h 2.3.29pre1-ikd/include/linux/memleak_unwrap.h --- 2.3.29pre1/include/linux/memleak_unwrap.h Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/memleak_unwrap.h Mon Nov 22 16:56:24 1999 @@ -0,0 +1,93 @@ +#ifndef _MM_UNWRAP_H +#define _MM_UNWRAP_H + +#include + +#ifdef CONFIG_MEMLEAK + +#ifdef MEMLEAK_UNWRAP_PAGE +/* mm/page_alloc.c */ +#undef __get_free_pages +#define __get_free_pages(gfp_mask,gfporder) \ + __get_free_pages_wrap((gfp_mask),(gfporder),IDPTR) +#endif /* MEMLEAK_UNWRAP_PAGE */ + +#ifdef MEMLEAK_UNWRAP_SLAB +/* mm/slab.c */ +/* + * NOTE: leave kmem_cache_create wrapped, as otherwise the allocation + * id won't exist for the underlying allocator. Other functions + * which lead to a physical allocation must also pass this id. + * This looks ugly, but causes ownership of the allocation to be + * passed on to the allocation initiator. + * + * freeing of the allocation is the responsibility of the underlying + * allocator. I hope that this helps to keep memleak in sync. + */ + +#undef kmem_cache_alloc +#undef kmalloc + +#define kmem_cache_alloc(cachep,flags) \ + kmem_cache_alloc_wrap((cachep),(flags),IDPTR) + +#define kmalloc(size,priority) \ + kmalloc_wrap((size),(priority),IDPTR) + +#define kmem_cache_grow(cachep,flags) \ + kmem_cache_grow_wrap((cachep),(flags),IDPTR) + +#define __kmem_cache_alloc(cachep,flags) \ + __kmem_cache_alloc_wrap((cachep),(flags),IDPTR) + +#define kmem_cache_slabmgmt(cachep,objp,local_flags) \ + kmem_cache_slabmgmt_wrap((cachep),(objp),(local_flags),IDPTR) +#endif /* MEMLEAK_UNWRAP_SLAB */ + +#ifdef MEMLEAK_UNWRAP_VMALLOC +/* mm/vmalloc.c */ +#undef vmalloc +#undef get_vm_area +#undef alloc_area_pte +#undef alloc_area_pmd +#undef vmalloc_area_pages + +#define get_vm_area(size) get_vm_area_wrap((size),IDPTR) +#define alloc_area_pte(pte, address, size) alloc_area_pte_wrap((pte),(address),(size),IDPTR) +#define alloc_area_pmd(pmd, address, size) alloc_area_pmd_wrap((pmd),(address),(size),IDPTR) +#define vmalloc_area_pages(address, size) vmalloc_area_pages_wrap((address),(size),IDPTR) +#endif /* MEMLEAK_UNWRAP_VMALLOC */ + +#ifdef MEMLEAK_UNWRAP_SKBUFF +/* net/core/skbuff.c */ +#undef alloc_skb +#undef skb_clone +#undef skb_copy +#undef skb_realloc_headroom + +#define alloc_skb(size,gfp_mask) alloc_skb_wrap((size),(gfp_mask),IDPTR) +#define skb_clone(skb,gfp_mask) skb_clone_wrap((skb),(gfp_mask),IDPTR) +#define skb_copy(skb,gfp_mask) skb_copy_wrap((skb),(gfp_mask),IDPTR) +#define skb_realloc_headroom(skb,newheadroom) skb_realloc_headroom_wrap((skb),(newheadroom),IDPTR) +#endif /* MEMLEAK_UNWRAP_SKBUFF */ + +#ifdef MEMLEAK_UNWRAP_SOCK +/* net/core/sock.c */ +#undef sock_wmalloc +#undef sock_rmalloc +#undef sock_kmalloc +#undef sk_alloc + +#define sock_wmalloc(sk,size,force,priority) sock_wmalloc_wrap((sk),(size),(force),(priority),IDPTR) +#define sock_rmalloc(sk,size,force,priority) sock_rmalloc_wrap((sk),(size),(force),(priority),IDPTR) +#define sock_kmalloc(sk,size,priority) sock_kmalloc_wrap((sk),(size),(priority),IDPTR) +#define sk_alloc(family,priority,zero_it) sk_alloc_wrap((family),(priority),(zero_it),IDPTR) + +/* include/net/sock.h */ +#undef sock_alloc_send_skb +#define sock_alloc_send_skb(sk,size,fallback,noblock,errcode) \ + sock_alloc_send_skb_wrap((sk),(size),(fallback),(noblock),(errcode),IDPTR) +#endif /* MEMLEAK_UNWRAP_SOCK */ + +#endif /* CONFIG_MEMLEAK */ +#endif /* _MM_UNWRAP_H */ diff -urN 2.3.29pre1/include/linux/mm.h 2.3.29pre1-ikd/include/linux/mm.h --- 2.3.29pre1/include/linux/mm.h Mon Nov 22 03:55:33 1999 +++ 2.3.29pre1-ikd/include/linux/mm.h Mon Nov 22 16:56:24 1999 @@ -291,6 +291,7 @@ * return virtual kernel addresses to the allocated page(s), the * alloc_page*() variants return 'struct page *'. */ +#ifndef CONFIG_MEMLEAK #define __get_free_page(gfp_mask) __get_free_pages((gfp_mask),0) #define __get_dma_pages(gfp_mask, order) __get_free_pages((gfp_mask) | GFP_DMA,(order)) extern unsigned long FASTCALL(__get_free_pages(int gfp_mask, unsigned long order)); @@ -306,6 +307,101 @@ clear_page((void *)page); return page; } + +#define MEMLEAK_ALLOC(addr) {} +#define MEMLEAK_FREE(addr) {} +#define MEMLEAK_ALLOC_NOLOCK(addr) {} +#define MEMLEAK_FREE_TRUE(expr,addr) {} + +#else +/* + * 'allocation identifier' for memleak detection + */ +struct alloc_struct { + int id; + char *file; + int line; +}; + +#define MEMLEAK_WRAP(x,y...) \ +({ \ + static struct alloc_struct MEMLEAKID = { 0, __FILE__, __LINE__ }; \ + x##_wrap(y,&MEMLEAKID); \ +}) + +extern unsigned long memleak_init (unsigned long, unsigned long); +extern int alloc_addr_lock(unsigned long, struct alloc_struct *); +extern int alloc_addr_nolock(unsigned long, struct alloc_struct *); +extern int free_addr(unsigned long); + +#define MEMLEAK_PARANOID 1 +#ifdef MEMLEAK_PARANOID +#define PROBLEM() printk(KERN_ERR "MEMLEAK PROBLEM: <%s,%d>.\n",__FILE__,__LINE__) +#else +#define PROBLEM() {} +#endif /* MEMLEAK_PARANOID */ + +extern unsigned long FASTCALL(__get_free_pages_wrap(int gfp_mask, + unsigned long gfporder, struct alloc_struct *IDPTR)); + +#ifndef MEMLEAK_PASS_ALLOCATION +/* These are for use externally to an allocator. All allocators pass a + * pointer down the stack and map the allocation from inside the alocator, + * and under it's locking mechanism. + */ +#define MEMLEAK_ALLOC(addr) \ +({ \ + if(alloc_addr_lock((unsigned long)(addr),&MEMLEAKID)) \ + PROBLEM(); \ +}) +#else +#define MEMLEAK_ALLOC(addr) \ +({ \ + if(alloc_addr_lock((unsigned long)(addr),IDPTR)) \ + PROBLEM(); \ +}) +#define MEMLEAK_ALLOC_NOLOCK(addr) \ +({ \ + if(alloc_addr_nolock((unsigned long)(addr),IDPTR)) \ + PROBLEM(); \ +}) +#endif /* MEMLEAK_PASS_ALLOCATION */ + +#define MEMLEAK_FREE(addr) \ +({ \ + if(free_addr((unsigned long)(addr))) \ + PROBLEM(); \ +}) +#define MEMLEAK_FREE_TRUE(expr,addr) \ +({ \ + if((expr)) \ + MEMLEAK_FREE((addr)); \ +}) + +/* + * Sometimes, it is useful to disable memleak mapping for a specific file. + * In this case, define MEMLEAK_KILL_ALLOCATION in that file. + */ +#ifndef MEMLEAK_KILL_ALLOCATION +#define __get_free_pages(gfp_mask,gfporder) \ + MEMLEAK_WRAP(__get_free_pages,gfp_mask,gfporder) +#else +#define __get_free_pages(gfp_mask,gfporder) \ + __get_free_pages_wrap((gfp_mask),(gfporder),NULL) +#endif + +#define get_free_page(gfp_mask) \ +({ \ + unsigned long _page; \ + _page = __get_free_pages((gfp_mask),0); \ + if (_page) \ + memset((void *) _page, 0, PAGE_SIZE); \ + _page; \ +}) + +#define __get_free_page(gfp_mask) __get_free_pages((gfp_mask),0) +#define __get_dma_pages(gfp_mask, order) __get_free_pages(((gfp_mask) | GFP_DMA),(order)) +#endif /* CONFIG_MEMLEAK */ /* * The old interface name will be removed in 2.5: diff -urN 2.3.29pre1/include/linux/mm.h.orig 2.3.29pre1-ikd/include/linux/mm.h.orig --- 2.3.29pre1/include/linux/mm.h.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/mm.h.orig Mon Nov 22 03:55:33 1999 @@ -0,0 +1,453 @@ +#ifndef _LINUX_MM_H +#define _LINUX_MM_H + +#include +#include + +#ifdef __KERNEL__ + +#include +#include +#include + +extern unsigned long max_mapnr; +extern unsigned long num_physpages; +extern void * high_memory; +extern int page_cluster; + +#include +#include + +/* + * Linux kernel virtual memory manager primitives. + * The idea being to have a "virtual" mm in the same way + * we have a virtual fs - giving a cleaner interface to the + * mm details, and allowing different kinds of memory mappings + * (from shared memory to executable loading to arbitrary + * mmap() functions). + */ + +/* + * This struct defines a memory VMM memory area. There is one of these + * per VM-area/task. A VM area is any part of the process virtual memory + * space that has a special rule for the page-fault handlers (ie a shared + * library, the executable area etc). + */ +struct vm_area_struct { + struct mm_struct * vm_mm; /* VM area parameters */ + unsigned long vm_start; + unsigned long vm_end; + + /* linked list of VM areas per task, sorted by address */ + struct vm_area_struct *vm_next; + + pgprot_t vm_page_prot; + unsigned short vm_flags; + + /* AVL tree of VM areas per task, sorted by address */ + short vm_avl_height; + struct vm_area_struct * vm_avl_left; + struct vm_area_struct * vm_avl_right; + + /* For areas with inode, the list inode->i_mmap, for shm areas, + * the list of attaches, otherwise unused. + */ + struct vm_area_struct *vm_next_share; + struct vm_area_struct **vm_pprev_share; + + struct vm_operations_struct * vm_ops; + unsigned long vm_pgoff; /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */ + struct file * vm_file; + void * vm_private_data; /* was vm_pte (shared mem) */ +}; + +/* + * vm_flags.. + */ +#define VM_READ 0x0001 /* currently active flags */ +#define VM_WRITE 0x0002 +#define VM_EXEC 0x0004 +#define VM_SHARED 0x0008 + +#define VM_MAYREAD 0x0010 /* limits for mprotect() etc */ +#define VM_MAYWRITE 0x0020 +#define VM_MAYEXEC 0x0040 +#define VM_MAYSHARE 0x0080 + +#define VM_GROWSDOWN 0x0100 /* general info on the segment */ +#define VM_GROWSUP 0x0200 +#define VM_SHM 0x0400 /* shared memory area, don't swap out */ +#define VM_DENYWRITE 0x0800 /* ETXTBSY on write attempts.. */ + +#define VM_EXECUTABLE 0x1000 +#define VM_LOCKED 0x2000 +#define VM_IO 0x4000 /* Memory mapped I/O or similar */ + +#define VM_STACK_FLAGS 0x0177 + +/* + * mapping from the currently active vm_flags protection bits (the + * low four bits) to a page protection mask.. + */ +extern pgprot_t protection_map[16]; + + +/* + * These are the virtual MM functions - opening of an area, closing and + * unmapping it (needed to keep files on disk up-to-date etc), pointer + * to the functions called when a no-page or a wp-page exception occurs. + */ +struct vm_operations_struct { + void (*open)(struct vm_area_struct * area); + void (*close)(struct vm_area_struct * area); + void (*unmap)(struct vm_area_struct *area, unsigned long, size_t); + void (*protect)(struct vm_area_struct *area, unsigned long, size_t, unsigned int newprot); + int (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags); + void (*advise)(struct vm_area_struct *area, unsigned long, size_t, unsigned int advise); + struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int write_access); + struct page * (*wppage)(struct vm_area_struct * area, unsigned long address, struct page * page); + int (*swapout)(struct page *, struct file *); +}; + +/* + * A swap entry has to fit into a "unsigned long", as + * the entry is hidden in the "index" field of the + * swapper address space. + */ +typedef struct { + unsigned long val; +} swp_entry_t; + +/* + * Try to keep the most commonly accessed fields in single cache lines + * here (16 bytes or greater). This ordering should be particularly + * beneficial on 32-bit processors. + * + * The first line is data used in page cache lookup, the second line + * is used for linear searches (eg. clock algorithm scans). + */ +typedef struct page { + /* these must be first (free area handling) */ + struct list_head list; + struct address_space *mapping; + unsigned long index; + struct page *next_hash; + atomic_t count; + unsigned long flags; /* atomic flags, some possibly updated asynchronously */ + struct list_head lru; + wait_queue_head_t wait; + struct page **pprev_hash; + struct buffer_head * buffers; + unsigned long virtual; /* nonzero if kmapped */ +} mem_map_t; + +#define get_page(p) atomic_inc(&(p)->count) +#define put_page(p) __free_page(p) +#define put_page_testzero(p) atomic_dec_and_test(&(p)->count) +#define page_count(p) atomic_read(&(p)->count) +#define set_page_count(p,v) atomic_set(&(p)->count, v) + +/* Page flag bit values */ +#define PG_locked 0 +#define PG_error 1 +#define PG_referenced 2 +#define PG_uptodate 3 +#define PG_decr_after 5 +#define PG_DMA 7 +#define PG_slab 8 +#define PG_swap_cache 9 +#define PG_skip 10 +#define PG_swap_entry 11 +#define PG_highmem 12 + /* bits 21-30 unused */ +#define PG_reserved 31 + + +/* Make it prettier to test the above... */ +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags) +#define SetPageUptodate(page) set_bit(PG_uptodate, &(page)->flags) +#define ClearPageUptodate(page) clear_bit(PG_uptodate, &(page)->flags) +#define PageLocked(page) test_bit(PG_locked, &(page)->flags) +#define LockPage(page) set_bit(PG_locked, &(page)->flags) +#define TryLockPage(page) test_and_set_bit(PG_locked, &(page)->flags) +#define UnlockPage(page) do { \ + clear_bit(PG_locked, &(page)->flags); \ + wake_up(&page->wait); \ + } while (0) +#define PageError(page) test_bit(PG_error, &(page)->flags) +#define SetPageError(page) test_and_set_bit(PG_error, &(page)->flags) +#define ClearPageError(page) clear_bit(PG_error, &(page)->flags) +#define PageReferenced(page) test_bit(PG_referenced, &(page)->flags) +#define PageDecrAfter(page) test_bit(PG_decr_after, &(page)->flags) +#define PageDMA(page) test_bit(PG_DMA, &(page)->flags) +#define PageSlab(page) test_bit(PG_slab, &(page)->flags) +#define PageSwapCache(page) test_bit(PG_swap_cache, &(page)->flags) +#define PageReserved(page) test_bit(PG_reserved, &(page)->flags) + +#define PageSetSlab(page) set_bit(PG_slab, &(page)->flags) +#define PageSetSwapCache(page) set_bit(PG_swap_cache, &(page)->flags) + +#define PageTestandSetSwapCache(page) test_and_set_bit(PG_swap_cache, &(page)->flags) + +#define PageClearSlab(page) clear_bit(PG_slab, &(page)->flags) +#define PageClearSwapCache(page) clear_bit(PG_swap_cache, &(page)->flags) + +#define PageTestandClearSwapCache(page) test_and_clear_bit(PG_swap_cache, &(page)->flags) + +#ifdef CONFIG_HIGHMEM +#define PageHighMem(page) test_bit(PG_highmem, &(page)->flags) +#else +#define PageHighMem(page) 0 /* needed to optimize away at compile time */ +#endif + +#define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags) +#define ClearPageReserved(page) clear_bit(PG_reserved, &(page)->flags) + +/* + * Error return values for the *_nopage functions + */ +#define NOPAGE_SIGBUS (NULL) +#define NOPAGE_OOM ((struct page *) (-1)) + + +/* + * Various page->flags bits: + * + * PG_reserved is set for a page which must never be accessed (which + * may not even be present). + * + * PG_DMA is set for those pages which lie in the range of + * physical addresses capable of carrying DMA transfers. + * + * Multiple processes may "see" the same page. E.g. for untouched + * mappings of /dev/null, all processes see the same page full of + * zeroes, and text pages of executables and shared libraries have + * only one copy in memory, at most, normally. + * + * For the non-reserved pages, page->count denotes a reference count. + * page->count == 0 means the page is free. + * page->count == 1 means the page is used for exactly one purpose + * (e.g. a private data page of one process). + * + * A page may be used for kmalloc() or anyone else who does a + * __get_free_page(). In this case the page->count is at least 1, and + * all other fields are unused but should be 0 or NULL. The + * management of this page is the responsibility of the one who uses + * it. + * + * The other pages (we may call them "process pages") are completely + * managed by the Linux memory manager: I/O, buffers, swapping etc. + * The following discussion applies only to them. + * + * A page may belong to an inode's memory mapping. In this case, + * page->inode is the pointer to the inode, and page->offset is the + * file offset of the page (not necessarily a multiple of PAGE_SIZE). + * + * A page may have buffers allocated to it. In this case, + * page->buffers is a circular list of these buffer heads. Else, + * page->buffers == NULL. + * + * For pages belonging to inodes, the page->count is the number of + * attaches, plus 1 if buffers are allocated to the page. + * + * All pages belonging to an inode make up a doubly linked list + * inode->i_pages, using the fields page->next and page->prev. (These + * fields are also used for freelist management when page->count==0.) + * There is also a hash table mapping (inode,offset) to the page + * in memory if present. The lists for this hash table use the fields + * page->next_hash and page->pprev_hash. + * + * All process pages can do I/O: + * - inode pages may need to be read from disk, + * - inode pages which have been modified and are MAP_SHARED may need + * to be written to disk, + * - private pages which have been modified may need to be swapped out + * to swap space and (later) to be read back into memory. + * During disk I/O, PG_locked is used. This bit is set before I/O + * and reset when I/O completes. page->wait is a wait queue of all + * tasks waiting for the I/O on this page to complete. + * PG_uptodate tells whether the page's contents is valid. + * When a read completes, the page becomes uptodate, unless a disk I/O + * error happened. + * + * For choosing which pages to swap out, inode pages carry a + * PG_referenced bit, which is set any time the system accesses + * that page through the (inode,offset) hash table. + * + * PG_skip is used on sparc/sparc64 architectures to "skip" certain + * parts of the address space. + * + * PG_error is set to indicate that an I/O error occurred on this page. + */ + +extern mem_map_t * mem_map; + +/* + * This is timing-critical - most of the time in getting a new page + * goes to clearing the page. If you want a page without the clearing + * overhead, just use __get_free_page() directly.. + * + * We have two allocation namespaces - the *get*page*() variants + * return virtual kernel addresses to the allocated page(s), the + * alloc_page*() variants return 'struct page *'. + */ +#define __get_free_page(gfp_mask) __get_free_pages((gfp_mask),0) +#define __get_dma_pages(gfp_mask, order) __get_free_pages((gfp_mask) | GFP_DMA,(order)) +extern unsigned long FASTCALL(__get_free_pages(int gfp_mask, unsigned long order)); +extern struct page * FASTCALL(alloc_pages(int gfp_mask, unsigned long order)); +#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) + +extern inline unsigned long get_zeroed_page(int gfp_mask) +{ + unsigned long page; + + page = __get_free_page(gfp_mask); + if (page) + clear_page((void *)page); + return page; +} + +/* + * The old interface name will be removed in 2.5: + */ +#define get_free_page get_zeroed_page + +/* memory.c & swap.c*/ + +#define free_page(addr) free_pages((addr),0) +extern int FASTCALL(free_pages(unsigned long addr, unsigned long order)); +extern int FASTCALL(__free_page(struct page *)); + +extern void show_free_areas(void); +extern struct page * put_dirty_page(struct task_struct * tsk, struct page *page, + unsigned long address); + +extern void clear_page_tables(struct mm_struct *, unsigned long, int); + +extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size); +extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma); +extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot); +extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot); + +extern void vmtruncate(struct inode * inode, unsigned long offset); +extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access); +extern int make_pages_present(unsigned long addr, unsigned long end); +extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); +extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len); +extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len); + +extern int pgt_cache_water[2]; +extern int check_pgt_cache(void); + +extern void paging_init(void); +extern void free_area_init(unsigned int * zones_size); +extern void mem_init(void); +extern void show_mem(void); +extern void oom(struct task_struct * tsk); +extern void si_meminfo(struct sysinfo * val); +extern void swapin_readahead(swp_entry_t); + +/* mmap.c */ +extern void vma_init(void); +extern void merge_segments(struct mm_struct *, unsigned long, unsigned long); +extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *); +extern void build_mmap_avl(struct mm_struct *); +extern void exit_mmap(struct mm_struct *); +extern unsigned long get_unmapped_area(unsigned long, unsigned long); + +extern unsigned long do_mmap(struct file *, unsigned long, unsigned long, + unsigned long, unsigned long, unsigned long); +extern int do_munmap(unsigned long, size_t); +extern unsigned long do_brk(unsigned long, unsigned long); + +/* filemap.c */ +extern void remove_inode_page(struct page *); +extern unsigned long page_unuse(struct page *); +extern int shrink_mmap(int, int); +extern void truncate_inode_pages(struct inode *, unsigned long); +extern void put_cached_page(unsigned long); + +/* + * GFP bitmasks.. + */ +#define __GFP_WAIT 0x01 +#define __GFP_LOW 0x02 +#define __GFP_MED 0x04 +#define __GFP_HIGH 0x08 +#define __GFP_IO 0x10 +#define __GFP_SWAP 0x20 +#ifdef CONFIG_HIGHMEM +#define __GFP_HIGHMEM 0x40 +#else +#define __GFP_HIGHMEM 0x0 /* noop */ +#endif + +#define __GFP_DMA 0x80 + +#define GFP_BUFFER (__GFP_LOW | __GFP_WAIT) +#define GFP_ATOMIC (__GFP_HIGH) +#define GFP_USER (__GFP_LOW | __GFP_WAIT | __GFP_IO) +#define GFP_HIGHUSER (GFP_USER | __GFP_HIGHMEM) +#define GFP_KERNEL (__GFP_MED | __GFP_WAIT | __GFP_IO) +#define GFP_NFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO) +#define GFP_KSWAPD (__GFP_IO | __GFP_SWAP) + +/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some + platforms, used as appropriate on others */ + +#define GFP_DMA __GFP_DMA + +/* Flag - indicates that the buffer can be taken from high memory which is not + directly addressable by the kernel */ + +#define GFP_HIGHMEM __GFP_HIGHMEM + +/* vma is the first one with address < vma->vm_end, + * and even address < vma->vm_start. Have to extend vma. */ +static inline int expand_stack(struct vm_area_struct * vma, unsigned long address) +{ + unsigned long grow; + + address &= PAGE_MASK; + grow = (vma->vm_start - address) >> PAGE_SHIFT; + if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur || + ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) + return -ENOMEM; + vma->vm_start = address; + vma->vm_pgoff -= grow; + vma->vm_mm->total_vm += grow; + if (vma->vm_flags & VM_LOCKED) + vma->vm_mm->locked_vm += grow; + return 0; +} + +/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */ +extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr); + +/* Look up the first VMA which intersects the interval start_addr..end_addr-1, + NULL if none. Assume start_addr < end_addr. */ +static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr) +{ + struct vm_area_struct * vma = find_vma(mm,start_addr); + + if (vma && end_addr <= vma->vm_start) + vma = NULL; + return vma; +} + +extern struct vm_area_struct *find_extend_vma(struct task_struct *tsk, unsigned long addr); + +#define buffer_under_min() (atomic_read(&buffermem_pages) * 100 < \ + buffer_mem.min_percent * num_physpages) +#define pgcache_under_min() (atomic_read(&page_cache_size) * 100 < \ + page_cache.min_percent * num_physpages) + +#define vmlist_access_lock(mm) spin_lock(&mm->page_table_lock) +#define vmlist_access_unlock(mm) spin_unlock(&mm->page_table_lock) +#define vmlist_modify_lock(mm) vmlist_access_lock(mm) +#define vmlist_modify_unlock(mm) vmlist_access_unlock(mm) + + +#endif /* __KERNEL__ */ + +#endif diff -urN 2.3.29pre1/include/linux/proc_fs.h.orig 2.3.29pre1-ikd/include/linux/proc_fs.h.orig --- 2.3.29pre1/include/linux/proc_fs.h.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/proc_fs.h.orig Mon Nov 22 03:55:38 1999 @@ -0,0 +1,291 @@ +#ifndef _LINUX_PROC_FS_H +#define _LINUX_PROC_FS_H + +#include +#include + +/* + * The proc filesystem constants/structures + */ + +/* + * Offset of the first process in the /proc root directory.. + */ +#define FIRST_PROCESS_ENTRY 256 + + +/* + * We always define these enumerators + */ + +enum { + PROC_ROOT_INO = 1, +}; + +/* Finally, the dynamically allocatable proc entries are reserved: */ + +#define PROC_DYNAMIC_FIRST 4096 +#define PROC_NDYNAMIC 4096 +#define PROC_OPENPROM_FIRST (PROC_DYNAMIC_FIRST+PROC_NDYNAMIC) +#define PROC_OPENPROM PROC_OPENPROM_FIRST +#define PROC_NOPENPROM 4096 +#define PROC_OPENPROMD_FIRST (PROC_OPENPROM_FIRST+PROC_NOPENPROM) +#define PROC_NOPENPROMD 4096 + +#define PROC_SUPER_MAGIC 0x9fa0 + +/* + * This is not completely implemented yet. The idea is to + * create an in-memory tree (like the actual /proc filesystem + * tree) of these proc_dir_entries, so that we can dynamically + * add new files to /proc. + * + * The "next" pointer creates a linked list of one /proc directory, + * while parent/subdir create the directory structure (every + * /proc file has a parent, but "subdir" is NULL for all + * non-directory entries). + * + * "get_info" is called at "read", while "owner" is used to protect module + * from unloading while proc_dir_entry is in use + */ + +typedef int (read_proc_t)(char *page, char **start, off_t off, + int count, int *eof, void *data); +typedef int (write_proc_t)(struct file *file, const char *buffer, + unsigned long count, void *data); +typedef int (get_info_t)(char *, char **, off_t, int, int); + +struct proc_dir_entry { + unsigned short low_ino; + unsigned short namelen; + const char *name; + mode_t mode; + nlink_t nlink; + uid_t uid; + gid_t gid; + unsigned long size; + struct inode_operations * ops; + get_info_t *get_info; + struct module *owner; + struct proc_dir_entry *next, *parent, *subdir; + void *data; + read_proc_t *read_proc; + write_proc_t *write_proc; + int (*readlink_proc)(struct proc_dir_entry *de, char *page); + unsigned int count; /* use count */ + int deleted; /* delete flag */ +}; + +#define PROC_INODE_PROPER(inode) ((inode)->i_ino & ~0xffff) +#define PROC_INODE_OPENPROM(inode) \ + ((inode->i_ino >= PROC_OPENPROM_FIRST) \ + && (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)) + +#ifdef CONFIG_PROC_FS + +extern struct proc_dir_entry proc_root; +extern struct proc_dir_entry *proc_root_fs; +extern struct proc_dir_entry *proc_net; +extern struct proc_dir_entry proc_sys; +extern struct proc_dir_entry proc_openprom; +extern struct proc_dir_entry *proc_mca; +extern struct proc_dir_entry *proc_bus; +extern struct proc_dir_entry *proc_root_driver; +extern struct proc_dir_entry proc_root_kcore; + +extern void proc_root_init(void); +extern void proc_misc_init(void); + +struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry); +void proc_pid_delete_inode(struct inode *inode); +int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir); + +extern int proc_register(struct proc_dir_entry *, struct proc_dir_entry *); +extern int proc_unregister(struct proc_dir_entry *, int); + +extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, + struct proc_dir_entry *parent); +extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent); + + +/* + * retrieve the proc_dir_entry associated with /proc/driver/$module_name + */ +extern inline +struct proc_dir_entry *proc_driver_find (const char *module_name) +{ + struct proc_dir_entry *p; + + p = proc_root_driver->subdir; + while (p != NULL) { + if (strcmp (p->name, module_name) == 0) + return p; + + p = p->next; + } + return NULL; +} + + +/* + * remove /proc/driver/$module_name, and all its contents + */ +extern inline int proc_driver_unregister(const char *module_name) +{ + remove_proc_entry (module_name, proc_root_driver); + return 0; +} + + +/* + * create driver-specific playground directory, /proc/driver/$module_name + */ +extern inline int proc_driver_register(const char *module_name) +{ + struct proc_dir_entry *p; + + p = create_proc_entry (module_name, S_IFDIR, proc_root_driver); + + return (p == NULL) ? -1 : 0; +} + +extern struct super_block *proc_super_blocks; +extern struct dentry_operations proc_dentry_operations; +extern struct super_block *proc_read_super(struct super_block *,void *,int); +extern int init_proc_fs(void); +extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *); +extern int proc_statfs(struct super_block *, struct statfs *, int); +extern void proc_read_inode(struct inode *); +extern void proc_write_inode(struct inode *); + +extern int proc_match(int, const char *,struct proc_dir_entry *); + +/* + * These are generic /proc routines that use the internal + * "struct proc_dir_entry" tree to traverse the filesystem. + * + * The /proc root directory has extended versions to take care + * of the /proc/ subdirectories. + */ +extern int proc_readdir(struct file *, void *, filldir_t); +extern struct dentry *proc_lookup(struct inode *, struct dentry *); + +struct openpromfs_dev { + struct openpromfs_dev *next; + u32 node; + ino_t inode; + kdev_t rdev; + mode_t mode; + char name[32]; +}; +extern struct inode_operations * +proc_openprom_register(int (*readdir)(struct file *, void *, filldir_t), + struct dentry * (*lookup)(struct inode *, struct dentry *), + void (*use)(struct inode *, int), + struct openpromfs_dev ***); +extern void proc_openprom_deregister(void); +extern void (*proc_openprom_use)(struct inode *,int); +extern int proc_openprom_regdev(struct openpromfs_dev *); +extern int proc_openprom_unregdev(struct openpromfs_dev *); + +extern struct inode_operations proc_dir_inode_operations; +extern struct inode_operations proc_file_inode_operations; +extern struct inode_operations proc_openprom_inode_operations; +extern struct inode_operations proc_sys_inode_operations; +extern struct inode_operations proc_kcore_inode_operations; +extern struct inode_operations proc_profile_inode_operations; +extern struct inode_operations proc_kmsg_inode_operations; +#if CONFIG_AP1000 +extern struct inode_operations proc_ringbuf_inode_operations; +#endif +extern struct inode_operations proc_omirr_inode_operations; +extern struct inode_operations proc_ppc_htab_inode_operations; + +/* + * proc_tty.c + */ +extern void proc_tty_init(void); +extern void proc_tty_register_driver(struct tty_driver *driver); +extern void proc_tty_unregister_driver(struct tty_driver *driver); + +/* + * proc_devtree.c + */ +extern void proc_device_tree_init(void); + +extern inline struct proc_dir_entry *create_proc_read_entry(const char *name, + mode_t mode, struct proc_dir_entry *base, + read_proc_t *read_proc, void * data) +{ + struct proc_dir_entry *res=create_proc_entry(name,mode,base); + if (res) { + res->read_proc=read_proc; + res->data=data; + } + return res; +} + +extern inline struct proc_dir_entry *create_proc_info_entry(const char *name, + mode_t mode, struct proc_dir_entry *base, get_info_t *get_info) +{ + struct proc_dir_entry *res=create_proc_entry(name,mode,base); + if (res) res->get_info=get_info; + return res; +} + +extern inline struct proc_dir_entry *proc_net_create(const char *name, + mode_t mode, get_info_t *get_info) +{ + return create_proc_info_entry(name,mode,proc_net,get_info); +} + +extern inline void proc_net_remove(const char *name) +{ + remove_proc_entry(name,proc_net); +} + +#else + +extern inline int proc_register(struct proc_dir_entry *a, struct proc_dir_entry *b) { return 0; } +extern inline int proc_unregister(struct proc_dir_entry *a, int b) { return 0; } +extern inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, + get_info_t *get_info) {return NULL;} +extern inline void proc_net_remove(const char *name) {} + +extern inline struct proc_dir_entry *create_proc_entry(const char *name, + mode_t mode, struct proc_dir_entry *parent) { return NULL; } + +extern inline void remove_proc_entry(const char *name, struct proc_dir_entry *parent) {}; + +extern inline struct proc_dir_entry *create_proc_read_entry(const char *name, + mode_t mode, struct proc_dir_entry *base, + int (*read_proc)(char *, char **, off_t, int, int *, void *), + void * data) { return NULL; } +extern inline struct proc_dir_entry *create_proc_info_entry(const char *name, + mode_t mode, struct proc_dir_entry *base, get_info_t *get_info) + { return NULL; } + +extern inline void proc_tty_register_driver(struct tty_driver *driver) {}; +extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {}; + +extern inline +struct proc_dir_entry *proc_driver_find (const char *module_name) +{ + return NULL; +} + +extern inline int proc_driver_unregister(const char *module_name) +{ + return 0; +} + +extern inline int proc_driver_register(const char *module_name) +{ + return 0; +} + +extern struct proc_dir_entry proc_root; + +#endif /* CONFIG_PROC_FS */ + +#endif /* _LINUX_PROC_FS_H */ diff -urN 2.3.29pre1/include/linux/proc_fs.h.rej 2.3.29pre1-ikd/include/linux/proc_fs.h.rej --- 2.3.29pre1/include/linux/proc_fs.h.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/proc_fs.h.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,38 @@ +*************** +*** 57,62 **** + PROC_FS, + PROC_SYSVIPC, + PROC_DRIVER, + }; + + enum pid_directory_inos { +--- 57,64 ---- + PROC_FS, + PROC_SYSVIPC, + PROC_DRIVER, ++ PROC_TRACE, ++ PROC_MEMLEAK, + }; + + enum pid_directory_inos { +*************** +*** 501,506 **** + extern struct inode_operations proc_omirr_inode_operations; + extern struct inode_operations proc_ppc_htab_inode_operations; + extern struct inode_operations proc_sysvipc_inode_operations; + + /* + * proc_tty.c +--- 503,514 ---- + extern struct inode_operations proc_omirr_inode_operations; + extern struct inode_operations proc_ppc_htab_inode_operations; + extern struct inode_operations proc_sysvipc_inode_operations; ++ #ifdef CONFIG_TRACE ++ extern struct inode_operations proc_trace_inode_operations; ++ #endif ++ #ifdef CONFIG_MEMLEAK ++ extern struct inode_operations proc_memleak_inode_operations; ++ #endif + + /* + * proc_tty.c diff -urN 2.3.29pre1/include/linux/profiler.h 2.3.29pre1-ikd/include/linux/profiler.h --- 2.3.29pre1/include/linux/profiler.h Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/profiler.h Mon Nov 22 16:56:24 1999 @@ -0,0 +1,87 @@ +#ifndef _LINUX_PROFILER_H +#define _LINUX_PROFILER_H + +#include +#include +#include +#include + +#ifdef __KERNEL__ +#ifdef CONFIG_DEBUG_MCOUNT + +extern void mcount (void); +extern int mcount_internal(profiler_pc_t self_addr); +extern atomic_t mcount_ready; /* controls all mcount() processing */ + +#define SUSPEND_MCOUNT atomic_dec(&mcount_ready) +#define RESUME_MCOUNT atomic_inc(&mcount_ready) +#define SUSPEND_MCOUNT_PROC(x) ((x)->flags |= PF_NO_MCOUNT) +#define RESUME_MCOUNT_PROC(x) ((x)->flags &= ~PF_NO_MCOUNT) +#define MCOUNT() mcount() + +#ifdef CONFIG_TRACE + +extern atomic_t mcount_trace_ready; /* controls just mcount() tracing */ +/* + * Protect the profiling table with a spin lock, only one cpu at a + * time. No point in read/write locks, almost all accesses are for + * write. Since this code is accessed from all contexts, use + * spin_lock_irqsave. + */ +extern spinlock_t trace_table_lock; + +/* Note: The hierarchy is mcount_ready, mcount_trace_ready, trace_table_lock */ + +struct trace_entry { + profiler_pc_t pc; +#ifdef CONFIG_TRACE_TIMESTAMP + profiler_timestamp_t timestamp; +#endif +#ifdef CONFIG_TRACE_PID + pid_t pid; +#endif +#if defined(CONFIG_TRACE_CPU) && (defined(__SMP__) || defined(CONFIG_SMP)) + unsigned int cpu; +#endif +}; + +extern struct trace_table { + unsigned int table_size; + unsigned int curr_call; + struct trace_entry entries[CONFIG_TRACE_SIZE]; +} *trace_table; + +/* + * die_if_kernel() uses this to 'extend' the stack trace given in an Oops + * message. You can use this when debugging special code, as a debugging aid. + */ +void print_emergency_trace (void); + +#define TRACE_CALIBRATION_CALLS 20 + +#define SUSPEND_MCOUNT_TRACE atomic_dec(&mcount_trace_ready) +#define RESUME_MCOUNT_TRACE atomic_inc(&mcount_trace_ready) +#define LOCK_MCOUNT_TRACE(x) spin_lock_irqsave(&trace_table_lock, x); +#define UNLOCK_MCOUNT_TRACE(x) spin_unlock_irqrestore(&trace_table_lock, x); + +#else /* !CONFIG_TRACE */ + +#define SUSPEND_MCOUNT_TRACE +#define RESUME_MCOUNT_TRACE +#define LOCK_MCOUNT_TRACE(x) +#define UNLOCK_MCOUNT_TRACE(x) + +#endif /* CONFIG_TRACE */ +#else /* !CONFIG_DEBUG_MCOUNT */ + +#define SUSPEND_MCOUNT +#define RESUME_MCOUNT +#define SUSPEND_MCOUNT_PROC(x) +#define RESUME_MCOUNT_PROC(x) +#define MCOUNT() + +#endif /* CONFIG_DEBUG_MCOUNT */ + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_PROFILER_H */ diff -urN 2.3.29pre1/include/linux/reboot.h 2.3.29pre1-ikd/include/linux/reboot.h --- 2.3.29pre1/include/linux/reboot.h Tue Sep 14 15:03:19 1999 +++ 2.3.29pre1-ikd/include/linux/reboot.h Mon Nov 22 16:56:24 1999 @@ -20,6 +20,9 @@ * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task. * POWER_OFF Stop OS and remove all power from system, if possible. * RESTART2 Restart system using given command string. + * OOPS Cause a kernel Oops, the machine should continue afterwards. + * STACKFAULT Overflow the kernel stack with recursion. + * KERNEL_LOOP Endless kernel loop, unlocked. */ #define LINUX_REBOOT_CMD_RESTART 0x01234567 @@ -29,6 +32,9 @@ #define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 +#define LINUX_REBOOT_CMD_OOPS 0x4F6F7001 +#define LINUX_REBOOT_CMD_STACKFAULT 0x53746602 +#define LINUX_REBOOT_CMD_KERNEL_LOOP 0x4C6F7003 #ifdef __KERNEL__ diff -urN 2.3.29pre1/include/linux/sched.h 2.3.29pre1-ikd/include/linux/sched.h --- 2.3.29pre1/include/linux/sched.h Mon Nov 22 03:55:33 1999 +++ 2.3.29pre1-ikd/include/linux/sched.h Mon Nov 22 17:14:54 1999 @@ -5,6 +5,7 @@ extern unsigned long event; +#include #include #include #include @@ -363,6 +364,9 @@ u32 self_exec_id; /* Protection of fields allocatio/deallocation */ struct semaphore exit_sem; +#ifdef CONFIG_DEBUG_SOFTLOCKUP + unsigned int deadlock_count; +#endif }; /* @@ -380,6 +384,9 @@ #define PF_SIGNALED 0x00000400 /* killed by a signal */ #define PF_MEMALLOC 0x00000800 /* Allocating memory */ #define PF_VFORK 0x00001000 /* Wake up parent in mm_release */ +#ifdef CONFIG_DEBUG_MCOUNT +#define PF_NO_MCOUNT 0x00002000 /* skip mcount() processing */ +#endif #define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ #define PF_DTRACE 0x00200000 /* delayed trace (used on m68k, i386) */ diff -urN 2.3.29pre1/include/linux/sched.h.orig 2.3.29pre1-ikd/include/linux/sched.h.orig --- 2.3.29pre1/include/linux/sched.h.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/sched.h.orig Mon Nov 22 03:55:33 1999 @@ -0,0 +1,860 @@ +#ifndef _LINUX_SCHED_H +#define _LINUX_SCHED_H + +#include /* for HZ */ + +extern unsigned long event; + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * cloning flags: + */ +#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ +#define CLONE_VM 0x00000100 /* set if VM shared between processes */ +#define CLONE_FS 0x00000200 /* set if fs info shared between processes */ +#define CLONE_FILES 0x00000400 /* set if open files shared between processes */ +#define CLONE_SIGHAND 0x00000800 /* set if signal handlers shared */ +#define CLONE_PID 0x00001000 /* set if pid shared */ +#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ +#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ +#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ + +/* + * These are the constant used to fake the fixed-point load-average + * counting. Some notes: + * - 11 bit fractions expand to 22 bits by the multiplies: this gives + * a load-average precision of 10 bits integer + 11 bits fractional + * - if you want to count load-averages more often, you need more + * precision, or rounding will get you. With 2-second counting freq, + * the EXP_n values would be 1981, 2034 and 2043 if still using only + * 11 bit fractions. + */ +extern unsigned long avenrun[]; /* Load averages */ + +#define FSHIFT 11 /* nr of bits of precision */ +#define FIXED_1 (1<>= FSHIFT; + +#define CT_TO_SECS(x) ((x) / HZ) +#define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ) + +extern int nr_running, nr_threads; +extern int last_pid; + +#include +#include +#include +#include +#include + +#include + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 4 +#define TASK_STOPPED 8 +#define TASK_SWAPPING 16 +#define TASK_EXCLUSIVE 32 + +#define __set_task_state(tsk, state_value) \ + do { tsk->state = state_value; } while (0) +#ifdef __SMP__ +#define set_task_state(tsk, state_value) \ + set_mb(tsk->state, state_value) +#else +#define set_task_state(tsk, state_value) \ + __set_task_state(tsk, state_value) +#endif + +#define __set_current_state(state_value) \ + do { current->state = state_value; } while (0) +#ifdef __SMP__ +#define set_current_state(state_value) \ + set_mb(current->state, state_value) +#else +#define set_current_state(state_value) \ + __set_current_state(state_value) +#endif + +/* + * Scheduling policies + */ +#define SCHED_OTHER 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 + +/* + * This is an additional bit set when we want to + * yield the CPU for one re-schedule.. + */ +#define SCHED_YIELD 0x10 + +struct sched_param { + int sched_priority; +}; + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#ifdef __KERNEL__ + +#include + +/* + * This serializes "schedule()" and also protects + * the run-queue from deletions/modifications (but + * _adding_ to the beginning of the run-queue has + * a separate lock). + */ +extern rwlock_t tasklist_lock; +extern spinlock_t runqueue_lock; + +extern void sched_init(void); +extern void init_idle(void); +extern void show_state(void); +extern void cpu_init (void); +extern void trap_init(void); +extern void update_one_process( struct task_struct *p, + unsigned long ticks, unsigned long user, unsigned long system, int cpu); + +#define MAX_SCHEDULE_TIMEOUT LONG_MAX +extern signed long FASTCALL(schedule_timeout(signed long timeout)); +asmlinkage void schedule(void); + +/* + * The default fd array needs to be at least BITS_PER_LONG, + * as this is the granularity returned by copy_fdset(). + */ +#define NR_OPEN_DEFAULT BITS_PER_LONG + +/* + * Open file table structure + */ +struct files_struct { + atomic_t count; + rwlock_t file_lock; + int max_fds; + int max_fdset; + int next_fd; + struct file ** fd; /* current fd array */ + fd_set *close_on_exec; + fd_set *open_fds; + fd_set close_on_exec_init; + fd_set open_fds_init; + struct file * fd_array[NR_OPEN_DEFAULT]; +}; + +#define INIT_FILES { \ + ATOMIC_INIT(1), \ + RW_LOCK_UNLOCKED, \ + NR_OPEN_DEFAULT, \ + __FD_SETSIZE, \ + 0, \ + &init_files.fd_array[0], \ + &init_files.close_on_exec_init, \ + &init_files.open_fds_init, \ + { { 0, } }, \ + { { 0, } }, \ + { NULL, } \ +} + +struct fs_struct { + atomic_t count; + int umask; + struct dentry * root, * pwd; +}; + +#define INIT_FS { \ + ATOMIC_INIT(1), \ + 0022, \ + NULL, NULL \ +} + +/* Maximum number of active map areas.. This is a random (large) number */ +#define MAX_MAP_COUNT (65536) + +/* Number of map areas at which the AVL tree is activated. This is arbitrary. */ +#define AVL_MIN_MAP_COUNT 32 + +struct mm_struct { + struct vm_area_struct * mmap; /* list of VMAs */ + struct vm_area_struct * mmap_avl; /* tree of VMAs */ + struct vm_area_struct * mmap_cache; /* last find_vma result */ + pgd_t * pgd; + atomic_t mm_users; /* How many users with user space? */ + atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ + int map_count; /* number of VMAs */ + struct semaphore mmap_sem; + spinlock_t page_table_lock; + unsigned long context; + unsigned long start_code, end_code, start_data, end_data; + unsigned long start_brk, brk, start_stack; + unsigned long arg_start, arg_end, env_start, env_end; + unsigned long rss, total_vm, locked_vm; + unsigned long def_flags; + unsigned long cpu_vm_mask; + unsigned long swap_cnt; /* number of pages to swap on next pass */ + unsigned long swap_address; + /* + * This is an architecture-specific pointer: the portable + * part of Linux does not know about any segments. + */ + void * segments; +}; + +#define INIT_MM(name) { \ + &init_mmap, NULL, NULL, \ + swapper_pg_dir, \ + ATOMIC_INIT(2), ATOMIC_INIT(1), 1, \ + __MUTEX_INITIALIZER(name.mmap_sem), \ + SPIN_LOCK_UNLOCKED, \ + 0, \ + 0, 0, 0, 0, \ + 0, 0, 0, \ + 0, 0, 0, 0, \ + 0, 0, 0, \ + 0, 0, 0, 0, NULL } + +struct signal_struct { + atomic_t count; + struct k_sigaction action[_NSIG]; + spinlock_t siglock; +}; + + +#define INIT_SIGNALS { \ + ATOMIC_INIT(1), \ + { {{0,}}, }, \ + SPIN_LOCK_UNLOCKED } + +/* + * Some day this will be a full-fledged user tracking system.. + * Right now it is only used to track how many processes a + * user has, but it has the potential to track memory usage etc. + */ +struct user_struct; + +struct task_struct { +/* these are hardcoded - don't touch */ + volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + unsigned long flags; /* per process flags, defined below */ + int sigpending; + mm_segment_t addr_limit; /* thread address space: + 0-0xBFFFFFFF for user-thead + 0-0xFFFFFFFF for kernel-thread + */ + struct exec_domain *exec_domain; + volatile long need_resched; + +/* various fields */ + long counter; + long priority; + cycles_t avg_slice; +/* SMP and runqueue state */ + int has_cpu; + int processor; + int last_processor; + int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */ + struct task_struct *next_task, *prev_task; + struct list_head run_list; + +/* task state */ + struct linux_binfmt *binfmt; + int exit_code, exit_signal; + int pdeath_signal; /* The signal sent when the parent dies */ + /* ??? */ + unsigned long personality; + int dumpable:1; + int did_exec:1; + pid_t pid; + pid_t pgrp; + pid_t tty_old_pgrp; + pid_t session; + /* boolean value for session group leader */ + int leader; + /* + * pointers to (original) parent process, youngest child, younger sibling, + * older sibling, respectively. (p->father can be replaced with + * p->p_pptr->pid) + */ + struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; + + /* PID hash table linkage. */ + struct task_struct *pidhash_next; + struct task_struct **pidhash_pprev; + + wait_queue_head_t wait_chldexit; /* for wait4() */ + struct semaphore *vfork_sem; /* for vfork() */ + unsigned long policy, rt_priority; + unsigned long it_real_value, it_prof_value, it_virt_value; + unsigned long it_real_incr, it_prof_incr, it_virt_incr; + struct timer_list real_timer; + struct tms times; + unsigned long start_time; + long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS]; +/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ + unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; + int swappable:1; +/* process credentials */ + uid_t uid,euid,suid,fsuid; + gid_t gid,egid,sgid,fsgid; + int ngroups; + gid_t groups[NGROUPS]; + kernel_cap_t cap_effective, cap_inheritable, cap_permitted; + struct user_struct *user; +/* limits */ + struct rlimit rlim[RLIM_NLIMITS]; + unsigned short used_math; + char comm[16]; +/* file system info */ + int link_count; + struct tty_struct *tty; /* NULL if no tty */ +/* ipc stuff */ + struct sem_undo *semundo; + struct sem_queue *semsleeping; +/* CPU-specific state of this task */ + struct thread_struct thread; +/* filesystem information */ + struct fs_struct *fs; +/* open file information */ + struct files_struct *files; + +/* memory management info */ + struct mm_struct *mm, *active_mm; + +/* signal handlers */ + spinlock_t sigmask_lock; /* Protects signal and blocked */ + struct signal_struct *sig; + sigset_t signal, blocked; + struct signal_queue *sigqueue, **sigqueue_tail; + unsigned long sas_ss_sp; + size_t sas_ss_size; + +/* Thread group tracking */ + u32 parent_exec_id; + u32 self_exec_id; +/* Protection of fields allocatio/deallocation */ + struct semaphore exit_sem; +}; + +/* + * Per process flags + */ +#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */ + /* Not implemented yet, only for 486*/ +#define PF_STARTING 0x00000002 /* being created */ +#define PF_EXITING 0x00000004 /* getting shut down */ +#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called */ +#define PF_TRACESYS 0x00000020 /* tracing system calls */ +#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ +#define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ +#define PF_DUMPCORE 0x00000200 /* dumped core */ +#define PF_SIGNALED 0x00000400 /* killed by a signal */ +#define PF_MEMALLOC 0x00000800 /* Allocating memory */ +#define PF_VFORK 0x00001000 /* Wake up parent in mm_release */ + +#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ +#define PF_DTRACE 0x00200000 /* delayed trace (used on m68k, i386) */ + +/* + * Limit the stack by to some sane default: root can always + * increase this limit if needed.. 8MB seems reasonable. + */ +#define _STK_LIM (8*1024*1024) + +#define DEF_PRIORITY (20*HZ/100) /* 200 ms time slices */ + +/* + * INIT_TASK is used to set up the first task table, touch at + * your own risk!. Base=0, limit=0x1fffff (=2MB) + */ +#define INIT_TASK(name) \ +/* state etc */ { 0,0,0,KERNEL_DS,&default_exec_domain,0, \ +/* counter */ DEF_PRIORITY,DEF_PRIORITY,0, \ +/* SMP */ 0,0,0,-1, \ +/* schedlink */ &init_task,&init_task, LIST_HEAD_INIT(init_task.run_list), \ +/* binfmt */ NULL, \ +/* ec,brk... */ 0,0,0,0,0,0, \ +/* pid etc.. */ 0,0,0,0,0, \ +/* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \ +/* pidhash */ NULL, NULL, \ +/* chld wait */ __WAIT_QUEUE_HEAD_INITIALIZER(name.wait_chldexit), NULL, \ +/* timeout */ SCHED_OTHER,0,0,0,0,0,0,0, \ +/* timer */ { NULL, NULL, 0, 0, it_real_fn }, \ +/* utime */ {0,0,0,0},0, \ +/* per CPU times */ {0, }, {0, }, \ +/* flt */ 0,0,0,0,0,0, \ +/* swp */ 0, \ +/* process credentials */ \ +/* uid etc */ 0,0,0,0,0,0,0,0, \ +/* suppl grps*/ 0, {0,}, \ +/* caps */ CAP_INIT_EFF_SET,CAP_INIT_INH_SET,CAP_FULL_SET, \ +/* user */ NULL, \ +/* rlimits */ INIT_RLIMITS, \ +/* math */ 0, \ +/* comm */ "swapper", \ +/* fs info */ 0,NULL, \ +/* ipc */ NULL, NULL, \ +/* thread */ INIT_THREAD, \ +/* fs */ &init_fs, \ +/* files */ &init_files, \ +/* mm */ NULL, &init_mm, \ +/* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \ +/* exec cts */ 0,0, \ +/* exit_sem */ __MUTEX_INITIALIZER(name.exit_sem), \ +} + +#ifndef INIT_TASK_SIZE +# define INIT_TASK_SIZE 2048*sizeof(long) +#endif + +union task_union { + struct task_struct task; + unsigned long stack[INIT_TASK_SIZE/sizeof(long)]; +}; + +extern union task_union init_task_union; + +extern struct mm_struct init_mm; +extern struct task_struct *init_tasks[NR_CPUS]; + +/* PID hashing. (shouldnt this be dynamic?) */ +#define PIDHASH_SZ (4096 >> 2) +extern struct task_struct *pidhash[PIDHASH_SZ]; + +#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) + +extern __inline__ void hash_pid(struct task_struct *p) +{ + struct task_struct **htable = &pidhash[pid_hashfn(p->pid)]; + + if((p->pidhash_next = *htable) != NULL) + (*htable)->pidhash_pprev = &p->pidhash_next; + *htable = p; + p->pidhash_pprev = htable; +} + +extern __inline__ void unhash_pid(struct task_struct *p) +{ + if(p->pidhash_next) + p->pidhash_next->pidhash_pprev = p->pidhash_pprev; + *p->pidhash_pprev = p->pidhash_next; +} + +extern __inline__ struct task_struct *find_task_by_pid(int pid) +{ + struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)]; + + for(p = *htable; p && p->pid != pid; p = p->pidhash_next) + ; + + return p; +} + +/* per-UID process charging. */ +extern int alloc_uid(struct task_struct *); +void free_uid(struct task_struct *); + +#include + +extern unsigned long volatile jiffies; +extern unsigned long itimer_ticks; +extern unsigned long itimer_next; +extern struct timeval xtime; +extern void do_timer(struct pt_regs *); + +extern unsigned int * prof_buffer; +extern unsigned long prof_len; +extern unsigned long prof_shift; + +#define CURRENT_TIME (xtime.tv_sec) + +extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode)); +extern void FASTCALL(sleep_on(wait_queue_head_t *q)); +extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q, + signed long timeout)); +extern void FASTCALL(interruptible_sleep_on(wait_queue_head_t *q)); +extern long FASTCALL(interruptible_sleep_on_timeout(wait_queue_head_t *q, + signed long timeout)); +extern void FASTCALL(wake_up_process(struct task_struct * tsk)); + +#define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE) +#define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE) + +extern int in_group_p(gid_t); + +extern void flush_signals(struct task_struct *); +extern void flush_signal_handlers(struct task_struct *); +extern int dequeue_signal(sigset_t *, siginfo_t *); +extern int send_sig_info(int, struct siginfo *, struct task_struct *); +extern int force_sig_info(int, struct siginfo *, struct task_struct *); +extern int kill_pg_info(int, struct siginfo *, pid_t); +extern int kill_sl_info(int, struct siginfo *, pid_t); +extern int kill_proc_info(int, struct siginfo *, pid_t); +extern int kill_something_info(int, struct siginfo *, int); +extern void notify_parent(struct task_struct *, int); +extern void force_sig(int, struct task_struct *); +extern int send_sig(int, struct task_struct *, int); +extern int kill_pg(pid_t, int, int); +extern int kill_sl(pid_t, int, int); +extern int kill_proc(pid_t, int, int); +extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *); +extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long); + +extern inline int signal_pending(struct task_struct *p) +{ + return (p->sigpending != 0); +} + +/* Reevaluate whether the task has signals pending delivery. + This is required every time the blocked sigset_t changes. + All callers should have t->sigmask_lock. */ + +static inline void recalc_sigpending(struct task_struct *t) +{ + unsigned long ready; + long i; + + switch (_NSIG_WORDS) { + default: + for (i = _NSIG_WORDS, ready = 0; --i >= 0 ;) + ready |= t->signal.sig[i] &~ t->blocked.sig[i]; + break; + + case 4: ready = t->signal.sig[3] &~ t->blocked.sig[3]; + ready |= t->signal.sig[2] &~ t->blocked.sig[2]; + ready |= t->signal.sig[1] &~ t->blocked.sig[1]; + ready |= t->signal.sig[0] &~ t->blocked.sig[0]; + break; + + case 2: ready = t->signal.sig[1] &~ t->blocked.sig[1]; + ready |= t->signal.sig[0] &~ t->blocked.sig[0]; + break; + + case 1: ready = t->signal.sig[0] &~ t->blocked.sig[0]; + } + + t->sigpending = (ready != 0); +} + +/* True if we are on the alternate signal stack. */ + +static inline int on_sig_stack(unsigned long sp) +{ + return (sp - current->sas_ss_sp < current->sas_ss_size); +} + +static inline int sas_ss_flags(unsigned long sp) +{ + return (current->sas_ss_size == 0 ? SS_DISABLE + : on_sig_stack(sp) ? SS_ONSTACK : 0); +} + +extern int request_irq(unsigned int, + void (*handler)(int, void *, struct pt_regs *), + unsigned long, const char *, void *); +extern void free_irq(unsigned int, void *); + +/* + * This has now become a routine instead of a macro, it sets a flag if + * it returns true (to do BSD-style accounting where the process is flagged + * if it uses root privs). The implication of this is that you should do + * normal permissions checks first, and check suser() last. + * + * [Dec 1997 -- Chris Evans] + * For correctness, the above considerations need to be extended to + * fsuser(). This is done, along with moving fsuser() checks to be + * last. + * + * These will be removed, but in the mean time, when the SECURE_NOROOT + * flag is set, uids don't grant privilege. + */ +extern inline int suser(void) +{ + if (!issecure(SECURE_NOROOT) && current->euid == 0) { + current->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} + +extern inline int fsuser(void) +{ + if (!issecure(SECURE_NOROOT) && current->fsuid == 0) { + current->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} + +/* + * capable() checks for a particular capability. + * New privilege checks should use this interface, rather than suser() or + * fsuser(). See include/linux/capability.h for defined capabilities. + */ + +extern inline int capable(int cap) +{ +#if 1 /* ok now */ + if (cap_raised(current->cap_effective, cap)) +#else + if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0) +#endif + { + current->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} + +/* + * Routines for handling mm_structs + */ +extern struct mm_struct * mm_alloc(void); + +extern struct mm_struct * start_lazy_tlb(void); +extern void end_lazy_tlb(struct mm_struct *mm); + +/* mmdrop drops the mm and the page tables */ +extern inline void FASTCALL(__mmdrop(struct mm_struct *)); +static inline void mmdrop(struct mm_struct * mm) +{ + if (atomic_dec_and_test(&mm->mm_count)) + __mmdrop(mm); +} + +/* mmput gets rid of the mappings and all user-space */ +extern void mmput(struct mm_struct *); +/* Remove the current tasks stale references to the old mm_struct */ +extern void mm_release(void); + +/* + * Routines for handling the fd arrays + */ +extern struct file ** alloc_fd_array(int); +extern int expand_fd_array(struct files_struct *, int nr); +extern void free_fd_array(struct file **, int); + +extern fd_set *alloc_fdset(int); +extern int expand_fdset(struct files_struct *, int nr); +extern void free_fdset(fd_set *, int); + +/* Expand files. Return <0 on error; 0 nothing done; 1 files expanded, + * we may have blocked. + * + * Should be called with the files->file_lock spinlock held for write. + */ +static inline int expand_files(struct files_struct *files, int nr) +{ + int err, expand = 0; +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " %d: nr = %d\n", current->pid, nr); +#endif + + if (nr >= files->max_fdset) { + expand = 1; + if ((err = expand_fdset(files, nr))) + goto out; + } + if (nr >= files->max_fds) { + expand = 1; + if ((err = expand_fd_array(files, nr))) + goto out; + } + err = expand; + out: +#ifdef FDSET_DEBUG + if (err) + printk (KERN_ERR __FUNCTION__ " %d: return %d\n", current->pid, err); +#endif + return err; +} + +extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); +extern void flush_thread(void); +extern void exit_thread(void); + +extern void exit_mm(struct task_struct *); +extern void exit_fs(struct task_struct *); +extern void exit_files(struct task_struct *); +extern void exit_sighand(struct task_struct *); + +extern void daemonize(void); + +extern int do_execve(char *, char **, char **, struct pt_regs *); +extern int do_fork(unsigned long, unsigned long, struct pt_regs *); + +extern inline void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) +{ + unsigned long flags; + + wq_write_lock_irqsave(&q->lock, flags); + __add_wait_queue(q, wait); + wq_write_unlock_irqrestore(&q->lock, flags); +} + +extern inline void add_wait_queue_exclusive(wait_queue_head_t *q, + wait_queue_t * wait) +{ + unsigned long flags; + + wq_write_lock_irqsave(&q->lock, flags); + __add_wait_queue_tail(q, wait); + wq_write_unlock_irqrestore(&q->lock, flags); +} + +extern inline void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) +{ + unsigned long flags; + + wq_write_lock_irqsave(&q->lock, flags); + __remove_wait_queue(q, wait); + wq_write_unlock_irqrestore(&q->lock, flags); +} + +#define __wait_event(wq, condition) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + if (condition) \ + break; \ + schedule(); \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event(wq, condition) \ +do { \ + if (condition) \ + break; \ + __wait_event(wq, condition); \ +} while (0) + +#define __wait_event_interruptible(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + schedule(); \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_interruptible(wq, condition) \ +({ \ + int __ret = 0; \ + if (!(condition)) \ + __wait_event_interruptible(wq, condition, __ret); \ + __ret; \ +}) + +#define REMOVE_LINKS(p) do { \ + (p)->next_task->prev_task = (p)->prev_task; \ + (p)->prev_task->next_task = (p)->next_task; \ + if ((p)->p_osptr) \ + (p)->p_osptr->p_ysptr = (p)->p_ysptr; \ + if ((p)->p_ysptr) \ + (p)->p_ysptr->p_osptr = (p)->p_osptr; \ + else \ + (p)->p_pptr->p_cptr = (p)->p_osptr; \ + } while (0) + +#define SET_LINKS(p) do { \ + (p)->next_task = &init_task; \ + (p)->prev_task = init_task.prev_task; \ + init_task.prev_task->next_task = (p); \ + init_task.prev_task = (p); \ + (p)->p_ysptr = NULL; \ + if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \ + (p)->p_osptr->p_ysptr = p; \ + (p)->p_pptr->p_cptr = p; \ + } while (0) + +#define for_each_task(p) \ + for (p = &init_task ; (p = p->next_task) != &init_task ; ) + + +static inline void del_from_runqueue(struct task_struct * p) +{ + nr_running--; + list_del(&p->run_list); + p->run_list.next = NULL; +} + +extern inline int task_on_runqueue(struct task_struct *p) +{ + return (p->run_list.next != NULL); +} + +extern inline void unhash_process(struct task_struct *p) +{ + if (task_on_runqueue(p)) BUG(); + write_lock_irq(&tasklist_lock); + nr_threads--; + unhash_pid(p); + REMOVE_LINKS(p); + write_unlock_irq(&tasklist_lock); +} + +static inline int task_lock(struct task_struct *p) +{ + down(&p->exit_sem); + if (p->p_pptr) + return 1; + /* He's dead, Jim. You take his wallet, I'll take the tricorder... */ + up(&p->exit_sem); + return 0; +} + +static inline void task_unlock(struct task_struct *p) +{ + up(&p->exit_sem); +} + +#endif /* __KERNEL__ */ + +#endif diff -urN 2.3.29pre1/include/linux/sched.h.rej 2.3.29pre1-ikd/include/linux/sched.h.rej --- 2.3.29pre1/include/linux/sched.h.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/sched.h.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,18 @@ +*************** +*** 357,362 **** + struct signal_queue *sigqueue, **sigqueue_tail; + unsigned long sas_ss_sp; + size_t sas_ss_size; + }; + + /* +--- 358,366 ---- + struct signal_queue *sigqueue, **sigqueue_tail; + unsigned long sas_ss_sp; + size_t sas_ss_size; ++ #ifdef CONFIG_DEBUG_SOFTLOCKUP ++ unsigned int deadlock_count; ++ #endif + }; + + /* diff -urN 2.3.29pre1/include/linux/sched.h.~1~ 2.3.29pre1-ikd/include/linux/sched.h.~1~ --- 2.3.29pre1/include/linux/sched.h.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/sched.h.~1~ Mon Nov 22 16:56:24 1999 @@ -0,0 +1,864 @@ +#ifndef _LINUX_SCHED_H +#define _LINUX_SCHED_H + +#include /* for HZ */ + +extern unsigned long event; + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * cloning flags: + */ +#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ +#define CLONE_VM 0x00000100 /* set if VM shared between processes */ +#define CLONE_FS 0x00000200 /* set if fs info shared between processes */ +#define CLONE_FILES 0x00000400 /* set if open files shared between processes */ +#define CLONE_SIGHAND 0x00000800 /* set if signal handlers shared */ +#define CLONE_PID 0x00001000 /* set if pid shared */ +#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ +#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ +#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ + +/* + * These are the constant used to fake the fixed-point load-average + * counting. Some notes: + * - 11 bit fractions expand to 22 bits by the multiplies: this gives + * a load-average precision of 10 bits integer + 11 bits fractional + * - if you want to count load-averages more often, you need more + * precision, or rounding will get you. With 2-second counting freq, + * the EXP_n values would be 1981, 2034 and 2043 if still using only + * 11 bit fractions. + */ +extern unsigned long avenrun[]; /* Load averages */ + +#define FSHIFT 11 /* nr of bits of precision */ +#define FIXED_1 (1<>= FSHIFT; + +#define CT_TO_SECS(x) ((x) / HZ) +#define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ) + +extern int nr_running, nr_threads; +extern int last_pid; + +#include +#include +#include +#include +#include + +#include + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 4 +#define TASK_STOPPED 8 +#define TASK_SWAPPING 16 +#define TASK_EXCLUSIVE 32 + +#define __set_task_state(tsk, state_value) \ + do { tsk->state = state_value; } while (0) +#ifdef __SMP__ +#define set_task_state(tsk, state_value) \ + set_mb(tsk->state, state_value) +#else +#define set_task_state(tsk, state_value) \ + __set_task_state(tsk, state_value) +#endif + +#define __set_current_state(state_value) \ + do { current->state = state_value; } while (0) +#ifdef __SMP__ +#define set_current_state(state_value) \ + set_mb(current->state, state_value) +#else +#define set_current_state(state_value) \ + __set_current_state(state_value) +#endif + +/* + * Scheduling policies + */ +#define SCHED_OTHER 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 + +/* + * This is an additional bit set when we want to + * yield the CPU for one re-schedule.. + */ +#define SCHED_YIELD 0x10 + +struct sched_param { + int sched_priority; +}; + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#ifdef __KERNEL__ + +#include + +/* + * This serializes "schedule()" and also protects + * the run-queue from deletions/modifications (but + * _adding_ to the beginning of the run-queue has + * a separate lock). + */ +extern rwlock_t tasklist_lock; +extern spinlock_t runqueue_lock; + +extern void sched_init(void); +extern void init_idle(void); +extern void show_state(void); +extern void cpu_init (void); +extern void trap_init(void); +extern void update_one_process( struct task_struct *p, + unsigned long ticks, unsigned long user, unsigned long system, int cpu); + +#define MAX_SCHEDULE_TIMEOUT LONG_MAX +extern signed long FASTCALL(schedule_timeout(signed long timeout)); +asmlinkage void schedule(void); + +/* + * The default fd array needs to be at least BITS_PER_LONG, + * as this is the granularity returned by copy_fdset(). + */ +#define NR_OPEN_DEFAULT BITS_PER_LONG + +/* + * Open file table structure + */ +struct files_struct { + atomic_t count; + rwlock_t file_lock; + int max_fds; + int max_fdset; + int next_fd; + struct file ** fd; /* current fd array */ + fd_set *close_on_exec; + fd_set *open_fds; + fd_set close_on_exec_init; + fd_set open_fds_init; + struct file * fd_array[NR_OPEN_DEFAULT]; +}; + +#define INIT_FILES { \ + ATOMIC_INIT(1), \ + RW_LOCK_UNLOCKED, \ + NR_OPEN_DEFAULT, \ + __FD_SETSIZE, \ + 0, \ + &init_files.fd_array[0], \ + &init_files.close_on_exec_init, \ + &init_files.open_fds_init, \ + { { 0, } }, \ + { { 0, } }, \ + { NULL, } \ +} + +struct fs_struct { + atomic_t count; + int umask; + struct dentry * root, * pwd; +}; + +#define INIT_FS { \ + ATOMIC_INIT(1), \ + 0022, \ + NULL, NULL \ +} + +/* Maximum number of active map areas.. This is a random (large) number */ +#define MAX_MAP_COUNT (65536) + +/* Number of map areas at which the AVL tree is activated. This is arbitrary. */ +#define AVL_MIN_MAP_COUNT 32 + +struct mm_struct { + struct vm_area_struct * mmap; /* list of VMAs */ + struct vm_area_struct * mmap_avl; /* tree of VMAs */ + struct vm_area_struct * mmap_cache; /* last find_vma result */ + pgd_t * pgd; + atomic_t mm_users; /* How many users with user space? */ + atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ + int map_count; /* number of VMAs */ + struct semaphore mmap_sem; + spinlock_t page_table_lock; + unsigned long context; + unsigned long start_code, end_code, start_data, end_data; + unsigned long start_brk, brk, start_stack; + unsigned long arg_start, arg_end, env_start, env_end; + unsigned long rss, total_vm, locked_vm; + unsigned long def_flags; + unsigned long cpu_vm_mask; + unsigned long swap_cnt; /* number of pages to swap on next pass */ + unsigned long swap_address; + /* + * This is an architecture-specific pointer: the portable + * part of Linux does not know about any segments. + */ + void * segments; +}; + +#define INIT_MM(name) { \ + &init_mmap, NULL, NULL, \ + swapper_pg_dir, \ + ATOMIC_INIT(2), ATOMIC_INIT(1), 1, \ + __MUTEX_INITIALIZER(name.mmap_sem), \ + SPIN_LOCK_UNLOCKED, \ + 0, \ + 0, 0, 0, 0, \ + 0, 0, 0, \ + 0, 0, 0, 0, \ + 0, 0, 0, \ + 0, 0, 0, 0, NULL } + +struct signal_struct { + atomic_t count; + struct k_sigaction action[_NSIG]; + spinlock_t siglock; +}; + + +#define INIT_SIGNALS { \ + ATOMIC_INIT(1), \ + { {{0,}}, }, \ + SPIN_LOCK_UNLOCKED } + +/* + * Some day this will be a full-fledged user tracking system.. + * Right now it is only used to track how many processes a + * user has, but it has the potential to track memory usage etc. + */ +struct user_struct; + +struct task_struct { +/* these are hardcoded - don't touch */ + volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + unsigned long flags; /* per process flags, defined below */ + int sigpending; + mm_segment_t addr_limit; /* thread address space: + 0-0xBFFFFFFF for user-thead + 0-0xFFFFFFFF for kernel-thread + */ + struct exec_domain *exec_domain; + volatile long need_resched; + +/* various fields */ + long counter; + long priority; + cycles_t avg_slice; +/* SMP and runqueue state */ + int has_cpu; + int processor; + int last_processor; + int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */ + struct task_struct *next_task, *prev_task; + struct list_head run_list; + +/* task state */ + struct linux_binfmt *binfmt; + int exit_code, exit_signal; + int pdeath_signal; /* The signal sent when the parent dies */ + /* ??? */ + unsigned long personality; + int dumpable:1; + int did_exec:1; + pid_t pid; + pid_t pgrp; + pid_t tty_old_pgrp; + pid_t session; + /* boolean value for session group leader */ + int leader; + /* + * pointers to (original) parent process, youngest child, younger sibling, + * older sibling, respectively. (p->father can be replaced with + * p->p_pptr->pid) + */ + struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; + + /* PID hash table linkage. */ + struct task_struct *pidhash_next; + struct task_struct **pidhash_pprev; + + wait_queue_head_t wait_chldexit; /* for wait4() */ + struct semaphore *vfork_sem; /* for vfork() */ + unsigned long policy, rt_priority; + unsigned long it_real_value, it_prof_value, it_virt_value; + unsigned long it_real_incr, it_prof_incr, it_virt_incr; + struct timer_list real_timer; + struct tms times; + unsigned long start_time; + long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS]; +/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ + unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; + int swappable:1; +/* process credentials */ + uid_t uid,euid,suid,fsuid; + gid_t gid,egid,sgid,fsgid; + int ngroups; + gid_t groups[NGROUPS]; + kernel_cap_t cap_effective, cap_inheritable, cap_permitted; + struct user_struct *user; +/* limits */ + struct rlimit rlim[RLIM_NLIMITS]; + unsigned short used_math; + char comm[16]; +/* file system info */ + int link_count; + struct tty_struct *tty; /* NULL if no tty */ +/* ipc stuff */ + struct sem_undo *semundo; + struct sem_queue *semsleeping; +/* CPU-specific state of this task */ + struct thread_struct thread; +/* filesystem information */ + struct fs_struct *fs; +/* open file information */ + struct files_struct *files; + +/* memory management info */ + struct mm_struct *mm, *active_mm; + +/* signal handlers */ + spinlock_t sigmask_lock; /* Protects signal and blocked */ + struct signal_struct *sig; + sigset_t signal, blocked; + struct signal_queue *sigqueue, **sigqueue_tail; + unsigned long sas_ss_sp; + size_t sas_ss_size; + +/* Thread group tracking */ + u32 parent_exec_id; + u32 self_exec_id; +/* Protection of fields allocatio/deallocation */ + struct semaphore exit_sem; +}; + +/* + * Per process flags + */ +#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */ + /* Not implemented yet, only for 486*/ +#define PF_STARTING 0x00000002 /* being created */ +#define PF_EXITING 0x00000004 /* getting shut down */ +#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called */ +#define PF_TRACESYS 0x00000020 /* tracing system calls */ +#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ +#define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ +#define PF_DUMPCORE 0x00000200 /* dumped core */ +#define PF_SIGNALED 0x00000400 /* killed by a signal */ +#define PF_MEMALLOC 0x00000800 /* Allocating memory */ +#define PF_VFORK 0x00001000 /* Wake up parent in mm_release */ +#ifdef CONFIG_DEBUG_MCOUNT +#define PF_NO_MCOUNT 0x00002000 /* skip mcount() processing */ +#endif + +#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ +#define PF_DTRACE 0x00200000 /* delayed trace (used on m68k, i386) */ + +/* + * Limit the stack by to some sane default: root can always + * increase this limit if needed.. 8MB seems reasonable. + */ +#define _STK_LIM (8*1024*1024) + +#define DEF_PRIORITY (20*HZ/100) /* 200 ms time slices */ + +/* + * INIT_TASK is used to set up the first task table, touch at + * your own risk!. Base=0, limit=0x1fffff (=2MB) + */ +#define INIT_TASK(name) \ +/* state etc */ { 0,0,0,KERNEL_DS,&default_exec_domain,0, \ +/* counter */ DEF_PRIORITY,DEF_PRIORITY,0, \ +/* SMP */ 0,0,0,-1, \ +/* schedlink */ &init_task,&init_task, LIST_HEAD_INIT(init_task.run_list), \ +/* binfmt */ NULL, \ +/* ec,brk... */ 0,0,0,0,0,0, \ +/* pid etc.. */ 0,0,0,0,0, \ +/* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \ +/* pidhash */ NULL, NULL, \ +/* chld wait */ __WAIT_QUEUE_HEAD_INITIALIZER(name.wait_chldexit), NULL, \ +/* timeout */ SCHED_OTHER,0,0,0,0,0,0,0, \ +/* timer */ { NULL, NULL, 0, 0, it_real_fn }, \ +/* utime */ {0,0,0,0},0, \ +/* per CPU times */ {0, }, {0, }, \ +/* flt */ 0,0,0,0,0,0, \ +/* swp */ 0, \ +/* process credentials */ \ +/* uid etc */ 0,0,0,0,0,0,0,0, \ +/* suppl grps*/ 0, {0,}, \ +/* caps */ CAP_INIT_EFF_SET,CAP_INIT_INH_SET,CAP_FULL_SET, \ +/* user */ NULL, \ +/* rlimits */ INIT_RLIMITS, \ +/* math */ 0, \ +/* comm */ "swapper", \ +/* fs info */ 0,NULL, \ +/* ipc */ NULL, NULL, \ +/* thread */ INIT_THREAD, \ +/* fs */ &init_fs, \ +/* files */ &init_files, \ +/* mm */ NULL, &init_mm, \ +/* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \ +/* exec cts */ 0,0, \ +/* exit_sem */ __MUTEX_INITIALIZER(name.exit_sem), \ +} + +#ifndef INIT_TASK_SIZE +# define INIT_TASK_SIZE 2048*sizeof(long) +#endif + +union task_union { + struct task_struct task; + unsigned long stack[INIT_TASK_SIZE/sizeof(long)]; +}; + +extern union task_union init_task_union; + +extern struct mm_struct init_mm; +extern struct task_struct *init_tasks[NR_CPUS]; + +/* PID hashing. (shouldnt this be dynamic?) */ +#define PIDHASH_SZ (4096 >> 2) +extern struct task_struct *pidhash[PIDHASH_SZ]; + +#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) + +extern __inline__ void hash_pid(struct task_struct *p) +{ + struct task_struct **htable = &pidhash[pid_hashfn(p->pid)]; + + if((p->pidhash_next = *htable) != NULL) + (*htable)->pidhash_pprev = &p->pidhash_next; + *htable = p; + p->pidhash_pprev = htable; +} + +extern __inline__ void unhash_pid(struct task_struct *p) +{ + if(p->pidhash_next) + p->pidhash_next->pidhash_pprev = p->pidhash_pprev; + *p->pidhash_pprev = p->pidhash_next; +} + +extern __inline__ struct task_struct *find_task_by_pid(int pid) +{ + struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)]; + + for(p = *htable; p && p->pid != pid; p = p->pidhash_next) + ; + + return p; +} + +/* per-UID process charging. */ +extern int alloc_uid(struct task_struct *); +void free_uid(struct task_struct *); + +#include + +extern unsigned long volatile jiffies; +extern unsigned long itimer_ticks; +extern unsigned long itimer_next; +extern struct timeval xtime; +extern void do_timer(struct pt_regs *); + +extern unsigned int * prof_buffer; +extern unsigned long prof_len; +extern unsigned long prof_shift; + +#define CURRENT_TIME (xtime.tv_sec) + +extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode)); +extern void FASTCALL(sleep_on(wait_queue_head_t *q)); +extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q, + signed long timeout)); +extern void FASTCALL(interruptible_sleep_on(wait_queue_head_t *q)); +extern long FASTCALL(interruptible_sleep_on_timeout(wait_queue_head_t *q, + signed long timeout)); +extern void FASTCALL(wake_up_process(struct task_struct * tsk)); + +#define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE) +#define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE) + +extern int in_group_p(gid_t); + +extern void flush_signals(struct task_struct *); +extern void flush_signal_handlers(struct task_struct *); +extern int dequeue_signal(sigset_t *, siginfo_t *); +extern int send_sig_info(int, struct siginfo *, struct task_struct *); +extern int force_sig_info(int, struct siginfo *, struct task_struct *); +extern int kill_pg_info(int, struct siginfo *, pid_t); +extern int kill_sl_info(int, struct siginfo *, pid_t); +extern int kill_proc_info(int, struct siginfo *, pid_t); +extern int kill_something_info(int, struct siginfo *, int); +extern void notify_parent(struct task_struct *, int); +extern void force_sig(int, struct task_struct *); +extern int send_sig(int, struct task_struct *, int); +extern int kill_pg(pid_t, int, int); +extern int kill_sl(pid_t, int, int); +extern int kill_proc(pid_t, int, int); +extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *); +extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long); + +extern inline int signal_pending(struct task_struct *p) +{ + return (p->sigpending != 0); +} + +/* Reevaluate whether the task has signals pending delivery. + This is required every time the blocked sigset_t changes. + All callers should have t->sigmask_lock. */ + +static inline void recalc_sigpending(struct task_struct *t) +{ + unsigned long ready; + long i; + + switch (_NSIG_WORDS) { + default: + for (i = _NSIG_WORDS, ready = 0; --i >= 0 ;) + ready |= t->signal.sig[i] &~ t->blocked.sig[i]; + break; + + case 4: ready = t->signal.sig[3] &~ t->blocked.sig[3]; + ready |= t->signal.sig[2] &~ t->blocked.sig[2]; + ready |= t->signal.sig[1] &~ t->blocked.sig[1]; + ready |= t->signal.sig[0] &~ t->blocked.sig[0]; + break; + + case 2: ready = t->signal.sig[1] &~ t->blocked.sig[1]; + ready |= t->signal.sig[0] &~ t->blocked.sig[0]; + break; + + case 1: ready = t->signal.sig[0] &~ t->blocked.sig[0]; + } + + t->sigpending = (ready != 0); +} + +/* True if we are on the alternate signal stack. */ + +static inline int on_sig_stack(unsigned long sp) +{ + return (sp - current->sas_ss_sp < current->sas_ss_size); +} + +static inline int sas_ss_flags(unsigned long sp) +{ + return (current->sas_ss_size == 0 ? SS_DISABLE + : on_sig_stack(sp) ? SS_ONSTACK : 0); +} + +extern int request_irq(unsigned int, + void (*handler)(int, void *, struct pt_regs *), + unsigned long, const char *, void *); +extern void free_irq(unsigned int, void *); + +/* + * This has now become a routine instead of a macro, it sets a flag if + * it returns true (to do BSD-style accounting where the process is flagged + * if it uses root privs). The implication of this is that you should do + * normal permissions checks first, and check suser() last. + * + * [Dec 1997 -- Chris Evans] + * For correctness, the above considerations need to be extended to + * fsuser(). This is done, along with moving fsuser() checks to be + * last. + * + * These will be removed, but in the mean time, when the SECURE_NOROOT + * flag is set, uids don't grant privilege. + */ +extern inline int suser(void) +{ + if (!issecure(SECURE_NOROOT) && current->euid == 0) { + current->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} + +extern inline int fsuser(void) +{ + if (!issecure(SECURE_NOROOT) && current->fsuid == 0) { + current->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} + +/* + * capable() checks for a particular capability. + * New privilege checks should use this interface, rather than suser() or + * fsuser(). See include/linux/capability.h for defined capabilities. + */ + +extern inline int capable(int cap) +{ +#if 1 /* ok now */ + if (cap_raised(current->cap_effective, cap)) +#else + if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0) +#endif + { + current->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} + +/* + * Routines for handling mm_structs + */ +extern struct mm_struct * mm_alloc(void); + +extern struct mm_struct * start_lazy_tlb(void); +extern void end_lazy_tlb(struct mm_struct *mm); + +/* mmdrop drops the mm and the page tables */ +extern inline void FASTCALL(__mmdrop(struct mm_struct *)); +static inline void mmdrop(struct mm_struct * mm) +{ + if (atomic_dec_and_test(&mm->mm_count)) + __mmdrop(mm); +} + +/* mmput gets rid of the mappings and all user-space */ +extern void mmput(struct mm_struct *); +/* Remove the current tasks stale references to the old mm_struct */ +extern void mm_release(void); + +/* + * Routines for handling the fd arrays + */ +extern struct file ** alloc_fd_array(int); +extern int expand_fd_array(struct files_struct *, int nr); +extern void free_fd_array(struct file **, int); + +extern fd_set *alloc_fdset(int); +extern int expand_fdset(struct files_struct *, int nr); +extern void free_fdset(fd_set *, int); + +/* Expand files. Return <0 on error; 0 nothing done; 1 files expanded, + * we may have blocked. + * + * Should be called with the files->file_lock spinlock held for write. + */ +static inline int expand_files(struct files_struct *files, int nr) +{ + int err, expand = 0; +#ifdef FDSET_DEBUG + printk (KERN_ERR __FUNCTION__ " %d: nr = %d\n", current->pid, nr); +#endif + + if (nr >= files->max_fdset) { + expand = 1; + if ((err = expand_fdset(files, nr))) + goto out; + } + if (nr >= files->max_fds) { + expand = 1; + if ((err = expand_fd_array(files, nr))) + goto out; + } + err = expand; + out: +#ifdef FDSET_DEBUG + if (err) + printk (KERN_ERR __FUNCTION__ " %d: return %d\n", current->pid, err); +#endif + return err; +} + +extern int copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); +extern void flush_thread(void); +extern void exit_thread(void); + +extern void exit_mm(struct task_struct *); +extern void exit_fs(struct task_struct *); +extern void exit_files(struct task_struct *); +extern void exit_sighand(struct task_struct *); + +extern void daemonize(void); + +extern int do_execve(char *, char **, char **, struct pt_regs *); +extern int do_fork(unsigned long, unsigned long, struct pt_regs *); + +extern inline void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) +{ + unsigned long flags; + + wq_write_lock_irqsave(&q->lock, flags); + __add_wait_queue(q, wait); + wq_write_unlock_irqrestore(&q->lock, flags); +} + +extern inline void add_wait_queue_exclusive(wait_queue_head_t *q, + wait_queue_t * wait) +{ + unsigned long flags; + + wq_write_lock_irqsave(&q->lock, flags); + __add_wait_queue_tail(q, wait); + wq_write_unlock_irqrestore(&q->lock, flags); +} + +extern inline void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) +{ + unsigned long flags; + + wq_write_lock_irqsave(&q->lock, flags); + __remove_wait_queue(q, wait); + wq_write_unlock_irqrestore(&q->lock, flags); +} + +#define __wait_event(wq, condition) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + if (condition) \ + break; \ + schedule(); \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event(wq, condition) \ +do { \ + if (condition) \ + break; \ + __wait_event(wq, condition); \ +} while (0) + +#define __wait_event_interruptible(wq, condition, ret) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + schedule(); \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_interruptible(wq, condition) \ +({ \ + int __ret = 0; \ + if (!(condition)) \ + __wait_event_interruptible(wq, condition, __ret); \ + __ret; \ +}) + +#define REMOVE_LINKS(p) do { \ + (p)->next_task->prev_task = (p)->prev_task; \ + (p)->prev_task->next_task = (p)->next_task; \ + if ((p)->p_osptr) \ + (p)->p_osptr->p_ysptr = (p)->p_ysptr; \ + if ((p)->p_ysptr) \ + (p)->p_ysptr->p_osptr = (p)->p_osptr; \ + else \ + (p)->p_pptr->p_cptr = (p)->p_osptr; \ + } while (0) + +#define SET_LINKS(p) do { \ + (p)->next_task = &init_task; \ + (p)->prev_task = init_task.prev_task; \ + init_task.prev_task->next_task = (p); \ + init_task.prev_task = (p); \ + (p)->p_ysptr = NULL; \ + if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \ + (p)->p_osptr->p_ysptr = p; \ + (p)->p_pptr->p_cptr = p; \ + } while (0) + +#define for_each_task(p) \ + for (p = &init_task ; (p = p->next_task) != &init_task ; ) + + +static inline void del_from_runqueue(struct task_struct * p) +{ + nr_running--; + list_del(&p->run_list); + p->run_list.next = NULL; +} + +extern inline int task_on_runqueue(struct task_struct *p) +{ + return (p->run_list.next != NULL); +} + +extern inline void unhash_process(struct task_struct *p) +{ + if (task_on_runqueue(p)) BUG(); + write_lock_irq(&tasklist_lock); + nr_threads--; + unhash_pid(p); + REMOVE_LINKS(p); + write_unlock_irq(&tasklist_lock); +} + +static inline int task_lock(struct task_struct *p) +{ + down(&p->exit_sem); + if (p->p_pptr) + return 1; + /* He's dead, Jim. You take his wallet, I'll take the tricorder... */ + up(&p->exit_sem); + return 0; +} + +static inline void task_unlock(struct task_struct *p) +{ + up(&p->exit_sem); +} + +#endif /* __KERNEL__ */ + +#endif diff -urN 2.3.29pre1/include/linux/skbuff.h 2.3.29pre1-ikd/include/linux/skbuff.h --- 2.3.29pre1/include/linux/skbuff.h Mon Nov 22 03:55:38 1999 +++ 2.3.29pre1-ikd/include/linux/skbuff.h Mon Nov 22 16:56:24 1999 @@ -164,12 +164,30 @@ extern void skb_unlink(struct sk_buff *buf); extern __u32 skb_queue_len(struct sk_buff_head *list); extern struct sk_buff * skb_peek_copy(struct sk_buff_head *list); + +#ifndef CONFIG_MEMLEAK extern struct sk_buff * alloc_skb(unsigned int size, int priority); extern struct sk_buff * dev_alloc_skb(unsigned int size); extern void kfree_skbmem(struct sk_buff *skb); extern struct sk_buff * skb_clone(struct sk_buff *skb, int priority); extern struct sk_buff * skb_copy(struct sk_buff *skb, int priority); extern struct sk_buff * skb_realloc_headroom(struct sk_buff *skb, int newheadroom); +#else /* CONFIG_MEMLEAK */ + +#include + +extern struct sk_buff * alloc_skb_wrap(unsigned int size, int priority, struct alloc_struct * IDPTR); +extern void kfree_skbmem(struct sk_buff *skb); /* no wrap for this */ +extern struct sk_buff * skb_clone_wrap(struct sk_buff *skb, int priority, struct alloc_struct * IDPTR); +extern struct sk_buff * skb_copy_wrap(struct sk_buff *skb, int priority, struct alloc_struct * IDPTR); +extern struct sk_buff * skb_realloc_headroom_wrap(struct sk_buff *skb, int newheadroom,struct alloc_struct * IDPTR); + +#define alloc_skb(size,priority) MEMLEAK_WRAP(alloc_skb,(size),(priority)) +#define skb_clone(skb,priority) MEMLEAK_WRAP(skb_clone,(skb),(priority)) +#define skb_copy(skb,priority) MEMLEAK_WRAP(skb_copy,(skb),(priority)) +#define skb_realloc_headroom(skb,newheadroom) MEMLEAK_WRAP(skb_realloc_headroom,(skb),(newheadroom)) +#endif /* CONFIG_MEMLEAK */ + #define dev_kfree_skb(a) kfree_skb(a) extern unsigned char * skb_put(struct sk_buff *skb, unsigned int len); extern unsigned char * skb_push(struct sk_buff *skb, unsigned int len); @@ -585,6 +603,7 @@ kfree_skb(skb); } +#ifndef CONFIG_MEMLEAK extern __inline__ struct sk_buff *dev_alloc_skb(unsigned int length) { struct sk_buff *skb; @@ -594,6 +613,16 @@ skb_reserve(skb,16); return skb; } +#else +#define dev_alloc_skb(length) \ +({ \ + struct sk_buff *_skb; \ + _skb = alloc_skb((unsigned int)(length)+16, GFP_ATOMIC); \ + if (_skb) \ + skb_reserve(_skb,16); \ + _skb; \ +}) +#endif /* CONFIG_MEMLEAK */ extern __inline__ struct sk_buff * skb_cow(struct sk_buff *skb, unsigned int headroom) diff -urN 2.3.29pre1/include/linux/slab.h 2.3.29pre1-ikd/include/linux/slab.h --- 2.3.29pre1/include/linux/slab.h Mon Nov 22 03:55:33 1999 +++ 2.3.29pre1-ikd/include/linux/slab.h Mon Nov 22 16:56:24 1999 @@ -9,6 +9,8 @@ #if defined(__KERNEL__) +#include + typedef struct kmem_cache_s kmem_cache_t; #include @@ -48,6 +50,7 @@ extern void kmem_cache_init(void); extern void kmem_cache_sizes_init(void); extern kmem_cache_t *kmem_find_general_cachep(size_t); +#ifndef CONFIG_MEMLEAK extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long, void (*)(void *, kmem_cache_t *, unsigned long), void (*)(void *, kmem_cache_t *, unsigned long)); @@ -59,6 +62,34 @@ extern void *kmalloc(size_t, int); extern void kfree(const void *); extern void kfree_s(const void *, size_t); +#else +extern kmem_cache_t *kmem_cache_create_wrap(const char *, size_t, size_t, unsigned long, + void (*)(void *, kmem_cache_t *, unsigned long), + void (*)(void *, kmem_cache_t *, unsigned long), struct alloc_struct *); +extern int kmem_cache_shrink(kmem_cache_t *); /* no wrap for this */ +extern int kmem_cache_destroy(kmem_cache_t *); /* no wrap for this */ +extern void *kmem_cache_alloc_wrap(kmem_cache_t *, int, struct alloc_struct *); +extern void kmem_cache_free(kmem_cache_t *, void *); /* no wrap for this */ + +extern void *kmalloc_wrap(unsigned int size, int priority, struct alloc_struct *); +extern void kfree(const void *); +extern void kfree_s(const void *, size_t); + +#define kmem_cache_create(name,size,offset,flags,ctor,dtor) \ + MEMLEAK_WRAP(kmem_cache_create,name,size,offset,flags,ctor,dtor) + +#ifndef MEMLEAK_KILL_ALLOCATION +#define kmem_cache_alloc(cachep,flags) \ + MEMLEAK_WRAP(kmem_cache_alloc,cachep,flags) +#else +#define kmem_cache_alloc(cachep,flags) \ + kmem_cache_alloc_wrap((cachep),(flags),NULL) +#endif + +#define kmalloc(size,priority) \ + MEMLEAK_WRAP(kmalloc,size,priority) + +#endif /* CONFIG_MEMLEAK */ extern void kmem_cache_reap(int); extern int get_slabinfo(char *); diff -urN 2.3.29pre1/include/linux/slab.h.orig 2.3.29pre1-ikd/include/linux/slab.h.orig --- 2.3.29pre1/include/linux/slab.h.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/slab.h.orig Mon Nov 22 03:55:33 1999 @@ -0,0 +1,72 @@ +/* + * linux/mm/slab.h + * Written by Mark Hemment, 1996. + * (markhe@nextd.demon.co.uk) + */ + +#if !defined(_LINUX_SLAB_H) +#define _LINUX_SLAB_H + +#if defined(__KERNEL__) + +typedef struct kmem_cache_s kmem_cache_t; + +#include +#include + +/* flags for kmem_cache_alloc() */ +#define SLAB_BUFFER GFP_BUFFER +#define SLAB_ATOMIC GFP_ATOMIC +#define SLAB_USER GFP_USER +#define SLAB_KERNEL GFP_KERNEL +#define SLAB_NFS GFP_NFS +#define SLAB_DMA GFP_DMA + +#define SLAB_LEVEL_MASK 0x0000007fUL +#define SLAB_NO_GROW 0x00001000UL /* don't grow a cache */ + +/* flags to pass to kmem_cache_create(). + * The first 3 are only valid when the allocator as been build + * SLAB_DEBUG_SUPPORT. + */ +#define SLAB_DEBUG_FREE 0x00000100UL /* Peform (expensive) checks on free */ +#define SLAB_DEBUG_INITIAL 0x00000200UL /* Call constructor (as verifier) */ +#define SLAB_RED_ZONE 0x00000400UL /* Red zone objs in a cache */ +#define SLAB_POISON 0x00000800UL /* Poison objects */ +#define SLAB_NO_REAP 0x00001000UL /* never reap from the cache */ +#define SLAB_HWCACHE_ALIGN 0x00002000UL /* align objs on a h/w cache lines */ +#if 0 +#define SLAB_HIGH_PACK 0x00004000UL /* XXX */ +#endif + +/* flags passed to a constructor func */ +#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */ +#define SLAB_CTOR_ATOMIC 0x002UL /* tell constructor it can't sleep */ +#define SLAB_CTOR_VERIFY 0x004UL /* tell constructor it's a verify call */ + +/* prototypes */ +extern void kmem_cache_init(void); +extern void kmem_cache_sizes_init(void); +extern kmem_cache_t *kmem_find_general_cachep(size_t); +extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long, + void (*)(void *, kmem_cache_t *, unsigned long), + void (*)(void *, kmem_cache_t *, unsigned long)); +extern int kmem_cache_destroy(kmem_cache_t *); +extern int kmem_cache_shrink(kmem_cache_t *); +extern void *kmem_cache_alloc(kmem_cache_t *, int); +extern void kmem_cache_free(kmem_cache_t *, void *); + +extern void *kmalloc(size_t, int); +extern void kfree(const void *); +extern void kfree_s(const void *, size_t); + +extern void kmem_cache_reap(int); +extern int get_slabinfo(char *); + +/* System wide caches */ +extern kmem_cache_t *vm_area_cachep; +extern kmem_cache_t *mm_cachep; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SLAB_H */ diff -urN 2.3.29pre1/include/linux/smp.h 2.3.29pre1-ikd/include/linux/smp.h --- 2.3.29pre1/include/linux/smp.h Sun Nov 21 17:46:05 1999 +++ 2.3.29pre1-ikd/include/linux/smp.h Mon Nov 22 16:56:24 1999 @@ -54,6 +54,10 @@ extern int smp_num_cpus; +#if defined(CONFIG_KDB) +extern volatile unsigned long smp_kdb_wait; +extern void smp_kdb_stop(int); +#endif /* CONFIG_KDB */ extern volatile unsigned long smp_msg_data; extern volatile int smp_src_cpu; extern volatile int smp_msg_id; diff -urN 2.3.29pre1/include/linux/sysctl.h 2.3.29pre1-ikd/include/linux/sysctl.h --- 2.3.29pre1/include/linux/sysctl.h Sun Nov 21 03:20:20 1999 +++ 2.3.29pre1-ikd/include/linux/sysctl.h Mon Nov 22 16:56:24 1999 @@ -488,6 +488,10 @@ }; /* CTL_DEBUG names: */ +enum { + DEBUG_KSTACK_METER = 1, + DEBUG_DISABLE_MCOUNT = 2, +}; /* CTL_DEV names: */ enum { diff -urN 2.3.29pre1/include/linux/sysctl.h.orig 2.3.29pre1-ikd/include/linux/sysctl.h.orig --- 2.3.29pre1/include/linux/sysctl.h.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/sysctl.h.orig Sun Nov 21 03:20:20 1999 @@ -0,0 +1,661 @@ +/* + * sysctl.h: General linux system control interface + * + * Begun 24 March 1995, Stephen Tweedie + * + **************************************************************** + **************************************************************** + ** + ** WARNING: + ** The values in this file are exported to user space via + ** the sysctl() binary interface. Do *NOT* change the + ** numbering of any existing values here, and do not change + ** any numbers within any one set of values. If you have + ** to redefine an existing interface, use a new number for it. + ** The kernel will then return ENOTDIR to any application using + ** the old binary interface. + ** + ** --sct + ** + **************************************************************** + **************************************************************** + */ + +#include + +#ifndef _LINUX_SYSCTL_H +#define _LINUX_SYSCTL_H + +#define CTL_MAXNAME 10 + +struct __sysctl_args { + int *name; + int nlen; + void *oldval; + size_t *oldlenp; + void *newval; + size_t newlen; + unsigned long __unused[4]; +}; + +/* Define sysctl names first */ + +/* Top-level names: */ + +/* For internal pattern-matching use only: */ +#ifdef __KERNEL__ +#define CTL_ANY -1 /* Matches any name */ +#define CTL_NONE 0 +#endif + +enum +{ + CTL_KERN=1, /* General kernel info and control */ + CTL_VM=2, /* VM management */ + CTL_NET=3, /* Networking */ + CTL_PROC=4, /* Process info */ + CTL_FS=5, /* Filesystems */ + CTL_DEBUG=6, /* Debugging */ + CTL_DEV=7, /* Devices */ + CTL_BUS=8 /* Buses */ +}; + +/* CTL_BUS names: */ +enum +{ + BUS_ISA=1 /* ISA */ +}; + +/* CTL_KERN names: */ +enum +{ + KERN_OSTYPE=1, /* string: system version */ + KERN_OSRELEASE=2, /* string: system release */ + KERN_OSREV=3, /* int: system revision */ + KERN_VERSION=4, /* string: compile time info */ + KERN_SECUREMASK=5, /* struct: maximum rights mask */ + KERN_PROF=6, /* table: profiling information */ + KERN_NODENAME=7, + KERN_DOMAINNAME=8, + + KERN_CAP_BSET=14, /* int: capability bounding set */ + KERN_PANIC=15, /* int: panic timeout */ + KERN_REALROOTDEV=16, /* real root device to mount after initrd */ + + KERN_SPARC_REBOOT=21, /* reboot command on Sparc */ + KERN_CTLALTDEL=22, /* int: allow ctl-alt-del to reboot */ + KERN_PRINTK=23, /* struct: control printk logging parameters */ + KERN_NAMETRANS=24, /* Name translation */ + KERN_PPC_HTABRECLAIM=25, /* turn htab reclaimation on/off on PPC */ + KERN_PPC_ZEROPAGED=26, /* turn idle page zeroing on/off on PPC */ + KERN_PPC_POWERSAVE_NAP=27, /* use nap mode for power saving */ + KERN_MODPROBE=28, + KERN_SG_BIG_BUFF=29, + KERN_ACCT=30, /* BSD process accounting parameters */ + KERN_PPC_L2CR=31, /* l2cr register on PPC */ + + KERN_RTSIGNR=32, /* Number of rt sigs queued */ + KERN_RTSIGMAX=33, /* Max queuable */ + + KERN_SHMMAX=34, /* int: Maximum shared memory segment */ + KERN_MSGMAX=35, /* int: Maximum size of a messege */ + KERN_MSGMNB=36, /* int: Maximum message queue size */ + KERN_MSGPOOL=37, /* int: Maximum system message pool size */ + KERN_SYSRQ=38, /* int: Sysreq enable */ + KERN_MAX_THREADS=39, /* int: Maximum nr of threads in the system */ + KERN_RANDOM=40, /* Random driver */ + KERN_SHMALL=41, /* int: Maximum size of shared memory */ + KERN_MSGMNI=42, /* int: msg queue identifiers */ + KERN_SEM=43 /* int: sysv semaphore limits */ +}; + + +/* CTL_VM names: */ +enum +{ + VM_SWAPCTL=1, /* struct: Set vm swapping control */ + VM_SWAPOUT=2, /* int: Background pageout interval */ + VM_FREEPG=3, /* struct: Set free page thresholds */ + VM_BDFLUSH=4, /* struct: Control buffer cache flushing */ + VM_OVERCOMMIT_MEMORY=5, /* Turn off the virtual memory safety limit */ + VM_BUFFERMEM=6, /* struct: Set buffer memory thresholds */ + VM_PAGECACHE=7, /* struct: Set cache memory thresholds */ + VM_PAGERDAEMON=8, /* struct: Control kswapd behaviour */ + VM_PGT_CACHE=9, /* struct: Set page table cache parameters */ + VM_PAGE_CLUSTER=10 /* int: set number of pages to swap together */ +}; + + +/* CTL_NET names: */ +enum +{ + NET_CORE=1, + NET_ETHER=2, + NET_802=3, + NET_UNIX=4, + NET_IPV4=5, + NET_IPX=6, + NET_ATALK=7, + NET_NETROM=8, + NET_AX25=9, + NET_BRIDGE=10, + NET_ROSE=11, + NET_IPV6=12, + NET_X25=13, + NET_TR=14, + NET_DECNET=15, + NET_ECONET=16, + NET_KHTTPD=17 +}; + +/* /proc/sys/kernel/random */ +enum +{ + RANDOM_POOLSIZE=1, + RANDOM_ENTROPY_COUNT=2, + RANDOM_READ_THRESH=3, + RANDOM_WRITE_THRESH=4, + RANDOM_BOOT_ID=5, + RANDOM_UUID=6 +}; + +/* /proc/sys/bus/isa */ +enum +{ + BUS_ISA_MEM_BASE=1, + BUS_ISA_PORT_BASE=2, + BUS_ISA_PORT_SHIFT=3 +}; + +/* /proc/sys/net/core */ +enum +{ + NET_CORE_WMEM_MAX=1, + NET_CORE_RMEM_MAX=2, + NET_CORE_WMEM_DEFAULT=3, + NET_CORE_RMEM_DEFAULT=4, +/* was NET_CORE_DESTROY_DELAY */ + NET_CORE_MAX_BACKLOG=6, + NET_CORE_FASTROUTE=7, + NET_CORE_MSG_COST=8, + NET_CORE_MSG_BURST=9, + NET_CORE_OPTMEM_MAX=10 +}; + +/* /proc/sys/net/ethernet */ + +/* /proc/sys/net/802 */ + +/* /proc/sys/net/unix */ + +enum +{ + NET_UNIX_DESTROY_DELAY=1, + NET_UNIX_DELETE_DELAY=2, + NET_UNIX_MAX_DGRAM_QLEN=3, +}; + +/* /proc/sys/net/ipv4 */ +enum +{ + /* v2.0 compatibile variables */ + NET_IPV4_FORWARD=8, + NET_IPV4_DYNADDR=9, + + NET_IPV4_CONF=16, + NET_IPV4_NEIGH=17, + NET_IPV4_ROUTE=18, + NET_IPV4_FIB_HASH=19, + + NET_IPV4_TCP_TIMESTAMPS=33, + NET_IPV4_TCP_WINDOW_SCALING=34, + NET_IPV4_TCP_SACK=35, + NET_IPV4_TCP_RETRANS_COLLAPSE=36, + NET_IPV4_DEFAULT_TTL=37, + NET_IPV4_AUTOCONFIG=38, + NET_IPV4_NO_PMTU_DISC=39, + NET_IPV4_TCP_SYN_RETRIES=40, + NET_IPV4_IPFRAG_HIGH_THRESH=41, + NET_IPV4_IPFRAG_LOW_THRESH=42, + NET_IPV4_IPFRAG_TIME=43, + NET_IPV4_TCP_MAX_KA_PROBES=44, + NET_IPV4_TCP_KEEPALIVE_TIME=45, + NET_IPV4_TCP_KEEPALIVE_PROBES=46, + NET_IPV4_TCP_RETRIES1=47, + NET_IPV4_TCP_RETRIES2=48, + NET_IPV4_TCP_FIN_TIMEOUT=49, + NET_IPV4_IP_MASQ_DEBUG=50, + NET_TCP_SYNCOOKIES=51, + NET_TCP_STDURG=52, + NET_TCP_RFC1337=53, + NET_TCP_SYN_TAILDROP=54, + NET_TCP_MAX_SYN_BACKLOG=55, + NET_IPV4_LOCAL_PORT_RANGE=56, + NET_IPV4_ICMP_ECHO_IGNORE_ALL=57, + NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS=58, + NET_IPV4_ICMP_SOURCEQUENCH_RATE=59, + NET_IPV4_ICMP_DESTUNREACH_RATE=60, + NET_IPV4_ICMP_TIMEEXCEED_RATE=61, + NET_IPV4_ICMP_PARAMPROB_RATE=62, + NET_IPV4_ICMP_ECHOREPLY_RATE=63, + NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64, + NET_IPV4_IGMP_MAX_MEMBERSHIPS=65, + NET_TCP_TW_RECYCLE=66, + NET_IPV4_ALWAYS_DEFRAG=67, + NET_IPV4_TCP_KEEPALIVE_INTVL=68, +}; + +enum { + NET_IPV4_ROUTE_FLUSH=1, + NET_IPV4_ROUTE_MIN_DELAY=2, + NET_IPV4_ROUTE_MAX_DELAY=3, + NET_IPV4_ROUTE_GC_THRESH=4, + NET_IPV4_ROUTE_MAX_SIZE=5, + NET_IPV4_ROUTE_GC_MIN_INTERVAL=6, + NET_IPV4_ROUTE_GC_TIMEOUT=7, + NET_IPV4_ROUTE_GC_INTERVAL=8, + NET_IPV4_ROUTE_REDIRECT_LOAD=9, + NET_IPV4_ROUTE_REDIRECT_NUMBER=10, + NET_IPV4_ROUTE_REDIRECT_SILENCE=11, + NET_IPV4_ROUTE_ERROR_COST=12, + NET_IPV4_ROUTE_ERROR_BURST=13, + NET_IPV4_ROUTE_GC_ELASTICITY=14, + NET_IPV4_ROUTE_MTU_EXPIRES=15, + NET_IPV4_ROUTE_MIN_PMTU=16, + NET_IPV4_ROUTE_MIN_ADVMSS=17 +}; + +enum +{ + NET_PROTO_CONF_ALL=-2, + NET_PROTO_CONF_DEFAULT=-3 + + /* And device ifindices ... */ +}; + +enum +{ + NET_IPV4_CONF_FORWARDING=1, + NET_IPV4_CONF_MC_FORWARDING=2, + NET_IPV4_CONF_PROXY_ARP=3, + NET_IPV4_CONF_ACCEPT_REDIRECTS=4, + NET_IPV4_CONF_SECURE_REDIRECTS=5, + NET_IPV4_CONF_SEND_REDIRECTS=6, + NET_IPV4_CONF_SHARED_MEDIA=7, + NET_IPV4_CONF_RP_FILTER=8, + NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9, + NET_IPV4_CONF_BOOTP_RELAY=10, + NET_IPV4_CONF_LOG_MARTIANS=11, + NET_IPV4_CONF_TAG=12 +}; + +/* /proc/sys/net/ipv6 */ +enum { + NET_IPV6_CONF=16, + NET_IPV6_NEIGH=17, + NET_IPV6_ROUTE=18 +}; + +enum { + NET_IPV6_ROUTE_FLUSH=1, + NET_IPV6_ROUTE_GC_THRESH=2, + NET_IPV6_ROUTE_MAX_SIZE=3, + NET_IPV6_ROUTE_GC_MIN_INTERVAL=4, + NET_IPV6_ROUTE_GC_TIMEOUT=5, + NET_IPV6_ROUTE_GC_INTERVAL=6, + NET_IPV6_ROUTE_GC_ELASTICITY=7, + NET_IPV6_ROUTE_MTU_EXPIRES=8, + NET_IPV6_ROUTE_MIN_ADVMSS=9 +}; + +enum { + NET_IPV6_FORWARDING=1, + NET_IPV6_HOP_LIMIT=2, + NET_IPV6_MTU=3, + NET_IPV6_ACCEPT_RA=4, + NET_IPV6_ACCEPT_REDIRECTS=5, + NET_IPV6_AUTOCONF=6, + NET_IPV6_DAD_TRANSMITS=7, + NET_IPV6_RTR_SOLICITS=8, + NET_IPV6_RTR_SOLICIT_INTERVAL=9, + NET_IPV6_RTR_SOLICIT_DELAY=10 +}; + +/* /proc/sys/net//neigh/ */ +enum { + NET_NEIGH_MCAST_SOLICIT=1, + NET_NEIGH_UCAST_SOLICIT=2, + NET_NEIGH_APP_SOLICIT=3, + NET_NEIGH_RETRANS_TIME=4, + NET_NEIGH_REACHABLE_TIME=5, + NET_NEIGH_DELAY_PROBE_TIME=6, + NET_NEIGH_GC_STALE_TIME=7, + NET_NEIGH_UNRES_QLEN=8, + NET_NEIGH_PROXY_QLEN=9, + NET_NEIGH_ANYCAST_DELAY=10, + NET_NEIGH_PROXY_DELAY=11, + NET_NEIGH_LOCKTIME=12, + NET_NEIGH_GC_INTERVAL=13, + NET_NEIGH_GC_THRESH1=14, + NET_NEIGH_GC_THRESH2=15, + NET_NEIGH_GC_THRESH3=16 +}; + +/* /proc/sys/net/ipx */ + + +/* /proc/sys/net/appletalk */ +enum { + NET_ATALK_AARP_EXPIRY_TIME=1, + NET_ATALK_AARP_TICK_TIME=2, + NET_ATALK_AARP_RETRANSMIT_LIMIT=3, + NET_ATALK_AARP_RESOLVE_TIME=4 +}; + + +/* /proc/sys/net/netrom */ +enum { + NET_NETROM_DEFAULT_PATH_QUALITY=1, + NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER=2, + NET_NETROM_NETWORK_TTL_INITIALISER=3, + NET_NETROM_TRANSPORT_TIMEOUT=4, + NET_NETROM_TRANSPORT_MAXIMUM_TRIES=5, + NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY=6, + NET_NETROM_TRANSPORT_BUSY_DELAY=7, + NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE=8, + NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT=9, + NET_NETROM_ROUTING_CONTROL=10, + NET_NETROM_LINK_FAILS_COUNT=11 +}; + +/* /proc/sys/net/ax25 */ +enum { + NET_AX25_IP_DEFAULT_MODE=1, + NET_AX25_DEFAULT_MODE=2, + NET_AX25_BACKOFF_TYPE=3, + NET_AX25_CONNECT_MODE=4, + NET_AX25_STANDARD_WINDOW=5, + NET_AX25_EXTENDED_WINDOW=6, + NET_AX25_T1_TIMEOUT=7, + NET_AX25_T2_TIMEOUT=8, + NET_AX25_T3_TIMEOUT=9, + NET_AX25_IDLE_TIMEOUT=10, + NET_AX25_N2=11, + NET_AX25_PACLEN=12, + NET_AX25_PROTOCOL=13, + NET_AX25_DAMA_SLAVE_TIMEOUT=14 +}; + +/* /proc/sys/net/rose */ +enum { + NET_ROSE_RESTART_REQUEST_TIMEOUT=1, + NET_ROSE_CALL_REQUEST_TIMEOUT=2, + NET_ROSE_RESET_REQUEST_TIMEOUT=3, + NET_ROSE_CLEAR_REQUEST_TIMEOUT=4, + NET_ROSE_ACK_HOLD_BACK_TIMEOUT=5, + NET_ROSE_ROUTING_CONTROL=6, + NET_ROSE_LINK_FAIL_TIMEOUT=7, + NET_ROSE_MAX_VCS=8, + NET_ROSE_WINDOW_SIZE=9, + NET_ROSE_NO_ACTIVITY_TIMEOUT=10 +}; + +/* /proc/sys/net/x25 */ +enum { + NET_X25_RESTART_REQUEST_TIMEOUT=1, + NET_X25_CALL_REQUEST_TIMEOUT=2, + NET_X25_RESET_REQUEST_TIMEOUT=3, + NET_X25_CLEAR_REQUEST_TIMEOUT=4, + NET_X25_ACK_HOLD_BACK_TIMEOUT=5 +}; + +/* /proc/sys/net/token-ring */ +enum +{ + NET_TR_RIF_TIMEOUT=1 +}; + +/* /proc/sys/net/decnet/ */ +enum { + NET_DECNET_NODE_TYPE = 1, + NET_DECNET_NODE_ADDRESS = 2, + NET_DECNET_NODE_NAME = 3, + NET_DECNET_DEFAULT_DEVICE = 4, + NET_DECNET_TIME_WAIT = 5, + NET_DECNET_DN_COUNT = 6, + NET_DECNET_DI_COUNT = 7, + NET_DECNET_DR_COUNT = 8, + NET_DECNET_DST_GC_INTERVAL = 9, + NET_DECNET_CONF = 10, + NET_DECNET_DEBUG_LEVEL = 255 +}; + +/* /proc/sys/net/khttpd/ */ +enum { + NET_KHTTPD_DOCROOT = 1, + NET_KHTTPD_START = 2, + NET_KHTTPD_STOP = 3, + NET_KHTTPD_UNLOAD = 4, + NET_KHTTPD_CLIENTPORT = 5, + NET_KHTTPD_PERMREQ = 6, + NET_KHTTPD_PERMFORBID = 7, + NET_KHTTPD_LOGGING = 8, + NET_KHTTPD_SERVERPORT = 9, + NET_KHTTPD_DYNAMICSTRING= 10, + NET_KHTTPD_SLOPPYMIME = 11, + NET_KHTTPD_THREADS = 12, + NET_KHTTPD_MAXCONNECT = 13 +}; + +/* /proc/sys/net/decnet/conf/ */ +enum { + NET_DECNET_CONF_LOOPBACK = -2, + NET_DECNET_CONF_DDCMP = -3, + NET_DECNET_CONF_PPP = -4, + NET_DECNET_CONF_X25 = -5, + NET_DECNET_CONF_GRE = -6, + NET_DECNET_CONF_ETHER = -7 + + /* ... and ifindex of devices */ +}; + +/* /proc/sys/net/decnet/conf// */ +enum { + NET_DECNET_CONF_DEV_PRIORITY = 1, + NET_DECNET_CONF_DEV_T1 = 2, + NET_DECNET_CONF_DEV_T2 = 3, + NET_DECNET_CONF_DEV_T3 = 4, + NET_DECNET_CONF_DEV_COST = 5, + NET_DECNET_CONF_DEV_BLKSIZE = 6, + NET_DECNET_CONF_DEV_STATE = 7 +}; + +/* CTL_PROC names: */ + +/* CTL_FS names: */ +enum +{ + FS_NRINODE=1, /* int:current number of allocated inodes */ + FS_STATINODE=2, + FS_MAXINODE=3, /* int:maximum number of inodes that can be allocated */ + FS_NRDQUOT=4, /* int:current number of allocated dquots */ + FS_MAXDQUOT=5, /* int:maximum number of dquots that can be allocated */ + FS_NRFILE=6, /* int:current number of allocated filedescriptors */ + FS_MAXFILE=7, /* int:maximum number of filedescriptors that can be allocated */ + FS_DENTRY=8, + FS_NRSUPER=9, /* int:current number of allocated super_blocks */ + FS_MAXSUPER=10 /* int:maximum number of super_blocks that can be allocated */ +}; + +/* CTL_DEBUG names: */ + +/* CTL_DEV names: */ +enum { + DEV_CDROM=1, + DEV_HWMON=2, + DEV_PARPORT=3 +}; + +/* /proc/sys/dev/cdrom */ +enum { + DEV_CDROM_INFO=1, + DEV_CDROM_AUTOCLOSE=2, + DEV_CDROM_AUTOEJECT=3, + DEV_CDROM_DEBUG=4, + DEV_CDROM_LOCK=5, + DEV_CDROM_CHECK_MEDIA=6 +}; + +/* /proc/sys/dev/parport */ +enum { + DEV_PARPORT_DEFAULT=-3 +}; + +/* /proc/sys/dev/parport/default */ +enum { + DEV_PARPORT_DEFAULT_TIMESLICE=1, + DEV_PARPORT_DEFAULT_SPINTIME=2 +}; + +/* /proc/sys/dev/parport/parport n */ +enum { + DEV_PARPORT_SPINTIME=1, + DEV_PARPORT_HARDWARE=2, + DEV_PARPORT_DEVICES=3, + DEV_PARPORT_AUTOPROBE=16 +}; + +/* /proc/sys/dev/parport/parport n/devices/ */ +enum { + DEV_PARPORT_DEVICES_ACTIVE=-3, +}; + +/* /proc/sys/dev/parport/parport n/devices/device n */ +enum { + DEV_PARPORT_DEVICE_TIMESLICE=1, +}; + +#ifdef __KERNEL__ + +extern asmlinkage long sys_sysctl(struct __sysctl_args *); +extern void sysctl_init(void); + +typedef struct ctl_table ctl_table; + +typedef int ctl_handler (ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + void **context); + +typedef int proc_handler (ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp); + +extern int proc_dostring(ctl_table *, int, struct file *, + void *, size_t *); +extern int proc_dointvec(ctl_table *, int, struct file *, + void *, size_t *); +extern int proc_dointvec_bset(ctl_table *, int, struct file *, + void *, size_t *); +extern int proc_dointvec_minmax(ctl_table *, int, struct file *, + void *, size_t *); +extern int proc_dointvec_jiffies(ctl_table *, int, struct file *, + void *, size_t *); +extern int proc_doulongvec_minmax(ctl_table *, int, struct file *, + void *, size_t *); +extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int, + struct file *, void *, size_t *); + +extern int do_sysctl (int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen); + +extern int do_sysctl_strategy (ctl_table *table, + int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void ** context); + +extern ctl_handler sysctl_string; +extern ctl_handler sysctl_intvec; +extern ctl_handler sysctl_jiffies; + +extern int do_string ( + void *oldval, size_t *oldlenp, void *newval, size_t newlen, + int rdwr, char *data, size_t max); +extern int do_int ( + void *oldval, size_t *oldlenp, void *newval, size_t newlen, + int rdwr, int *data); +extern int do_struct ( + void *oldval, size_t *oldlenp, void *newval, size_t newlen, + int rdwr, void *data, size_t len); + + +/* + * Register a set of sysctl names by calling register_sysctl_table + * with an initialised array of ctl_table's. An entry with zero + * ctl_name terminates the table. table->de will be set up by the + * registration and need not be initialised in advance. + * + * sysctl names can be mirrored automatically under /proc/sys. The + * procname supplied controls /proc naming. + * + * The table's mode will be honoured both for sys_sysctl(2) and + * proc-fs access. + * + * Leaf nodes in the sysctl tree will be represented by a single file + * under /proc; non-leaf nodes will be represented by directories. A + * null procname disables /proc mirroring at this node. + * + * sysctl(2) can automatically manage read and write requests through + * the sysctl table. The data and maxlen fields of the ctl_table + * struct enable minimal validation of the values being written to be + * performed, and the mode field allows minimal authentication. + * + * More sophisticated management can be enabled by the provision of a + * strategy routine with the table entry. This will be called before + * any automatic read or write of the data is performed. + * + * The strategy routine may return: + * <0: Error occurred (error is passed to user process) + * 0: OK - proceed with automatic read or write. + * >0: OK - read or write has been done by the strategy routine, so + * return immediately. + * + * There must be a proc_handler routine for any terminal nodes + * mirrored under /proc/sys (non-terminals are handled by a built-in + * directory handler). Several default handlers are available to + * cover common cases. + */ + +/* A sysctl table is an array of struct ctl_table: */ +struct ctl_table +{ + int ctl_name; /* Binary ID */ + const char *procname; /* Text ID for /proc/sys, or zero */ + void *data; + int maxlen; + mode_t mode; + ctl_table *child; + proc_handler *proc_handler; /* Callback for text formatting */ + ctl_handler *strategy; /* Callback function for all r/w */ + struct proc_dir_entry *de; /* /proc control block */ + void *extra1; + void *extra2; +}; + +/* struct ctl_table_header is used to maintain dynamic lists of + ctl_table trees. */ +struct ctl_table_header +{ + ctl_table *ctl_table; + DLNODE(struct ctl_table_header) ctl_entry; +}; + +struct ctl_table_header * register_sysctl_table(ctl_table * table, + int insert_at_head); +void unregister_sysctl_table(struct ctl_table_header * table); + +#else /* __KERNEL__ */ + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SYSCTL_H */ diff -urN 2.3.29pre1/include/linux/vmalloc.h.orig 2.3.29pre1-ikd/include/linux/vmalloc.h.orig --- 2.3.29pre1/include/linux/vmalloc.h.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/vmalloc.h.orig Mon Nov 22 03:55:38 1999 @@ -0,0 +1,29 @@ +#ifndef __LINUX_VMALLOC_H +#define __LINUX_VMALLOC_H + +#include +#include + +#include + +/* bits in vm_struct->flags */ +#define VM_IOREMAP 0x00000001 /* ioremap() and friends */ +#define VM_ALLOC 0x00000002 /* vmalloc() */ + +struct vm_struct { + unsigned long flags; + void * addr; + unsigned long size; + struct vm_struct * next; +}; + +struct vm_struct * get_vm_area(unsigned long size, unsigned long flags); +void vfree(void * addr); +void * vmalloc(unsigned long size); +long vread(char *buf, char *addr, unsigned long count); +void vmfree_area_pages(unsigned long address, unsigned long size); +int vmalloc_area_pages(unsigned long address, unsigned long size); + +extern struct vm_struct * vmlist; +#endif + diff -urN 2.3.29pre1/include/linux/vmalloc.h.rej 2.3.29pre1-ikd/include/linux/vmalloc.h.rej --- 2.3.29pre1/include/linux/vmalloc.h.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/include/linux/vmalloc.h.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,41 @@ +*************** +*** 13,24 **** + struct vm_struct * next; + }; + + struct vm_struct * get_vm_area(unsigned long size); + void vfree(void * addr); + void * vmalloc(unsigned long size); + long vread(char *buf, char *addr, unsigned long count); + void vmfree_area_pages(unsigned long address, unsigned long size); + int vmalloc_area_pages(unsigned long address, unsigned long size); + + #endif + +--- 13,38 ---- + struct vm_struct * next; + }; + ++ #ifndef CONFIG_MEMLEAK + struct vm_struct * get_vm_area(unsigned long size); ++ #endif + void vfree(void * addr); ++ #ifndef CONFIG_MEMLEAK + void * vmalloc(unsigned long size); ++ #endif + long vread(char *buf, char *addr, unsigned long count); + void vmfree_area_pages(unsigned long address, unsigned long size); ++ #ifndef CONFIG_MEMLEAK + int vmalloc_area_pages(unsigned long address, unsigned long size); ++ #else /* CONFIG_MEMLEAK */ ++ extern void * vmalloc_wrap(unsigned long size, struct alloc_struct *id); ++ extern struct vm_struct * get_vm_area_wrap(unsigned long size, struct alloc_struct *id); ++ extern int vmalloc_area_pages_wrap(unsigned long address, unsigned long size, struct alloc_struct *id); ++ ++ #define vmalloc(size) MEMLEAK_WRAP(vmalloc,size) ++ #define get_vm_area(size) MEMLEAK_WRAP(get_vm_area,size) ++ #define vmalloc_area_pages(address, size) MEMLEAK_WRAP(vmalloc_area_pages,address,size) ++ #endif /* CONFIG_MEMLEAK */ + + #endif + diff -urN 2.3.29pre1/include/net/sock.h 2.3.29pre1-ikd/include/net/sock.h --- 2.3.29pre1/include/net/sock.h Mon Nov 22 04:07:47 1999 +++ 2.3.29pre1-ikd/include/net/sock.h Mon Nov 22 16:56:24 1999 @@ -700,15 +700,38 @@ return a; } +#ifndef CONFIG_MEMLEAK extern struct sock * sk_alloc(int family, int priority, int zero_it); +#endif extern void sk_free(struct sock *sk); +#ifndef CONFIG_MEMLEAK extern struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority); extern struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority); +#else +extern struct sk_buff *sock_wmalloc_wrap(struct sock *sk, + unsigned long size, int force, + int priority, struct alloc_struct *IDPTR); +extern struct sk_buff *sock_rmalloc_wrap(struct sock *sk, + unsigned long size, int force, + int priority, struct alloc_struct *IDPTR); +extern void *sock_kmalloc_wrap(struct sock *sk, int size, int priority, struct alloc_struct *IDPTR); +extern struct sock * sk_alloc_wrap(int family, int priority, int zero_it, struct alloc_struct *IDPTR); + +#define sock_wmalloc(sk,size,force,priority) \ + MEMLEAK_WRAP(sock_wmalloc,(sk),(size),(force),(priority)) +#define sock_rmalloc(sk,size,force,priority) \ + MEMLEAK_WRAP(sock_rmalloc,(sk),(size),(force),(priority)) +#define sock_kmalloc(sk,size,priority) \ + MEMLEAK_WRAP(sock_kmalloc,(sk),(size),(priority)) +#define sk_alloc(family,priority,zero_it) \ + MEMLEAK_WRAP(sk_alloc,(family),(priority),(zero_it)) + +#endif /* CONFIG_MEMLEAK */ extern void sock_wfree(struct sk_buff *skb); extern void sock_rfree(struct sk_buff *skb); extern void sock_cfree(struct sk_buff *skb); @@ -722,12 +745,23 @@ extern int sock_getsockopt(struct socket *sock, int level, int op, char *optval, int *optlen); +#ifndef CONFIG_MEMLEAK extern struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigned long fallback, int noblock, int *errcode); extern void *sock_kmalloc(struct sock *sk, int size, int priority); +#else +extern struct sk_buff *sock_alloc_send_skb_wrap(struct sock *sk, + unsigned long size, + unsigned long fallback, + int noblock, + int *errcode, + struct alloc_struct *IDPTR); +#define sock_alloc_send_skb(sk,size,fallback,noblock,errcode) \ + MEMLEAK_WRAP(sock_alloc_send_skb,sk,size,fallback,noblock,errcode) +#endif extern void sock_kfree_s(struct sock *sk, void *mem, int size); diff -urN 2.3.29pre1/init/main.c 2.3.29pre1-ikd/init/main.c --- 2.3.29pre1/init/main.c Tue Oct 26 21:30:51 1999 +++ 2.3.29pre1-ikd/init/main.c Mon Nov 22 17:15:53 1999 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,10 @@ #include #endif +#if defined(CONFIG_KDB) +#include +#endif + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -102,6 +107,18 @@ extern void dquot_init_hash(void); #endif +#if defined(CONFIG_KDB) +extern void kdb_init(void); +#endif + +#ifdef __sparc__ +extern int serial_console; +#endif + +#ifdef CONFIG_DEBUG_MCOUNT +extern void mcount_init(void); +#endif + /* * Boot command-line arguments */ @@ -358,6 +375,10 @@ if (*str) return 0; console_loglevel = 10; +#if defined(CONFIG_KDB) + if (!strcmp(str,"kdb")) + kdb_flags = KDB_FLAG_EARLYKDB; +#endif /* CONFIG_KDB */ return 1; } @@ -456,6 +477,13 @@ printk(linux_banner); setup_arch(&command_line); paging_init(); +#ifdef CONFIG_MEMLEAK + /* + * memleak_init must run before other xx_init() will start + * eating ram. + */ + memory_end = memleak_init(memory_start,memory_end); +#endif trap_init(); init_IRQ(); sched_init(); @@ -493,6 +521,9 @@ initrd_start = 0; } #endif +#if defined(CONFIG_KDB) + kdb_init(); +#endif mem_init(); kmem_cache_sizes_init(); #ifdef CONFIG_PROC_FS @@ -519,6 +550,13 @@ check_bugs(); printk("POSIX conformance testing by UNIFIX\n"); +#ifdef CONFIG_DEBUG_MCOUNT + mcount_init(); +#endif +#if defined(CONFIG_KDB) + if (kdb_flags & KDB_FLAG_EARLYKDB) + KDB_ENTER(); +#endif /* * We count on the initial thread going ok * Like idlers init is an unlocked kernel thread, which will @@ -567,6 +605,32 @@ } while (call < &__initcall_end); } +#if defined(__SMP__) && defined(CONFIG_KERNEL_DEBUGGING) +void show_one (int i) +{ + static int curr=0x12345678; + + curr++; + *(((volatile int *)0x000b8000)+i)=curr; + *(((volatile int *)0x000b8100)+i)=curr; + *(((volatile int *)0x000b8200)+i)=curr; + *(((volatile int *)0x000b8300)+i)=curr; +} + +void show_us(void) +{ + for (;;) { + __cli(); + show_one(0); + show_one(10); + show_one(20); + show_one(30); + show_one(40); + show_one(50); + } +} +#endif + /* * Ok, the machine is now initialized. None of the devices * have been touched yet, but the CPU subsystem is up and @@ -699,6 +763,10 @@ (void) dup(0); (void) dup(0); +#if defined(CONFIG_KDB) + if (kdb_flags & KDB_FLAG_EARLYKDB) + KDB_ENTER(); +#endif /* * We try each of these until one succeeds. * diff -urN 2.3.29pre1/init/main.c.orig 2.3.29pre1-ikd/init/main.c.orig --- 2.3.29pre1/init/main.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/init/main.c.orig Tue Oct 26 21:30:51 1999 @@ -0,0 +1,716 @@ +/* + * linux/init/main.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * GK 2/5/95 - Changed to support mounting root fs via NFS + * Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96 + * Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96 + * Simplified starting of init: Michael A. Griffith + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_PCI +#include +#endif + +#ifdef CONFIG_DIO +#include +#endif + +#ifdef CONFIG_ZORRO +#include +#endif + +#ifdef CONFIG_MTRR +# include +#endif + +#ifdef CONFIG_APM +#include +#endif + +#ifdef CONFIG_MAC +extern void nubus_init(void); +#endif + +#ifdef CONFIG_ISAPNP +#include +#endif + +#ifdef CONFIG_IRDA +#include +#endif + +/* + * Versions of gcc older than that listed below may actually compile + * and link okay, but the end product can have subtle run time bugs. + * To avoid associated bogus bug reports, we flatly refuse to compile + * with a gcc that is known to be too old from the very beginning. + */ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) +#error sorry, your GCC is too old. It builds incorrect kernels. +#endif + +extern char _stext, _etext; +extern char *linux_banner; + +extern int console_loglevel; + +static int init(void *); + +extern void init_IRQ(void); +extern void init_modules(void); +extern void sock_init(void); +extern void fork_init(unsigned long); +extern void mca_init(void); +extern void sbus_init(void); +extern void ppc_init(void); +extern void sysctl_init(void); +extern void filescache_init(void); +extern void signals_init(void); +extern int init_pcmcia_ds(void); + +extern void free_initmem(void); +extern void filesystem_setup(void); + +extern void ecard_init(void); + +#if defined(CONFIG_SYSVIPC) +extern void ipc_init(void); +#endif +#if defined(CONFIG_QUOTA) +extern void dquot_init_hash(void); +#endif + +/* + * Boot command-line arguments + */ +#define MAX_INIT_ARGS 8 +#define MAX_INIT_ENVS 8 + +extern void time_init(void); + +int rows, cols; + +#ifdef CONFIG_BLK_DEV_INITRD +kdev_t real_root_dev; +#endif + +int root_mountflags = MS_RDONLY; +char *execute_command = NULL; + +static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; +static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; + +/* + * Read an int from an option string; if available accept a subsequent + * comma as well. + * + * Return values: + * 0 : no int in string + * 1 : int found, no subsequent comma + * 2 : int found including a subsequent comma + */ +int get_option(char **str, int *pint) +{ + char *cur = *str; + + if (!cur || !(*cur)) return 0; + *pint = simple_strtol(cur,str,0); + if (cur==*str) return 0; + if (**str==',') { + (*str)++; + return 2; + } + + return 1; +} + +char *get_options(char *str, int nints, int *ints) +{ + int res,i=1; + + while (iname); + if (strncmp(line,dev->name,len) == 0) { + line += len; + base = dev->num; + break; + } + dev++; + } while (dev->name); + } + return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16)); +} + +static int __init root_dev_setup(char *line) +{ + ROOT_DEV = name_to_kdev_t(line); + return 1; +} + +__setup("root=", root_dev_setup); + +static int __init checksetup(char *line) +{ + struct kernel_param *p; + + p = &__setup_start; + do { + int n = strlen(p->str); + if (!strncmp(line,p->str,n)) { + if (p->setup_func(line+n)) + return 1; + } + p++; + } while (p < &__setup_end); + return 0; +} + +/* this should be approx 2 Bo*oMips to start (note initial shift), and will + still work even if initially too large, it will just take slightly longer */ +unsigned long loops_per_sec = (1<<12); + +/* This is the number of bits of precision for the loops_per_second. Each + bit takes on average 1.5/HZ seconds. This (like the original) is a little + better than 1% */ +#define LPS_PREC 8 + +void __init calibrate_delay(void) +{ + unsigned long ticks, loopbit; + int lps_precision = LPS_PREC; + + loops_per_sec = (1<<12); + + printk("Calibrating delay loop... "); + while (loops_per_sec <<= 1) { + /* wait for "start of" clock tick */ + ticks = jiffies; + while (ticks == jiffies) + /* nothing */; + /* Go .. */ + ticks = jiffies; + __delay(loops_per_sec); + ticks = jiffies - ticks; + if (ticks) + break; + } + +/* Do a binary approximation to get loops_per_second set to equal one clock + (up to lps_precision bits) */ + loops_per_sec >>= 1; + loopbit = loops_per_sec; + while ( lps_precision-- && (loopbit >>= 1) ) { + loops_per_sec |= loopbit; + ticks = jiffies; + while (ticks == jiffies); + ticks = jiffies; + __delay(loops_per_sec); + if (jiffies != ticks) /* longer than 1 tick */ + loops_per_sec &= ~loopbit; + } + +/* finally, adjust loops per second in terms of seconds instead of clocks */ + loops_per_sec *= HZ; +/* Round the value and print it */ + printk("%lu.%02lu BogoMIPS\n", + (loops_per_sec+2500)/500000, + ((loops_per_sec+2500)/5000) % 100); +} + +static int __init readonly(char *str) +{ + if (*str) + return 0; + root_mountflags |= MS_RDONLY; + return 1; +} + +static int __init readwrite(char *str) +{ + if (*str) + return 0; + root_mountflags &= ~MS_RDONLY; + return 1; +} + +static int __init debug_kernel(char *str) +{ + if (*str) + return 0; + console_loglevel = 10; + return 1; +} + +__setup("ro", readonly); +__setup("rw", readwrite); +__setup("debug", debug_kernel); + +/* + * This is a simple kernel command line parsing function: it parses + * the command line, and fills in the arguments/environment to init + * as appropriate. Any cmd-line option is taken to be an environment + * variable if it contains the character '='. + * + * This routine also checks for options meant for the kernel. + * These options are not given to init - they are for internal kernel use only. + */ +static void __init parse_options(char *line) +{ + char *next; + int args, envs; + + if (!*line) + return; + args = 0; + envs = 1; /* TERM is set to 'linux' by default */ + next = line; + while ((line = next) != NULL) { + if ((next = strchr(line,' ')) != NULL) + *next++ = 0; + if (!strncmp(line,"init=",5)) { + line += 5; + execute_command = line; + /* In case LILO is going to boot us with default command line, + * it prepends "auto" before the whole cmdline which makes + * the shell think it should execute a script with such name. + * So we ignore all arguments entered _before_ init=... [MJ] + */ + args = 0; + continue; + } + if (checksetup(line)) + continue; + + /* + * Then check if it's an environment variable or + * an option. + */ + if (strchr(line,'=')) { + if (envs >= MAX_INIT_ENVS) + break; + envp_init[++envs] = line; + } else { + if (args >= MAX_INIT_ARGS) + break; + argv_init[++args] = line; + } + } + argv_init[args+1] = NULL; + envp_init[envs+1] = NULL; +} + + +extern void setup_arch(char **); +extern void cpu_idle(void); + +#ifndef __SMP__ + +#define smp_init() do { } while (0) + +#else + +/* Called by boot processor to activate the rest. */ +static void __init smp_init(void) +{ + /* Get other processors into their bootup holding patterns. */ + smp_boot_cpus(); + smp_threads_ready=1; + smp_commence(); +} + +#endif + +/* + * Activate the first processor. + */ + +asmlinkage void __init start_kernel(void) +{ + char * command_line; + unsigned long mempages; +/* + * Interrupts are still disabled. Do necessary setups, then + * enable them + */ + lock_kernel(); + printk(linux_banner); + setup_arch(&command_line); + paging_init(); + trap_init(); + init_IRQ(); + sched_init(); + time_init(); + parse_options(command_line); + + /* + * HACK ALERT! This is early. We're enabling the console before + * we've done PCI setups etc, and console_init() must be aware of + * this. But we do want output early, in case something goes wrong. + */ + console_init(); +#ifdef CONFIG_MODULES + init_modules(); +#endif + if (prof_shift) { + unsigned int size; + /* only text is profiled */ + prof_len = (unsigned long) &_etext - (unsigned long) &_stext; + prof_len >>= prof_shift; + + size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1; + prof_buffer = (unsigned int *) alloc_bootmem(size); + memset(prof_buffer, 0, size); + } + + kmem_cache_init(); + sti(); + calibrate_delay(); +#ifdef CONFIG_BLK_DEV_INITRD + // FIXME, use the bootmem.h interface. + if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) { + printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " + "disabling it.\n",initrd_start,memory_start); + initrd_start = 0; + } +#endif + mem_init(); + kmem_cache_sizes_init(); +#ifdef CONFIG_PROC_FS + proc_root_init(); +#endif + mempages = num_physpages; + + fork_init(mempages); + filescache_init(); + dcache_init(); + vma_init(); + buffer_init(mempages); + page_cache_init(mempages); + kiobuf_init(); + signals_init(); + inode_init(); + file_table_init(); +#if defined(CONFIG_SYSVIPC) + ipc_init(); +#endif +#if defined(CONFIG_QUOTA) + dquot_init_hash(); +#endif + check_bugs(); + printk("POSIX conformance testing by UNIFIX\n"); + + /* + * We count on the initial thread going ok + * Like idlers init is an unlocked kernel thread, which will + * make syscalls (and thus be locked). + */ + smp_init(); + kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + unlock_kernel(); + current->need_resched = 1; + cpu_idle(); +} + +#ifdef CONFIG_BLK_DEV_INITRD +static int do_linuxrc(void * shell) +{ + static char *argv[] = { "linuxrc", NULL, }; + + close(0);close(1);close(2); + setsid(); + (void) open("/dev/console",O_RDWR,0); + (void) dup(0); + (void) dup(0); + return execve(shell, argv, envp_init); +} + +static int __init no_initrd(char *s) +{ + mount_initrd = 0; + return 1; +} + +__setup("noinitrd", no_initrd); + +#endif + +struct task_struct *child_reaper = &init_task; + +static void __init do_initcalls(void) +{ + initcall_t *call; + + call = &__initcall_start; + do { + (*call)(); + call++; + } while (call < &__initcall_end); +} + +/* + * Ok, the machine is now initialized. None of the devices + * have been touched yet, but the CPU subsystem is up and + * running, and memory and process management works. + * + * Now we can finally start doing some real work.. + */ +static void __init do_basic_setup(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + int real_root_mountflags; +#endif + + /* + * Tell the world that we're going to be the grim + * reaper of innocent orphaned children. + * + * We don't want people to have to make incorrect + * assumptions about where in the task array this + * can be found. + */ + child_reaper = current; + +#if defined(CONFIG_MTRR) /* Do this after SMP initialization */ +/* + * We should probably create some architecture-dependent "fixup after + * everything is up" style function where this would belong better + * than in init/main.c.. + */ + mtrr_init(); +#endif + +#ifdef CONFIG_SYSCTL + sysctl_init(); +#endif + + /* + * Ok, at this point all CPU's should be initialized, so + * we can start looking into devices.. + */ +#ifdef CONFIG_PCI + pci_init(); +#endif +#ifdef CONFIG_SBUS + sbus_init(); +#endif +#if defined(CONFIG_PPC) + ppc_init(); +#endif +#ifdef CONFIG_MCA + mca_init(); +#endif +#ifdef CONFIG_ARCH_ACORN + ecard_init(); +#endif +#ifdef CONFIG_ZORRO + zorro_init(); +#endif +#ifdef CONFIG_DIO + dio_init(); +#endif +#ifdef CONFIG_MAC + nubus_init(); +#endif +#ifdef CONFIG_ISAPNP + isapnp_init(); +#endif + + /* Networking initialization needs a process context */ + sock_init(); + +#ifdef CONFIG_BLK_DEV_INITRD + real_root_dev = ROOT_DEV; + real_root_mountflags = root_mountflags; + if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; + else mount_initrd =0; +#endif + + do_initcalls(); + + /* .. filesystems .. */ + filesystem_setup(); + +#ifdef CONFIG_IRDA + irda_device_init(); /* Must be done after protocol initialization */ +#endif +#ifdef CONFIG_PCMCIA + init_pcmcia_ds(); /* Do this last */ +#endif + /* Mount the root filesystem.. */ + mount_root(); + +#ifdef CONFIG_BLK_DEV_INITRD + root_mountflags = real_root_mountflags; + if (mount_initrd && ROOT_DEV != real_root_dev + && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { + int error; + int i, pid; + + pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); + if (pid>0) + while (pid != wait(&i)); + if (MAJOR(real_root_dev) != RAMDISK_MAJOR + || MINOR(real_root_dev) != 0) { + error = change_root(real_root_dev,"/initrd"); + if (error) + printk(KERN_ERR "Change root to /initrd: " + "error %d\n",error); + } + } +#endif +} + +static int init(void * unused) +{ + lock_kernel(); + do_basic_setup(); + + /* + * Ok, we have completed the initial bootup, and + * we're essentially up and running. Get rid of the + * initmem segments and start the user-mode stuff.. + */ + free_initmem(); + unlock_kernel(); + + if (open("/dev/console", O_RDWR, 0) < 0) + printk("Warning: unable to open an initial console.\n"); + + (void) dup(0); + (void) dup(0); + + /* + * We try each of these until one succeeds. + * + * The Bourne shell can be used instead of init if we are + * trying to recover a really broken machine. + */ + + if (execute_command) + execve(execute_command,argv_init,envp_init); + execve("/sbin/init",argv_init,envp_init); + execve("/etc/init",argv_init,envp_init); + execve("/bin/init",argv_init,envp_init); + execve("/bin/sh",argv_init,envp_init); + panic("No init found. Try passing init= option to kernel."); +} diff -urN 2.3.29pre1/init/main.c.rej 2.3.29pre1-ikd/init/main.c.rej --- 2.3.29pre1/init/main.c.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/init/main.c.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,56 @@ +*************** +*** 24,29 **** + #include + #include + #include + + #include + #include +--- 24,30 ---- + #include + #include + #include ++ #include + + #include + #include +*************** +*** 457,462 **** + printk(linux_banner); + setup_arch(&command_line, &memory_start, &memory_end); + memory_start = paging_init(memory_start,memory_end); + trap_init(); + init_IRQ(); + sched_init(); +--- 478,490 ---- + printk(linux_banner); + setup_arch(&command_line, &memory_start, &memory_end); + memory_start = paging_init(memory_start,memory_end); ++ #ifdef CONFIG_MEMLEAK ++ /* ++ * memleak_init must run before other xx_init() will start ++ * eating ram. ++ */ ++ memory_end = memleak_init(memory_start,memory_end); ++ #endif + trap_init(); + init_IRQ(); + sched_init(); +*************** +*** 492,497 **** + } + #endif + mem_init(memory_start,memory_end); + kmem_cache_sizes_init(); + #ifdef CONFIG_PROC_FS + proc_root_init(); +--- 520,528 ---- + } + #endif + mem_init(memory_start,memory_end); ++ #if defined(CONFIG_KDB) ++ kdb_init(); ++ #endif + kmem_cache_sizes_init(); + #ifdef CONFIG_PROC_FS + proc_root_init(); diff -urN 2.3.29pre1/init/main.c.~1~ 2.3.29pre1-ikd/init/main.c.~1~ --- 2.3.29pre1/init/main.c.~1~ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/init/main.c.~1~ Mon Nov 22 16:56:24 1999 @@ -0,0 +1,773 @@ +/* + * linux/init/main.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * GK 2/5/95 - Changed to support mounting root fs via NFS + * Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96 + * Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96 + * Simplified starting of init: Michael A. Griffith + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_PCI +#include +#endif + +#ifdef CONFIG_DIO +#include +#endif + +#ifdef CONFIG_ZORRO +#include +#endif + +#ifdef CONFIG_MTRR +# include +#endif + +#ifdef CONFIG_APM +#include +#endif + +#ifdef CONFIG_MAC +extern void nubus_init(void); +#endif + +#ifdef CONFIG_ISAPNP +#include +#endif + +#ifdef CONFIG_IRDA +#include +#endif + +#if defined(CONFIG_KDB) +#include +#endif + +/* + * Versions of gcc older than that listed below may actually compile + * and link okay, but the end product can have subtle run time bugs. + * To avoid associated bogus bug reports, we flatly refuse to compile + * with a gcc that is known to be too old from the very beginning. + */ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) +#error sorry, your GCC is too old. It builds incorrect kernels. +#endif + +extern char _stext, _etext; +extern char *linux_banner; + +extern int console_loglevel; + +static int init(void *); + +extern void init_IRQ(void); +extern void init_modules(void); +extern void sock_init(void); +extern void fork_init(unsigned long); +extern void mca_init(void); +extern void sbus_init(void); +extern void ppc_init(void); +extern void sysctl_init(void); +extern void filescache_init(void); +extern void signals_init(void); +extern int init_pcmcia_ds(void); + +extern void free_initmem(void); +extern void filesystem_setup(void); + +extern void ecard_init(void); + +#if defined(CONFIG_SYSVIPC) +extern void ipc_init(void); +#endif +#if defined(CONFIG_QUOTA) +extern void dquot_init_hash(void); +#endif + +#if defined(CONFIG_KDB) +extern void kdb_init(void); +#endif + +#ifdef __sparc__ +extern int serial_console; +#endif + +#ifdef CONFIG_DEBUG_MCOUNT +extern void mcount_init(void); +#endif + +/* + * Boot command-line arguments + */ +#define MAX_INIT_ARGS 8 +#define MAX_INIT_ENVS 8 + +extern void time_init(void); + +int rows, cols; + +#ifdef CONFIG_BLK_DEV_INITRD +kdev_t real_root_dev; +#endif + +int root_mountflags = MS_RDONLY; +char *execute_command = NULL; + +static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; +static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; + +/* + * Read an int from an option string; if available accept a subsequent + * comma as well. + * + * Return values: + * 0 : no int in string + * 1 : int found, no subsequent comma + * 2 : int found including a subsequent comma + */ +int get_option(char **str, int *pint) +{ + char *cur = *str; + + if (!cur || !(*cur)) return 0; + *pint = simple_strtol(cur,str,0); + if (cur==*str) return 0; + if (**str==',') { + (*str)++; + return 2; + } + + return 1; +} + +char *get_options(char *str, int nints, int *ints) +{ + int res,i=1; + + while (iname); + if (strncmp(line,dev->name,len) == 0) { + line += len; + base = dev->num; + break; + } + dev++; + } while (dev->name); + } + return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16)); +} + +static int __init root_dev_setup(char *line) +{ + ROOT_DEV = name_to_kdev_t(line); + return 1; +} + +__setup("root=", root_dev_setup); + +static int __init checksetup(char *line) +{ + struct kernel_param *p; + + p = &__setup_start; + do { + int n = strlen(p->str); + if (!strncmp(line,p->str,n)) { + if (p->setup_func(line+n)) + return 1; + } + p++; + } while (p < &__setup_end); + return 0; +} + +/* this should be approx 2 Bo*oMips to start (note initial shift), and will + still work even if initially too large, it will just take slightly longer */ +unsigned long loops_per_sec = (1<<12); + +/* This is the number of bits of precision for the loops_per_second. Each + bit takes on average 1.5/HZ seconds. This (like the original) is a little + better than 1% */ +#define LPS_PREC 8 + +void __init calibrate_delay(void) +{ + unsigned long ticks, loopbit; + int lps_precision = LPS_PREC; + + loops_per_sec = (1<<12); + + printk("Calibrating delay loop... "); + while (loops_per_sec <<= 1) { + /* wait for "start of" clock tick */ + ticks = jiffies; + while (ticks == jiffies) + /* nothing */; + /* Go .. */ + ticks = jiffies; + __delay(loops_per_sec); + ticks = jiffies - ticks; + if (ticks) + break; + } + +/* Do a binary approximation to get loops_per_second set to equal one clock + (up to lps_precision bits) */ + loops_per_sec >>= 1; + loopbit = loops_per_sec; + while ( lps_precision-- && (loopbit >>= 1) ) { + loops_per_sec |= loopbit; + ticks = jiffies; + while (ticks == jiffies); + ticks = jiffies; + __delay(loops_per_sec); + if (jiffies != ticks) /* longer than 1 tick */ + loops_per_sec &= ~loopbit; + } + +/* finally, adjust loops per second in terms of seconds instead of clocks */ + loops_per_sec *= HZ; +/* Round the value and print it */ + printk("%lu.%02lu BogoMIPS\n", + (loops_per_sec+2500)/500000, + ((loops_per_sec+2500)/5000) % 100); +} + +static int __init readonly(char *str) +{ + if (*str) + return 0; + root_mountflags |= MS_RDONLY; + return 1; +} + +static int __init readwrite(char *str) +{ + if (*str) + return 0; + root_mountflags &= ~MS_RDONLY; + return 1; +} + +static int __init debug_kernel(char *str) +{ + if (*str) + return 0; + console_loglevel = 10; +#if defined(CONFIG_KDB) + if (!strcmp(str,"kdb")) + kdb_flags = KDB_FLAG_EARLYKDB; +#endif /* CONFIG_KDB */ + return 1; +} + +__setup("ro", readonly); +__setup("rw", readwrite); +__setup("debug", debug_kernel); + +/* + * This is a simple kernel command line parsing function: it parses + * the command line, and fills in the arguments/environment to init + * as appropriate. Any cmd-line option is taken to be an environment + * variable if it contains the character '='. + * + * This routine also checks for options meant for the kernel. + * These options are not given to init - they are for internal kernel use only. + */ +static void __init parse_options(char *line) +{ + char *next; + int args, envs; + + if (!*line) + return; + args = 0; + envs = 1; /* TERM is set to 'linux' by default */ + next = line; + while ((line = next) != NULL) { + if ((next = strchr(line,' ')) != NULL) + *next++ = 0; + if (!strncmp(line,"init=",5)) { + line += 5; + execute_command = line; + /* In case LILO is going to boot us with default command line, + * it prepends "auto" before the whole cmdline which makes + * the shell think it should execute a script with such name. + * So we ignore all arguments entered _before_ init=... [MJ] + */ + args = 0; + continue; + } + if (checksetup(line)) + continue; + + /* + * Then check if it's an environment variable or + * an option. + */ + if (strchr(line,'=')) { + if (envs >= MAX_INIT_ENVS) + break; + envp_init[++envs] = line; + } else { + if (args >= MAX_INIT_ARGS) + break; + argv_init[++args] = line; + } + } + argv_init[args+1] = NULL; + envp_init[envs+1] = NULL; +} + + +extern void setup_arch(char **); +extern void cpu_idle(void); + +#ifndef __SMP__ + +#define smp_init() do { } while (0) + +#else + +/* Called by boot processor to activate the rest. */ +static void __init smp_init(void) +{ + /* Get other processors into their bootup holding patterns. */ + smp_boot_cpus(); + smp_threads_ready=1; + smp_commence(); +} + +#endif + +/* + * Activate the first processor. + */ + +asmlinkage void __init start_kernel(void) +{ + char * command_line; + unsigned long mempages; +/* + * Interrupts are still disabled. Do necessary setups, then + * enable them + */ + lock_kernel(); + printk(linux_banner); + setup_arch(&command_line); + paging_init(); + trap_init(); + init_IRQ(); + sched_init(); + time_init(); + parse_options(command_line); + + /* + * HACK ALERT! This is early. We're enabling the console before + * we've done PCI setups etc, and console_init() must be aware of + * this. But we do want output early, in case something goes wrong. + */ + console_init(); +#ifdef CONFIG_MODULES + init_modules(); +#endif + if (prof_shift) { + unsigned int size; + /* only text is profiled */ + prof_len = (unsigned long) &_etext - (unsigned long) &_stext; + prof_len >>= prof_shift; + + size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1; + prof_buffer = (unsigned int *) alloc_bootmem(size); + memset(prof_buffer, 0, size); + } + + kmem_cache_init(); + sti(); + calibrate_delay(); +#ifdef CONFIG_BLK_DEV_INITRD + // FIXME, use the bootmem.h interface. + if (initrd_start && !initrd_below_start_ok && initrd_start < memory_start) { + printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " + "disabling it.\n",initrd_start,memory_start); + initrd_start = 0; + } +#endif + mem_init(); + kmem_cache_sizes_init(); +#ifdef CONFIG_PROC_FS + proc_root_init(); +#endif + mempages = num_physpages; + + fork_init(mempages); + filescache_init(); + dcache_init(); + vma_init(); + buffer_init(mempages); + page_cache_init(mempages); + kiobuf_init(); + signals_init(); + inode_init(); + file_table_init(); +#if defined(CONFIG_SYSVIPC) + ipc_init(); +#endif +#if defined(CONFIG_QUOTA) + dquot_init_hash(); +#endif + check_bugs(); + printk("POSIX conformance testing by UNIFIX\n"); + +#ifdef CONFIG_DEBUG_MCOUNT + mcount_init(); +#endif +#if defined(CONFIG_KDB) + if (kdb_flags & KDB_FLAG_EARLYKDB) + KDB_ENTER(); +#endif + /* + * We count on the initial thread going ok + * Like idlers init is an unlocked kernel thread, which will + * make syscalls (and thus be locked). + */ + smp_init(); + kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + unlock_kernel(); + current->need_resched = 1; + cpu_idle(); +} + +#ifdef CONFIG_BLK_DEV_INITRD +static int do_linuxrc(void * shell) +{ + static char *argv[] = { "linuxrc", NULL, }; + + close(0);close(1);close(2); + setsid(); + (void) open("/dev/console",O_RDWR,0); + (void) dup(0); + (void) dup(0); + return execve(shell, argv, envp_init); +} + +static int __init no_initrd(char *s) +{ + mount_initrd = 0; + return 1; +} + +__setup("noinitrd", no_initrd); + +#endif + +struct task_struct *child_reaper = &init_task; + +static void __init do_initcalls(void) +{ + initcall_t *call; + + call = &__initcall_start; + do { + (*call)(); + call++; + } while (call < &__initcall_end); +} + +#if defined(__SMP__) && defined(CONFIG_KERNEL_DEBUGGING) +void show_one (int i) +{ + static int curr=0x12345678; + + curr++; + *(((volatile int *)0x000b8000)+i)=curr; + *(((volatile int *)0x000b8100)+i)=curr; + *(((volatile int *)0x000b8200)+i)=curr; + *(((volatile int *)0x000b8300)+i)=curr; +} + +void show_us(void) +{ + for (;;) { + __cli(); + show_one(0); + show_one(10); + show_one(20); + show_one(30); + show_one(40); + show_one(50); + } +} +#endif + +/* + * Ok, the machine is now initialized. None of the devices + * have been touched yet, but the CPU subsystem is up and + * running, and memory and process management works. + * + * Now we can finally start doing some real work.. + */ +static void __init do_basic_setup(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + int real_root_mountflags; +#endif + + /* + * Tell the world that we're going to be the grim + * reaper of innocent orphaned children. + * + * We don't want people to have to make incorrect + * assumptions about where in the task array this + * can be found. + */ + child_reaper = current; + +#if defined(CONFIG_MTRR) /* Do this after SMP initialization */ +/* + * We should probably create some architecture-dependent "fixup after + * everything is up" style function where this would belong better + * than in init/main.c.. + */ + mtrr_init(); +#endif + +#ifdef CONFIG_SYSCTL + sysctl_init(); +#endif + + /* + * Ok, at this point all CPU's should be initialized, so + * we can start looking into devices.. + */ +#ifdef CONFIG_PCI + pci_init(); +#endif +#ifdef CONFIG_SBUS + sbus_init(); +#endif +#if defined(CONFIG_PPC) + ppc_init(); +#endif +#ifdef CONFIG_MCA + mca_init(); +#endif +#ifdef CONFIG_ARCH_ACORN + ecard_init(); +#endif +#ifdef CONFIG_ZORRO + zorro_init(); +#endif +#ifdef CONFIG_DIO + dio_init(); +#endif +#ifdef CONFIG_MAC + nubus_init(); +#endif +#ifdef CONFIG_ISAPNP + isapnp_init(); +#endif + + /* Networking initialization needs a process context */ + sock_init(); + +#ifdef CONFIG_BLK_DEV_INITRD + real_root_dev = ROOT_DEV; + real_root_mountflags = root_mountflags; + if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; + else mount_initrd =0; +#endif + + do_initcalls(); + + /* .. filesystems .. */ + filesystem_setup(); + +#ifdef CONFIG_IRDA + irda_device_init(); /* Must be done after protocol initialization */ +#endif +#ifdef CONFIG_PCMCIA + init_pcmcia_ds(); /* Do this last */ +#endif + /* Mount the root filesystem.. */ + mount_root(); + +#ifdef CONFIG_BLK_DEV_INITRD + root_mountflags = real_root_mountflags; + if (mount_initrd && ROOT_DEV != real_root_dev + && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { + int error; + int i, pid; + + pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); + if (pid>0) + while (pid != wait(&i)); + if (MAJOR(real_root_dev) != RAMDISK_MAJOR + || MINOR(real_root_dev) != 0) { + error = change_root(real_root_dev,"/initrd"); + if (error) + printk(KERN_ERR "Change root to /initrd: " + "error %d\n",error); + } + } +#endif +} + +static int init(void * unused) +{ + lock_kernel(); + do_basic_setup(); + + /* + * Ok, we have completed the initial bootup, and + * we're essentially up and running. Get rid of the + * initmem segments and start the user-mode stuff.. + */ + free_initmem(); + unlock_kernel(); + + if (open("/dev/console", O_RDWR, 0) < 0) + printk("Warning: unable to open an initial console.\n"); + + (void) dup(0); + (void) dup(0); + +#if defined(CONFIG_KDB) + if (kdb_flags & KDB_FLAG_EARLYKDB) + KDB_ENTER(); +#endif + /* + * We try each of these until one succeeds. + * + * The Bourne shell can be used instead of init if we are + * trying to recover a really broken machine. + */ + + if (execute_command) + execve(execute_command,argv_init,envp_init); + execve("/sbin/init",argv_init,envp_init); + execve("/etc/init",argv_init,envp_init); + execve("/bin/init",argv_init,envp_init); + execve("/bin/sh",argv_init,envp_init); + panic("No init found. Try passing init= option to kernel."); +} diff -urN 2.3.29pre1/kernel/Makefile 2.3.29pre1-ikd/kernel/Makefile --- 2.3.29pre1/kernel/Makefile Tue Jul 13 02:02:40 1999 +++ 2.3.29pre1-ikd/kernel/Makefile Mon Nov 22 16:56:24 1999 @@ -10,6 +10,10 @@ .S.s: $(CPP) -traditional $< -o $*.s +SUB_DIRS := debug +MOD_SUB_DIRS := debug +ALL_SUB_DIRS := debug + O_TARGET := kernel.o O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ diff -urN 2.3.29pre1/kernel/debug/Config.in 2.3.29pre1-ikd/kernel/debug/Config.in --- 2.3.29pre1/kernel/debug/Config.in Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/kernel/debug/Config.in Mon Nov 22 16:56:24 1999 @@ -0,0 +1,41 @@ +# +# Common kernel debugging configuration. arch specific debugging facilities +# are in arch/xxx/config.in. +# + bool 'Kernel debugging support' CONFIG_KERNEL_DEBUGGING n + if [ "$CONFIG_KERNEL_DEBUGGING" = "y" ]; then + bool ' GFP poison' CONFIG_GFP_POISON n + bool ' SLAB poison' CONFIG_SLAB_POISON n + bool ' Semphore deadlock detector' CONFIG_SEMAPHORE_DEADLOCK n + bool ' Debug kernel stack overflows' CONFIG_DEBUG_KSTACK n + if [ "$CONFIG_DEBUG_KSTACK" = "y" ]; then + int ' Stack threshold' CONFIG_KSTACK_THRESHOLD 500 + fi + bool ' Kernel Stack Meter' CONFIG_KSTACK_METER n + bool ' Detect software lockups' CONFIG_DEBUG_SOFTLOCKUP n + if [ "$CONFIG_DEBUG_SOFTLOCKUP" = "y" ]; then + int ' Deadlock threshold' CONFIG_SOFTLOCKUP_THRESHOLD 100000000 0 2147483647 + fi + bool ' GCC profiling support' CONFIG_PROFILE_GCC n + bool ' Enable kernel tracer' CONFIG_TRACE n + if [ "$CONFIG_TRACE" = "y" ]; then + int ' Trace ringbuffer size' CONFIG_TRACE_SIZE 16384 + bool ' Trace timestamps' CONFIG_TRACE_TIMESTAMP n + if [ "$CONFIG_TRACE_TIMESTAMP" = "y" ]; then + bool ' Truncate timestamp' CONFIG_TRACE_TRUNCTIME n + fi + bool ' Process ID' CONFIG_TRACE_PID n + bool ' Cpu ID' CONFIG_TRACE_CPU n + fi + # CONFIG_DEBUG_MCOUNT is "y" iff an option requires calls to mcount(). + if [ "$CONFIG_DEBUG_KSTACK" = "y" -o \ + "$CONFIG_DEBUG_SOFTLOCKUP" = "y" -o \ + "$CONFIG_KSTACK_METER" = "y" -o \ + "$CONFIG_TRACE" = "y" -o \ + "$CONFIG_PRINT_EIP" = "y" -o \ + "$CONFIG_PROFILE_GCC" = "y" ]; then + define_bool CONFIG_DEBUG_MCOUNT y + else + define_bool CONFIG_DEBUG_MCOUNT n + fi + fi diff -urN 2.3.29pre1/kernel/debug/Makefile 2.3.29pre1-ikd/kernel/debug/Makefile --- 2.3.29pre1/kernel/debug/Makefile Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/kernel/debug/Makefile Mon Nov 22 16:56:24 1999 @@ -0,0 +1,17 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +ifeq ($(CONFIG_KERNEL_DEBUGGING),y) + O_TARGET := debug.o + OX_OBJS = profiler.o + # Must turn off profiling for the profiler. + override CFLAGS := $(CFLAGS:%-pg=%-g -c) +endif + +include $(TOPDIR)/Rules.make diff -urN 2.3.29pre1/kernel/debug/profiler.c 2.3.29pre1-ikd/kernel/debug/profiler.c --- 2.3.29pre1/kernel/debug/profiler.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/kernel/debug/profiler.c Mon Nov 22 16:56:24 1999 @@ -0,0 +1,411 @@ +/* + * linux/kernel/profiler.c + * + * Copyright (C) 1997 Ingo Molnar, Richard Henderson + * Copyright (C) 1998 Andrea Arcangeli + * + * This source is covered by the GNU GPL, the same as all kernel sources. + */ + +/* + * 'profiler.c' implements various profiling hacks, by abusing the profiling + * hook 'mcount', generated by GCC -pg + * + * Currently used for: + * + * - monitoring kernel stack usage and generating oopses when stack overflow + * - detecting software lockups + * - tracing the kernel + * + * Has to be a separate C module, because we have to compile it without -pg, + * to avoid recursion. + */ + +/* + * - print-eip is now a config option and it' s improved to give as the + * the execution order of the box and fixed some glitches. + * - developed CONFIG_PROFILE_GCC + * - developed CONFIG_KSTACK_METER + * - fixed get_stack_left() to handle the 8k 2.1.x kernel stack size. + * -arca + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Generally we dislike #ifdef's in main modules, but these mcount() based + * features are is too performance-sensitive to make them an all or nothing + * option, and too small to be put into header files. + */ + +#ifdef CONFIG_DEBUG_MCOUNT /* any mcount() functions activated? */ + +#ifdef CONFIG_TRACE + +spinlock_t trace_table_lock = SPIN_LOCK_UNLOCKED; +struct trace_table *trace_table = NULL; + +#endif /* CONFIG_TRACE */ + +#ifdef CONFIG_KSTACK_METER +struct { + unsigned int min_left_stack; + profiler_pc_t stack_eater_eip; +} kstack_meter = {-1UL, 0,}; + +static spinlock_t stack_meter_lock = SPIN_LOCK_UNLOCKED; +#endif + +/* deal with too early calls to mcount() and recursion */ +atomic_t mcount_ready = ATOMIC_INIT(0); +int sysctl_disable_mcount = 0; +#ifdef CONFIG_TRACE +atomic_t mcount_trace_ready = ATOMIC_INIT(0); +#endif + +void mcount_init (void) +{ +#ifdef CONFIG_TRACE + if ((trace_table = vmalloc(sizeof(*trace_table))) == NULL) { + printk("mcount_init: cannot vmalloc trace_table, size %lu. No tracing possible.\n", (unsigned long) sizeof(*trace_table)); + } + else { + trace_table->table_size = CONFIG_TRACE_SIZE; + trace_table->curr_call = 0; + memset(trace_table->entries, 0, sizeof(trace_table->entries)); + spin_lock_init(&trace_table_lock); +#ifdef CONFIG_TRACE_TIMESTAMP +#ifdef __i386__ + if (!(boot_cpu_data.x86_capability & 0x10)) + printk("mcount_init: cpu does not support rdtsc, timestamps are jiffies instead\n"); +#else + printk("mcount_init: not i386 cpu, timestamps are jiffies instead\n"); +#endif /* __i386__ */ +#endif /* CONFIG_TRACE_TIMESTAMP */ + RESUME_MCOUNT_TRACE; /* start it */ + } +#endif /* CONFIG_TRACE */ + + printk("mcount_init\n"); + /* + * Ok, from now on it's for real: + */ + RESUME_MCOUNT; /* start it */ +} + +#ifdef CONFIG_TRACE + +/* Strictly speaking this routine should get the trace_table spin lock. + * However it is rarely used and may not be in a safe context to get the + * lock so we just dump the table and hope it does not change under us. + */ + +void print_emergency_trace (void) +{ + struct trace_entry *t; + int i, j; + + SUSPEND_MCOUNT_TRACE; + printk ("[] "); + +/* + * Well, 30 entries is pretty arbitrary, seems to be a reasonable value. + */ + j = trace_table->curr_call-30; + for (i=0; i<30; i++) { + j %= CONFIG_TRACE_SIZE; /* wraparound */ + t = &(trace_table->entries[j++]); + /* ksymoops expects [] */ + printk ("[<%08lx>] ", t->pc); +#ifdef CONFIG_TRACE_PID + printk("%d ", t->pid); +#endif +#if defined(CONFIG_TRACE_CPU) && defined(__SMP__) + printk("%d ", t->cpu); +#endif + } + RESUME_MCOUNT_TRACE; +} +#endif /* CONFIG_TRACE */ + +#ifdef __i386__ +/* + * this (64 bytes) is twice as big as cachelines, but we cannot + * guarantee cacheline alignment ... too bad. So we waste two + * cachelines in the bad case. + * + * cacheline alignment is absolutely vital in this case, as these + * variables are higher frequented than say .. "current", and they + * should stay local on the owner CPU under all circumstances. + */ +struct cacheline_t { unsigned int i; int __dummy[15]; }; + +#ifdef CONFIG_PRINT_EIP +/* + * Use this as last resort, when nothing else helps. If a hard lockup + * happens then you can decode the last EIP from the binary coded + * form on the screen. + */ + +static __inline__ void print_eip(unsigned int eip) +{ +#define video ((short int *)(0x000b8000 + __PAGE_OFFSET)) +#define HISTORY 24 +#define ALIGN __attribute__((aligned(4))) + + int i, value; + unsigned int tmp; + + /* + * We split the codepath in a dumb way, to get speed and proper + * per-CPU execution. + */ +#ifdef __SMP__ + if (!smp_processor_id()) + { +#endif + static struct cacheline_t curr_pos_0 ALIGN ={0,}; + static unsigned int count_0 = 0; + /* + * we cover 1M of code currently ... should be enuff + */ + if ((curr_pos_0.i += 80) == HISTORY*80) + curr_pos_0.i = 0; + + for (i=7; i>=0; i--) + { + /* + * mask off the hexa digits one by one. + */ + value = eip & 0xf; + if (value<10) + *(video+i+curr_pos_0.i) = 0x5400 + (value+'0'); + else + *(video+i+curr_pos_0.i) = 0x5400 + (value-10+'a'); + eip >>= 4; + } + /* *(video+8+curr_pos_0.i) = 0x5400 + '=';*/ + tmp = count_0++; + for (i=3; i>=0; i--) + { + /* + * mask off the hexa digits one by one. + */ + value = tmp & 0xf; + if (value<10) + *(video+i+9+curr_pos_0.i) = 0x5400 + (value+'0'); + else + *(video+i+9+curr_pos_0.i) = 0x5400 + (value-10+'a'); + tmp >>= 4; + } +#ifdef __SMP__ + } else { + static struct cacheline_t curr_pos_1 ALIGN ={0,}; + static unsigned int count_1 = 0; + /* + * we cover 1M of code currently ... should be enuff + */ + + if ((curr_pos_1.i += 80) == HISTORY*80) + curr_pos_1.i = 0; + + for (i=7; i>=0; i--) { + /* + * mask off the hexa digits one by one. + */ + value = eip & 0xf; + if (value<10) + *(video+40+i+curr_pos_1.i) = 0x6400 + (value+'0'); + else + *(video+40+i+curr_pos_1.i) = 0x6400 + (value-10+'a'); + eip >>= 4; + } + /* *(video+48+curr_pos_1.i) = 0x6400 + '=';*/ + tmp = count_1++; + for (i=3; i>=0; i--) { + /* + * mask off the hexa digits one by one. + */ + value = tmp & 0xf; + if (value<10) + *(video+i+49+curr_pos_1.i) = 0x6400 + (value+'0'); + else + *(video+i+49+curr_pos_1.i) = 0x6400 + (value-10+'a'); + tmp >>= 4; + } + } +#endif /* __SMP__ */ + +#undef ALIGN +#undef HISTORY +#undef video +} + +#endif /* CONFIG_PRINT_EIP */ +#endif /* __i386__ */ + +#ifdef CONFIG_PROFILE_GCC /* arca */ +static __inline__ void kernel_profiling(profiler_pc_t eip) +{ + extern char _stext; + extern unsigned int * prof_buffer; + + if (!prof_buffer) + return; + + eip -= (unsigned long) &_stext; + eip >>= prof_shift; + /* + * Don't ignore out-of-bounds EIP values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (eip > prof_len-1) + eip = prof_len-1; + + atomic_inc((atomic_t *)&prof_buffer[eip]); +} +#endif + +/* Watch this routine and mcount for any hidden calls to external + * routines. On SMP, something as simple as save_flags() calls + * __global_save_flags() in irq.c. If that module was compiled with + * -pg it calls back to mcount, stack overflow due to recursion. nm + * profiler.o should show no references to external procedures except + * for printk and vmalloc (from mcount_init). KAO. + */ + +inline int mcount_internal(profiler_pc_t self_addr) +{ +#ifdef CONFIG_PRINT_EIP + print_eip(self_addr); +#endif + +#ifdef CONFIG_PROFILE_GCC + kernel_profiling(self_addr); +#endif + +#ifdef CONFIG_DEBUG_SOFTLOCKUP + switch (current->deadlock_count) { + case 0: + if (current->pid) { + SUSPEND_MCOUNT; + printk("Deadlock threshold zero, should not happen, pid %d\n", current->pid); + RESUME_MCOUNT; + } + current->deadlock_count--; + return 0; + + case 1: + /* + * Oops on return. Do the oops outside this routine so + * mcount_ready and trace_table_lock are in a clean state. + */ + current->deadlock_count = 0; + /* no more mcount() processing for this process */ + SUSPEND_MCOUNT_PROC(current); + printk("Deadlock threshold exceeded, forcing Oops.\n"); + return 1; /* caller should oops */ + break; + + default: + current->deadlock_count--; + break; + } +#endif /* CONFIG_DEBUG_SOFTLOCKUP */ + +#ifdef CONFIG_DEBUG_KSTACK + if (get_stack_left() - sizeof(struct task_struct) /* accounted the tss -arca */ + < CONFIG_KSTACK_THRESHOLD) { + SUSPEND_MCOUNT_PROC(current); + printk(KERN_ALERT "kernel stack overflow. Forcing Oops.\n"); + return 1; + } +#endif /* CONFIG_DEBUG_KSTACK */ + +#ifdef CONFIG_KSTACK_METER /* arca */ + { + unsigned int left_stack, flags; + + /* + * One CPU per time to be sure that min_left_stack is really + * the minimum. -arca + */ + spin_lock_irqsave(&stack_meter_lock, flags); + left_stack = get_stack_left() - sizeof(struct task_struct); + if (left_stack < kstack_meter.min_left_stack) + { + kstack_meter.min_left_stack = left_stack; + kstack_meter.stack_eater_eip = self_addr; + } + spin_unlock_irqrestore(&stack_meter_lock, flags); + } +#endif + +#ifdef CONFIG_TRACE + { + /* Protected by trace_table_lock */ + struct trace_entry *t; + ++(trace_table->curr_call); + while (trace_table->curr_call >= CONFIG_TRACE_SIZE) { + trace_table->curr_call -= CONFIG_TRACE_SIZE; + } + + t = &(trace_table->entries[trace_table->curr_call]); + + t->pc = self_addr; +#ifdef CONFIG_TRACE_TIMESTAMP + t->timestamp = get_profiler_timestamp(); +#endif +#ifdef CONFIG_TRACE_PID + t->pid = current->pid; +#endif +#if defined(CONFIG_TRACE_CPU) && defined(__SMP__) + t->cpu = smp_processor_id(); +#endif + } +#endif /* CONFIG_TRACE */ + return 0; +} + +#ifdef __i386__ + +void mcount(void) +{ + int do_oops; +#ifdef CONFIG_TRACE + unsigned long flags; +#endif + if (sysctl_disable_mcount || atomic_read(&mcount_ready) <= 0) + return; + +#ifdef CONFIG_TRACE + if (atomic_read(&mcount_trace_ready) <= 0) + return; +#endif + + if (current->flags & PF_NO_MCOUNT) + return; + + LOCK_MCOUNT_TRACE(flags); + do_oops = mcount_internal((profiler_pc_t)__builtin_return_address(0)); + UNLOCK_MCOUNT_TRACE(flags); + + /* Do oops with mcount_ready and trace_table_lock in a clean state */ + if (do_oops) + *(char *)0=0; +} + +#ifdef CONFIG_MODULES +EXPORT_SYMBOL_NOVERS(mcount); +#endif + +#endif /* __i386__ */ + +#endif /* CONFIG_DEBUG_MCOUNT */ diff -urN 2.3.29pre1/kernel/fork.c 2.3.29pre1-ikd/kernel/fork.c --- 2.3.29pre1/kernel/fork.c Sun Nov 21 03:20:20 1999 +++ 2.3.29pre1-ikd/kernel/fork.c Mon Nov 22 16:56:24 1999 @@ -11,12 +11,14 @@ * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' */ +#include #include #include #include #include #include #include +#include #include #include @@ -630,9 +632,14 @@ p->did_exec = 0; p->swappable = 0; +#ifdef CONFIG_DEBUG_SOFTLOCKUP +#warning Do something about KSTACK here ... + p->deadlock_count=CONFIG_SOFTLOCKUP_THRESHOLD; +#endif p->state = TASK_UNINTERRUPTIBLE; copy_flags(clone_flags, p); + RESUME_MCOUNT_PROC(p); p->pid = get_pid(clone_flags); /* diff -urN 2.3.29pre1/kernel/fork.c.orig 2.3.29pre1-ikd/kernel/fork.c.orig --- 2.3.29pre1/kernel/fork.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/kernel/fork.c.orig Sun Nov 21 03:20:20 1999 @@ -0,0 +1,768 @@ +/* + * linux/kernel/fork.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * 'fork.c' contains the help-routines for the 'fork' system call + * (see also system_call.s). + * Fork is rather simple, once you get the hang of it, but the memory + * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* The idle threads do not count.. */ +int nr_threads=0; +int nr_running=0; + +int max_threads; +unsigned long total_forks = 0; /* Handle normal Linux uptimes. */ +int last_pid=0; + +/* SLAB cache for mm_struct's. */ +kmem_cache_t *mm_cachep; + +/* SLAB cache for files structs */ +kmem_cache_t *files_cachep; + +struct task_struct *pidhash[PIDHASH_SZ]; + +/* UID task count cache, to prevent walking entire process list every + * single fork() operation. + */ +#define UIDHASH_SZ (PIDHASH_SZ >> 2) + +static struct user_struct { + atomic_t count; + struct user_struct *next, **pprev; + unsigned int uid; +} *uidhash[UIDHASH_SZ]; + +spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED; + +kmem_cache_t *uid_cachep; + +#define uidhashfn(uid) (((uid >> 8) ^ uid) & (UIDHASH_SZ - 1)) + +/* + * These routines must be called with the uidhash spinlock held! + */ +static inline void uid_hash_insert(struct user_struct *up, unsigned int hashent) +{ + if((up->next = uidhash[hashent]) != NULL) + uidhash[hashent]->pprev = &up->next; + up->pprev = &uidhash[hashent]; + uidhash[hashent] = up; +} + +static inline void uid_hash_remove(struct user_struct *up) +{ + if(up->next) + up->next->pprev = up->pprev; + *up->pprev = up->next; +} + +static inline struct user_struct *uid_hash_find(unsigned short uid, unsigned int hashent) +{ + struct user_struct *up, *next; + + next = uidhash[hashent]; + for (;;) { + up = next; + if (next) { + next = up->next; + if (up->uid != uid) + continue; + atomic_inc(&up->count); + } + break; + } + return up; +} + +/* + * For SMP, we need to re-test the user struct counter + * after having aquired the spinlock. This allows us to do + * the common case (not freeing anything) without having + * any locking. + */ +#ifdef __SMP__ + #define uid_hash_free(up) (!atomic_read(&(up)->count)) +#else + #define uid_hash_free(up) (1) +#endif + +void free_uid(struct task_struct *p) +{ + struct user_struct *up = p->user; + + if (up) { + p->user = NULL; + if (atomic_dec_and_test(&up->count)) { + spin_lock(&uidhash_lock); + if (uid_hash_free(up)) { + uid_hash_remove(up); + kmem_cache_free(uid_cachep, up); + } + spin_unlock(&uidhash_lock); + } + } +} + +int alloc_uid(struct task_struct *p) +{ + unsigned int hashent = uidhashfn(p->uid); + struct user_struct *up; + + spin_lock(&uidhash_lock); + up = uid_hash_find(p->uid, hashent); + spin_unlock(&uidhash_lock); + + if (!up) { + struct user_struct *new; + + new = kmem_cache_alloc(uid_cachep, SLAB_KERNEL); + if (!new) + return -EAGAIN; + new->uid = p->uid; + atomic_set(&new->count, 1); + + /* + * Before adding this, check whether we raced + * on adding the same user already.. + */ + spin_lock(&uidhash_lock); + up = uid_hash_find(p->uid, hashent); + if (up) { + kmem_cache_free(uid_cachep, new); + } else { + uid_hash_insert(new, hashent); + up = new; + } + spin_unlock(&uidhash_lock); + + } + p->user = up; + return 0; +} + +void __init fork_init(unsigned long mempages) +{ + int i; + + uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct), + 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if(!uid_cachep) + panic("Cannot create uid taskcount SLAB cache\n"); + + for(i = 0; i < UIDHASH_SZ; i++) + uidhash[i] = 0; + + /* + * The default maximum number of threads is set to a safe + * value: the thread structures can take up at most half + * of memory. + */ + max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 2; + + init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; + init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2; +} + +/* Protects next_safe and last_pid. */ +spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED; + +static int get_pid(unsigned long flags) +{ + static int next_safe = PID_MAX; + struct task_struct *p; + + if (flags & CLONE_PID) + return current->pid; + + spin_lock(&lastpid_lock); + if((++last_pid) & 0xffff8000) { + last_pid = 300; /* Skip daemons etc. */ + goto inside; + } + if(last_pid >= next_safe) { +inside: + next_safe = PID_MAX; + read_lock(&tasklist_lock); + repeat: + for_each_task(p) { + if(p->pid == last_pid || + p->pgrp == last_pid || + p->session == last_pid) { + if(++last_pid >= next_safe) { + if(last_pid & 0xffff8000) + last_pid = 300; + next_safe = PID_MAX; + } + goto repeat; + } + if(p->pid > last_pid && next_safe > p->pid) + next_safe = p->pid; + if(p->pgrp > last_pid && next_safe > p->pgrp) + next_safe = p->pgrp; + if(p->session > last_pid && next_safe > p->session) + next_safe = p->session; + } + read_unlock(&tasklist_lock); + } + spin_unlock(&lastpid_lock); + + return last_pid; +} + +static inline int dup_mmap(struct mm_struct * mm) +{ + struct vm_area_struct * mpnt, *tmp, **pprev; + int retval; + + /* Kill me slowly. UGLY! FIXME! */ + memcpy(&mm->start_code, ¤t->mm->start_code, 15*sizeof(unsigned long)); + + flush_cache_mm(current->mm); + pprev = &mm->mmap; + for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) { + struct file *file; + + retval = -ENOMEM; + tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!tmp) + goto fail_nomem; + *tmp = *mpnt; + tmp->vm_flags &= ~VM_LOCKED; + tmp->vm_mm = mm; + mm->map_count++; + tmp->vm_next = NULL; + file = tmp->vm_file; + if (file) { + get_file(file); + if (tmp->vm_flags & VM_DENYWRITE) + atomic_dec(&file->f_dentry->d_inode->i_writecount); + + /* insert tmp into the share list, just after mpnt */ + spin_lock(&file->f_dentry->d_inode->i_shared_lock); + if((tmp->vm_next_share = mpnt->vm_next_share) != NULL) + mpnt->vm_next_share->vm_pprev_share = + &tmp->vm_next_share; + mpnt->vm_next_share = tmp; + tmp->vm_pprev_share = &mpnt->vm_next_share; + spin_unlock(&file->f_dentry->d_inode->i_shared_lock); + } + + /* Copy the pages, but defer checking for errors */ + retval = copy_page_range(mm, current->mm, tmp); + if (!retval && tmp->vm_ops && tmp->vm_ops->open) + tmp->vm_ops->open(tmp); + + /* + * Link in the new vma even if an error occurred, + * so that exit_mmap() can clean up the mess. + */ + tmp->vm_next = *pprev; + *pprev = tmp; + + pprev = &tmp->vm_next; + if (retval) + goto fail_nomem; + } + retval = 0; + if (mm->map_count >= AVL_MIN_MAP_COUNT) + build_mmap_avl(mm); + +fail_nomem: + flush_tlb_mm(current->mm); + return retval; +} + +/* + * Allocate and initialize an mm_struct. + */ +struct mm_struct * mm_alloc(void) +{ + struct mm_struct * mm; + + mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL); + if (mm) { + memset(mm, 0, sizeof(*mm)); + atomic_set(&mm->mm_users, 1); + atomic_set(&mm->mm_count, 1); + init_MUTEX(&mm->mmap_sem); + mm->page_table_lock = SPIN_LOCK_UNLOCKED; + mm->pgd = pgd_alloc(); + if (mm->pgd) + return mm; + kmem_cache_free(mm_cachep, mm); + } + return NULL; +} + +/* + * Called when the last reference to the mm + * is dropped: either by a lazy thread or by + * mmput. Free the page directory and the mm. + */ +inline void __mmdrop(struct mm_struct *mm) +{ + if (mm == &init_mm) BUG(); + pgd_free(mm->pgd); + destroy_context(mm); + kmem_cache_free(mm_cachep, mm); +} + +/* + * Decrement the use count and release all resources for an mm. + */ +void mmput(struct mm_struct *mm) +{ + if (atomic_dec_and_test(&mm->mm_users)) { + exit_mmap(mm); + mmdrop(mm); + } +} + +/* Please note the differences between mmput and mm_release. + * mmput is called whenever we stop holding onto a mm_struct, + * error success whatever. + * + * mm_release is called after a mm_struct has been removed + * from the current process. + * + * This difference is important for error handling, when we + * only half set up a mm_struct for a new process and need to restore + * the old one. Because we mmput the new mm_struct before + * restoring the old one. . . + * Eric Biederman 10 January 1998 + */ +void mm_release(void) +{ + struct task_struct *tsk = current; + + /* notify parent sleeping on vfork() */ + if (tsk->flags & PF_VFORK) { + tsk->flags &= ~PF_VFORK; + up(tsk->p_opptr->vfork_sem); + } +} + +static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk) +{ + struct mm_struct * mm; + int retval; + + tsk->min_flt = tsk->maj_flt = 0; + tsk->cmin_flt = tsk->cmaj_flt = 0; + tsk->nswap = tsk->cnswap = 0; + + tsk->mm = NULL; + tsk->active_mm = NULL; + + /* + * Are we cloning a kernel thread? + * + * We need to steal a active VM for that.. + */ + mm = current->mm; + if (!mm) + return 0; + + if (clone_flags & CLONE_VM) { + atomic_inc(&mm->mm_users); + goto good_mm; + } + + retval = -ENOMEM; + mm = mm_alloc(); + if (!mm) + goto fail_nomem; + + tsk->mm = mm; + tsk->active_mm = mm; + + /* + * child gets a private LDT (if there was an LDT in the parent) + */ + copy_segments(tsk, mm); + + down(¤t->mm->mmap_sem); + retval = dup_mmap(mm); + up(¤t->mm->mmap_sem); + if (retval) + goto free_pt; + +good_mm: + tsk->mm = mm; + tsk->active_mm = mm; + init_new_context(tsk,mm); + return 0; + +free_pt: + mmput(mm); +fail_nomem: + return retval; +} + +static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk) +{ + if (clone_flags & CLONE_FS) { + atomic_inc(¤t->fs->count); + return 0; + } + tsk->fs = kmalloc(sizeof(*tsk->fs), GFP_KERNEL); + if (!tsk->fs) + return -1; + atomic_set(&tsk->fs->count, 1); + tsk->fs->umask = current->fs->umask; + tsk->fs->root = dget(current->fs->root); + tsk->fs->pwd = dget(current->fs->pwd); + return 0; +} + +static int count_open_files(struct files_struct *files, int size) +{ + int i; + + /* Find the last open fd */ + for (i = size/(8*sizeof(long)); i > 0; ) { + if (files->open_fds->fds_bits[--i]) + break; + } + i = (i+1) * 8 * sizeof(long); + return i; +} + +static int copy_files(unsigned long clone_flags, struct task_struct * tsk) +{ + struct files_struct *oldf, *newf; + struct file **old_fds, **new_fds; + int open_files, nfds, size, i, error = 0; + + /* + * A background process may not have any files ... + */ + oldf = current->files; + if (!oldf) + goto out; + + if (clone_flags & CLONE_FILES) { + atomic_inc(&oldf->count); + goto out; + } + + tsk->files = NULL; + error = -ENOMEM; + newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); + if (!newf) + goto out; + + atomic_set(&newf->count, 1); + + newf->file_lock = RW_LOCK_UNLOCKED; + newf->next_fd = 0; + newf->max_fds = NR_OPEN_DEFAULT; + newf->max_fdset = __FD_SETSIZE; + newf->close_on_exec = &newf->close_on_exec_init; + newf->open_fds = &newf->open_fds_init; + newf->fd = &newf->fd_array[0]; + + /* We don't yet have the oldf readlock, but even if the old + fdset gets grown now, we'll only copy up to "size" fds */ + size = oldf->max_fdset; + if (size > __FD_SETSIZE) { + newf->max_fdset = 0; + write_lock(&newf->file_lock); + error = expand_fdset(newf, size); + write_unlock(&newf->file_lock); + if (error) + goto out_release; + } + read_lock(&oldf->file_lock); + + open_files = count_open_files(oldf, size); + + /* + * Check whether we need to allocate a larger fd array. + * Note: we're not a clone task, so the open count won't + * change. + */ + nfds = NR_OPEN_DEFAULT; + if (open_files > nfds) { + read_unlock(&oldf->file_lock); + newf->max_fds = 0; + write_lock(&newf->file_lock); + error = expand_fd_array(newf, open_files); + write_unlock(&newf->file_lock); + if (error) + goto out_release; + nfds = newf->max_fds; + read_lock(&oldf->file_lock); + } + + old_fds = oldf->fd; + new_fds = newf->fd; + + memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, open_files/8); + memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, open_files/8); + + for (i = open_files; i != 0; i--) { + struct file *f = *old_fds++; + if (f) + get_file(f); + *new_fds++ = f; + } + read_unlock(&oldf->file_lock); + + /* compute the remainder to be cleared */ + size = (newf->max_fds - open_files) * sizeof(struct file *); + + /* This is long word aligned thus could use a optimized version */ + memset(new_fds, 0, size); + + if (newf->max_fdset > open_files) { + int left = (newf->max_fdset-open_files)/8; + int start = open_files / (8 * sizeof(unsigned long)); + + memset(&newf->open_fds->fds_bits[start], 0, left); + memset(&newf->close_on_exec->fds_bits[start], 0, left); + } + + tsk->files = newf; + error = 0; +out: + return error; + +out_release: + free_fdset (newf->close_on_exec, newf->max_fdset); + free_fdset (newf->open_fds, newf->max_fdset); + kmem_cache_free(files_cachep, newf); + goto out; +} + +static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk) +{ + if (clone_flags & CLONE_SIGHAND) { + atomic_inc(¤t->sig->count); + return 0; + } + tsk->sig = kmalloc(sizeof(*tsk->sig), GFP_KERNEL); + if (!tsk->sig) + return -1; + spin_lock_init(&tsk->sig->siglock); + atomic_set(&tsk->sig->count, 1); + memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action)); + return 0; +} + +static inline void copy_flags(unsigned long clone_flags, struct task_struct *p) +{ + unsigned long new_flags = p->flags; + + new_flags &= ~(PF_SUPERPRIV | PF_USEDFPU | PF_VFORK); + new_flags |= PF_FORKNOEXEC; + if (!(clone_flags & CLONE_PTRACE)) + new_flags &= ~(PF_PTRACED|PF_TRACESYS); + if (clone_flags & CLONE_VFORK) + new_flags |= PF_VFORK; + p->flags = new_flags; +} + +/* + * Ok, this is the main fork-routine. It copies the system process + * information (task[nr]) and sets up the necessary registers. It + * also copies the data segment in its entirety. + */ +int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) +{ + int retval = -ENOMEM; + struct task_struct *p; + DECLARE_MUTEX_LOCKED(sem); + + if (clone_flags & CLONE_PID) { + /* This is only allowed from the boot up thread */ + if (current->pid) + return -EPERM; + } + + current->vfork_sem = &sem; + + p = alloc_task_struct(); + if (!p) + goto fork_out; + + *p = *current; + + lock_kernel(); + + retval = -EAGAIN; + if (p->user) { + if (atomic_read(&p->user->count) >= p->rlim[RLIMIT_NPROC].rlim_cur) + goto bad_fork_free; + atomic_inc(&p->user->count); + } + + /* + * Counter increases are protected by + * the kernel lock so nr_threads can't + * increase under us (but it may decrease). + */ + if (nr_threads >= max_threads) + goto bad_fork_cleanup_count; + + if (p->exec_domain && p->exec_domain->module) + __MOD_INC_USE_COUNT(p->exec_domain->module); + if (p->binfmt && p->binfmt->module) + __MOD_INC_USE_COUNT(p->binfmt->module); + + p->did_exec = 0; + p->swappable = 0; + p->state = TASK_UNINTERRUPTIBLE; + + copy_flags(clone_flags, p); + p->pid = get_pid(clone_flags); + + /* + * This is a "shadow run" state. The process + * is marked runnable, but isn't actually on + * any run queue yet.. (that happens at the + * very end). + */ + p->state = TASK_RUNNING; + p->run_list.next = NULL; + p->run_list.prev = NULL; + + if ((clone_flags & CLONE_VFORK) || !(clone_flags & CLONE_PARENT)) + p->p_pptr = p->p_opptr = current; + p->p_cptr = NULL; + init_waitqueue_head(&p->wait_chldexit); + p->vfork_sem = NULL; + sema_init(&p->exit_sem, 1); + + p->sigpending = 0; + sigemptyset(&p->signal); + p->sigqueue = NULL; + p->sigqueue_tail = &p->sigqueue; + + p->it_real_value = p->it_virt_value = p->it_prof_value = 0; + p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0; + init_timer(&p->real_timer); + p->real_timer.data = (unsigned long) p; + + p->leader = 0; /* session leadership doesn't inherit */ + p->tty_old_pgrp = 0; + p->times.tms_utime = p->times.tms_stime = 0; + p->times.tms_cutime = p->times.tms_cstime = 0; +#ifdef __SMP__ + { + int i; + p->has_cpu = 0; + p->processor = current->processor; + /* ?? should we just memset this ?? */ + for(i = 0; i < smp_num_cpus; i++) + p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0; + spin_lock_init(&p->sigmask_lock); + } +#endif + p->lock_depth = -1; /* -1 = no lock */ + p->start_time = jiffies; + + retval = -ENOMEM; + /* copy all the process information */ + if (copy_files(clone_flags, p)) + goto bad_fork_cleanup; + if (copy_fs(clone_flags, p)) + goto bad_fork_cleanup_files; + if (copy_sighand(clone_flags, p)) + goto bad_fork_cleanup_fs; + if (copy_mm(clone_flags, p)) + goto bad_fork_cleanup_sighand; + retval = copy_thread(0, clone_flags, usp, p, regs); + if (retval) + goto bad_fork_cleanup_sighand; + p->semundo = NULL; + + /* Our parent execution domain becomes current domain + These must match for thread signalling to apply */ + + p->parent_exec_id = p->self_exec_id; + + /* ok, now we should be set up.. */ + p->swappable = 1; + p->exit_signal = clone_flags & CSIGNAL; + p->pdeath_signal = 0; + + /* + * "share" dynamic priority between parent and child, thus the + * total amount of dynamic priorities in the system doesnt change, + * more scheduling fairness. This is only important in the first + * timeslice, on the long run the scheduling behaviour is unchanged. + */ + current->counter >>= 1; + p->counter = current->counter; + + /* + * Ok, add it to the run-queues and make it + * visible to the rest of the system. + * + * Let it rip! + */ + retval = p->pid; + write_lock_irq(&tasklist_lock); + SET_LINKS(p); + hash_pid(p); + nr_threads++; + write_unlock_irq(&tasklist_lock); + + wake_up_process(p); /* do this last */ + ++total_forks; + +bad_fork: + unlock_kernel(); +fork_out: + if ((clone_flags & CLONE_VFORK) && (retval > 0)) + down(&sem); + return retval; + +bad_fork_cleanup_sighand: + exit_sighand(p); +bad_fork_cleanup_fs: + exit_fs(p); /* blocking */ +bad_fork_cleanup_files: + exit_files(p); /* blocking */ +bad_fork_cleanup: + if (p->exec_domain && p->exec_domain->module) + __MOD_DEC_USE_COUNT(p->exec_domain->module); + if (p->binfmt && p->binfmt->module) + __MOD_DEC_USE_COUNT(p->binfmt->module); +bad_fork_cleanup_count: + if (p->user) + free_uid(p); +bad_fork_free: + free_task_struct(p); + goto bad_fork; +} + +void __init filescache_init(void) +{ + files_cachep = kmem_cache_create("files_cache", + sizeof(struct files_struct), + 0, + SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (!files_cachep) + panic("Cannot create files cache"); +} diff -urN 2.3.29pre1/kernel/ksyms.c.orig 2.3.29pre1-ikd/kernel/ksyms.c.orig --- 2.3.29pre1/kernel/ksyms.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/kernel/ksyms.c.orig Sun Nov 21 03:20:44 1999 @@ -0,0 +1,439 @@ +/* + * Herein lies all the functions/variables that are "exported" for linkage + * with dynamically loaded kernel modules. + * Jon. + * + * - Stacked module support and unified symbol table added (June 1994) + * - External symbol table support added (December 1994) + * - Versions on symbols added (December 1994) + * by Bjorn Ekwall + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_PROC_FS) +#include +#endif +#ifdef CONFIG_KMOD +#include +#endif + +extern int console_loglevel; +extern void set_device_ro(kdev_t dev,int flag); +extern struct file_operations * get_blkfops(unsigned int); +extern int blkdev_release(struct inode * inode); +#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) +extern int (*do_nfsservctl)(int, void *, void *); +#endif + +extern void *sys_call_table; + +extern int sys_tz; +extern int request_dma(unsigned int dmanr, char * deviceID); +extern void free_dma(unsigned int dmanr); +extern spinlock_t dma_spin_lock; + +#ifdef CONFIG_MODVERSIONS +const struct module_symbol __export_Using_Versions +__attribute__((section("__ksymtab"))) = { + 1 /* Version version */, "Using_Versions" +}; +#endif + + +#ifdef CONFIG_KMOD +EXPORT_SYMBOL(request_module); +#endif + +#ifdef CONFIG_MODULES +EXPORT_SYMBOL(get_module_symbol); +#endif +EXPORT_SYMBOL(get_option); +EXPORT_SYMBOL(get_options); + +/* process memory management */ +EXPORT_SYMBOL(do_mmap); +EXPORT_SYMBOL(do_munmap); +EXPORT_SYMBOL(do_brk); +EXPORT_SYMBOL(exit_mm); +EXPORT_SYMBOL(exit_files); +EXPORT_SYMBOL(exit_fs); +EXPORT_SYMBOL(exit_sighand); + +/* internal kernel memory management */ +EXPORT_SYMBOL(__get_free_pages); +EXPORT_SYMBOL(free_pages); +EXPORT_SYMBOL(alloc_pages); +EXPORT_SYMBOL(__free_page); +EXPORT_SYMBOL(kmem_find_general_cachep); +EXPORT_SYMBOL(kmem_cache_create); +EXPORT_SYMBOL(kmem_cache_destroy); +EXPORT_SYMBOL(kmem_cache_shrink); +EXPORT_SYMBOL(kmem_cache_alloc); +EXPORT_SYMBOL(kmem_cache_free); +EXPORT_SYMBOL(kmalloc); +EXPORT_SYMBOL(kfree); +EXPORT_SYMBOL(kfree_s); +EXPORT_SYMBOL(vmalloc); +EXPORT_SYMBOL(vfree); +EXPORT_SYMBOL(mem_map); +EXPORT_SYMBOL(remap_page_range); +EXPORT_SYMBOL(max_mapnr); +EXPORT_SYMBOL(high_memory); +EXPORT_SYMBOL(vmtruncate); +EXPORT_SYMBOL(find_vma); +EXPORT_SYMBOL(get_unmapped_area); +EXPORT_SYMBOL(init_mm); + +/* filesystem internal functions */ +EXPORT_SYMBOL(in_group_p); +EXPORT_SYMBOL(update_atime); +EXPORT_SYMBOL(get_super); +EXPORT_SYMBOL(get_fs_type); +EXPORT_SYMBOL(get_empty_super); +EXPORT_SYMBOL(remove_vfsmnt); +EXPORT_SYMBOL(getname); +EXPORT_SYMBOL(_fput); +EXPORT_SYMBOL(igrab); +EXPORT_SYMBOL(iunique); +EXPORT_SYMBOL(iget4); +EXPORT_SYMBOL(iput); +EXPORT_SYMBOL(__namei); +EXPORT_SYMBOL(lookup_dentry); +EXPORT_SYMBOL(open_namei); +EXPORT_SYMBOL(sys_close); +EXPORT_SYMBOL(d_alloc_root); +EXPORT_SYMBOL(d_delete); +EXPORT_SYMBOL(d_validate); +EXPORT_SYMBOL(d_rehash); +EXPORT_SYMBOL(d_invalidate); /* May be it will be better in dcache.h? */ +EXPORT_SYMBOL(d_move); +EXPORT_SYMBOL(d_instantiate); +EXPORT_SYMBOL(d_alloc); +EXPORT_SYMBOL(d_lookup); +EXPORT_SYMBOL(d_path); +EXPORT_SYMBOL(__mark_buffer_dirty); +EXPORT_SYMBOL(__mark_inode_dirty); +EXPORT_SYMBOL(free_kiovec); +EXPORT_SYMBOL(brw_kiovec); +EXPORT_SYMBOL(alloc_kiovec); +EXPORT_SYMBOL(get_empty_filp); +EXPORT_SYMBOL(init_private_file); +EXPORT_SYMBOL(filp_open); +EXPORT_SYMBOL(filp_close); +EXPORT_SYMBOL(put_filp); +EXPORT_SYMBOL(files_lock); +EXPORT_SYMBOL(check_disk_change); +EXPORT_SYMBOL(invalidate_buffers); +EXPORT_SYMBOL(invalidate_inodes); +EXPORT_SYMBOL(invalidate_inode_pages); +EXPORT_SYMBOL(truncate_inode_pages); +EXPORT_SYMBOL(fsync_dev); +EXPORT_SYMBOL(permission); +EXPORT_SYMBOL(inode_setattr); +EXPORT_SYMBOL(inode_change_ok); +EXPORT_SYMBOL(write_inode_now); +EXPORT_SYMBOL(notify_change); +EXPORT_SYMBOL(get_hardblocksize); +EXPORT_SYMBOL(set_blocksize); +EXPORT_SYMBOL(getblk); +EXPORT_SYMBOL(bread); +EXPORT_SYMBOL(breada); +EXPORT_SYMBOL(__brelse); +EXPORT_SYMBOL(__bforget); +EXPORT_SYMBOL(ll_rw_block); +EXPORT_SYMBOL(__wait_on_buffer); +EXPORT_SYMBOL(add_blkdev_randomness); +EXPORT_SYMBOL(block_read_full_page); +EXPORT_SYMBOL(block_write_full_page); +EXPORT_SYMBOL(block_write_partial_page); +EXPORT_SYMBOL(block_write_cont_page); +EXPORT_SYMBOL(block_flushpage); +EXPORT_SYMBOL(generic_file_read); +EXPORT_SYMBOL(do_generic_file_read); +EXPORT_SYMBOL(generic_file_write); +EXPORT_SYMBOL(generic_file_mmap); +EXPORT_SYMBOL(generic_buffer_fdatasync); +EXPORT_SYMBOL(page_hash_bits); +EXPORT_SYMBOL(page_hash_table); +EXPORT_SYMBOL(file_lock_table); +EXPORT_SYMBOL(posix_lock_file); +EXPORT_SYMBOL(posix_test_lock); +EXPORT_SYMBOL(posix_block_lock); +EXPORT_SYMBOL(posix_unblock_lock); +EXPORT_SYMBOL(locks_mandatory_area); +EXPORT_SYMBOL(dput); +EXPORT_SYMBOL(put_cached_page); +EXPORT_SYMBOL(is_root_busy); +EXPORT_SYMBOL(prune_dcache); +EXPORT_SYMBOL(shrink_dcache_sb); +EXPORT_SYMBOL(shrink_dcache_parent); +EXPORT_SYMBOL(find_inode_number); +EXPORT_SYMBOL(is_subdir); +EXPORT_SYMBOL(get_unused_fd); +EXPORT_SYMBOL(vfs_rmdir); +EXPORT_SYMBOL(vfs_unlink); +EXPORT_SYMBOL(vfs_rename); +EXPORT_SYMBOL(__pollwait); +EXPORT_SYMBOL(ROOT_DEV); +EXPORT_SYMBOL(add_to_page_cache_unique); +EXPORT_SYMBOL(__find_get_page); +EXPORT_SYMBOL(__find_lock_page); + +#if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE) +EXPORT_SYMBOL(do_nfsservctl); +#endif + +/* device registration */ +EXPORT_SYMBOL(register_chrdev); +EXPORT_SYMBOL(unregister_chrdev); +EXPORT_SYMBOL(register_blkdev); +EXPORT_SYMBOL(unregister_blkdev); +EXPORT_SYMBOL(tty_register_driver); +EXPORT_SYMBOL(tty_unregister_driver); +EXPORT_SYMBOL(tty_std_termios); + +/* block device driver support */ +EXPORT_SYMBOL(block_read); +EXPORT_SYMBOL(block_write); +EXPORT_SYMBOL(block_fsync); +EXPORT_SYMBOL(wait_for_request); +EXPORT_SYMBOL(blksize_size); +EXPORT_SYMBOL(hardsect_size); +EXPORT_SYMBOL(blk_size); +EXPORT_SYMBOL(blk_dev); +EXPORT_SYMBOL(is_read_only); +EXPORT_SYMBOL(set_device_ro); +EXPORT_SYMBOL(bmap); +EXPORT_SYMBOL(sync_dev); +EXPORT_SYMBOL(get_blkfops); +EXPORT_SYMBOL(blkdev_open); +EXPORT_SYMBOL(blkdev_release); +EXPORT_SYMBOL(gendisk_head); +EXPORT_SYMBOL(resetup_one_dev); +EXPORT_SYMBOL(unplug_device); +EXPORT_SYMBOL(make_request); +EXPORT_SYMBOL(tq_disk); +EXPORT_SYMBOL(init_buffer); +EXPORT_SYMBOL(refile_buffer); +EXPORT_SYMBOL(max_sectors); +EXPORT_SYMBOL(max_segments); +EXPORT_SYMBOL(max_readahead); +EXPORT_SYMBOL(file_moveto); + +/* tty routines */ +EXPORT_SYMBOL(tty_hangup); +EXPORT_SYMBOL(tty_wait_until_sent); +EXPORT_SYMBOL(tty_check_change); +EXPORT_SYMBOL(tty_hung_up_p); +EXPORT_SYMBOL(tty_flip_buffer_push); +EXPORT_SYMBOL(tty_get_baud_rate); +EXPORT_SYMBOL(do_SAK); +EXPORT_SYMBOL(console_print); +EXPORT_SYMBOL(console_loglevel); + +/* filesystem registration */ +EXPORT_SYMBOL(register_filesystem); +EXPORT_SYMBOL(unregister_filesystem); + +/* executable format registration */ +EXPORT_SYMBOL(register_binfmt); +EXPORT_SYMBOL(unregister_binfmt); +EXPORT_SYMBOL(search_binary_handler); +EXPORT_SYMBOL(prepare_binprm); +EXPORT_SYMBOL(compute_creds); +EXPORT_SYMBOL(remove_arg_zero); + +/* execution environment registration */ +EXPORT_SYMBOL(lookup_exec_domain); +EXPORT_SYMBOL(register_exec_domain); +EXPORT_SYMBOL(unregister_exec_domain); + +/* sysctl table registration */ +EXPORT_SYMBOL(register_sysctl_table); +EXPORT_SYMBOL(unregister_sysctl_table); +EXPORT_SYMBOL(sysctl_string); +EXPORT_SYMBOL(sysctl_intvec); +EXPORT_SYMBOL(proc_dostring); +EXPORT_SYMBOL(proc_dointvec); +EXPORT_SYMBOL(proc_dointvec_jiffies); +EXPORT_SYMBOL(proc_dointvec_minmax); +EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); +EXPORT_SYMBOL(proc_doulongvec_minmax); + +/* interrupt handling */ +EXPORT_SYMBOL(request_irq); +EXPORT_SYMBOL(free_irq); +EXPORT_SYMBOL(probe_irq_on); +EXPORT_SYMBOL(probe_irq_off); +EXPORT_SYMBOL(bh_active); +EXPORT_SYMBOL(bh_mask); +EXPORT_SYMBOL(bh_mask_count); +EXPORT_SYMBOL(bh_base); +EXPORT_SYMBOL(add_timer); +EXPORT_SYMBOL(del_timer); +EXPORT_SYMBOL(mod_timer); +EXPORT_SYMBOL(tq_timer); +EXPORT_SYMBOL(tq_immediate); +EXPORT_SYMBOL(tq_scheduler); +EXPORT_SYMBOL(timer_active); +EXPORT_SYMBOL(timer_table); + +#ifdef __SMP__ +/* Various random spinlocks we want to export */ +EXPORT_SYMBOL(tqueue_lock); +#endif + +/* autoirq from drivers/net/auto_irq.c */ +EXPORT_SYMBOL(autoirq_setup); +EXPORT_SYMBOL(autoirq_report); + +/* dma handling */ +EXPORT_SYMBOL(request_dma); +EXPORT_SYMBOL(free_dma); +EXPORT_SYMBOL(dma_spin_lock); +#ifdef HAVE_DISABLE_HLT +EXPORT_SYMBOL(disable_hlt); +EXPORT_SYMBOL(enable_hlt); +#endif + +/* resource handling */ +EXPORT_SYMBOL(request_resource); +EXPORT_SYMBOL(release_resource); +EXPORT_SYMBOL(allocate_resource); +EXPORT_SYMBOL(__request_region); +EXPORT_SYMBOL(__check_region); +EXPORT_SYMBOL(__release_region); +EXPORT_SYMBOL(ioport_resource); +EXPORT_SYMBOL(iomem_resource); + +/* process management */ +EXPORT_SYMBOL(__wake_up); +EXPORT_SYMBOL(sleep_on); +EXPORT_SYMBOL(sleep_on_timeout); +EXPORT_SYMBOL(interruptible_sleep_on); +EXPORT_SYMBOL(interruptible_sleep_on_timeout); +EXPORT_SYMBOL(schedule); +EXPORT_SYMBOL(schedule_timeout); +EXPORT_SYMBOL(jiffies); +EXPORT_SYMBOL(xtime); +EXPORT_SYMBOL(do_gettimeofday); +EXPORT_SYMBOL(loops_per_sec); +EXPORT_SYMBOL(kstat); + +/* misc */ +EXPORT_SYMBOL(panic); +EXPORT_SYMBOL(printk); +EXPORT_SYMBOL(sprintf); +EXPORT_SYMBOL(vsprintf); +EXPORT_SYMBOL(kdevname); +EXPORT_SYMBOL(bdevname); +EXPORT_SYMBOL(cdevname); +EXPORT_SYMBOL(partition_name); /* md.c only */ +EXPORT_SYMBOL(simple_strtoul); +EXPORT_SYMBOL(system_utsname); /* UTS data */ +EXPORT_SYMBOL(uts_sem); /* UTS semaphore */ +EXPORT_SYMBOL(sys_call_table); +EXPORT_SYMBOL(machine_restart); +EXPORT_SYMBOL(machine_halt); +EXPORT_SYMBOL(machine_power_off); +EXPORT_SYMBOL(register_reboot_notifier); +EXPORT_SYMBOL(unregister_reboot_notifier); +EXPORT_SYMBOL(_ctype); +EXPORT_SYMBOL(secure_tcp_sequence_number); +EXPORT_SYMBOL(get_random_bytes); +EXPORT_SYMBOL(securebits); +EXPORT_SYMBOL(cap_bset); +EXPORT_SYMBOL(daemonize); + +/* Program loader interfaces */ +EXPORT_SYMBOL(setup_arg_pages); +EXPORT_SYMBOL(copy_strings_kernel); +EXPORT_SYMBOL(do_execve); +EXPORT_SYMBOL(flush_old_exec); +EXPORT_SYMBOL(open_dentry); +EXPORT_SYMBOL(read_exec); + +/* Miscellaneous access points */ +EXPORT_SYMBOL(si_meminfo); + +/* Added to make file system as module */ +EXPORT_SYMBOL(sys_tz); +EXPORT_SYMBOL(__wait_on_super); +EXPORT_SYMBOL(file_fsync); +EXPORT_SYMBOL(clear_inode); +EXPORT_SYMBOL(nr_async_pages); +EXPORT_SYMBOL(___strtok); +EXPORT_SYMBOL(init_special_inode); +EXPORT_SYMBOL(init_fifo); +EXPORT_SYMBOL(fifo_inode_operations); +EXPORT_SYMBOL(chrdev_inode_operations); +EXPORT_SYMBOL(blkdev_inode_operations); +EXPORT_SYMBOL(read_ahead); +EXPORT_SYMBOL(get_hash_table); +EXPORT_SYMBOL(get_empty_inode); +EXPORT_SYMBOL(insert_inode_hash); +EXPORT_SYMBOL(remove_inode_hash); +EXPORT_SYMBOL(make_bad_inode); +EXPORT_SYMBOL(is_bad_inode); +EXPORT_SYMBOL(event); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(brw_page); + +/* all busmice */ +EXPORT_SYMBOL(add_mouse_randomness); +EXPORT_SYMBOL(fasync_helper); + +#ifdef CONFIG_BLK_DEV_MD +EXPORT_SYMBOL(disk_name); /* for md.c */ +#endif + +/* binfmt_aout */ +EXPORT_SYMBOL(get_write_access); +EXPORT_SYMBOL(put_write_access); + +/* dynamic registering of consoles */ +EXPORT_SYMBOL(register_console); +EXPORT_SYMBOL(unregister_console); + +/* time */ +EXPORT_SYMBOL(get_fast_time); + +/* library functions */ +EXPORT_SYMBOL(strnicmp); + +EXPORT_SYMBOL(init_task_union); diff -urN 2.3.29pre1/kernel/ksyms.c.rej 2.3.29pre1-ikd/kernel/ksyms.c.rej --- 2.3.29pre1/kernel/ksyms.c.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/kernel/ksyms.c.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,60 @@ +*************** +*** 90,108 **** + EXPORT_SYMBOL(exit_sighand); + + /* internal kernel memory management */ + EXPORT_SYMBOL(__get_free_pages); + EXPORT_SYMBOL(free_pages); + EXPORT_SYMBOL(__free_page); + EXPORT_SYMBOL(kmem_find_general_cachep); + EXPORT_SYMBOL(kmem_cache_create); + EXPORT_SYMBOL(kmem_cache_destroy); + EXPORT_SYMBOL(kmem_cache_shrink); + EXPORT_SYMBOL(kmem_cache_alloc); + EXPORT_SYMBOL(kmem_cache_free); + EXPORT_SYMBOL(kmalloc); + EXPORT_SYMBOL(kfree); + EXPORT_SYMBOL(kfree_s); + EXPORT_SYMBOL(vmalloc); + EXPORT_SYMBOL(vfree); + EXPORT_SYMBOL(mem_map); + EXPORT_SYMBOL(remap_page_range); +--- 90,127 ---- + EXPORT_SYMBOL(exit_sighand); + + /* internal kernel memory management */ ++ #ifndef CONFIG_MEMLEAK + EXPORT_SYMBOL(__get_free_pages); ++ #else ++ EXPORT_SYMBOL(__get_free_pages_wrap); ++ EXPORT_SYMBOL(kmem_cache_create_wrap); ++ EXPORT_SYMBOL(kmem_cache_alloc_wrap); ++ EXPORT_SYMBOL(kmalloc_wrap); ++ EXPORT_SYMBOL(vmalloc_wrap); ++ EXPORT_SYMBOL(alloc_addr_lock); ++ EXPORT_SYMBOL(alloc_addr_nolock); ++ EXPORT_SYMBOL(free_addr); ++ #endif /* CONFIG_MEMLEAK */ + EXPORT_SYMBOL(free_pages); + EXPORT_SYMBOL(__free_page); + EXPORT_SYMBOL(kmem_find_general_cachep); ++ #ifndef CONFIG_MEMLEAK + EXPORT_SYMBOL(kmem_cache_create); ++ #endif + EXPORT_SYMBOL(kmem_cache_destroy); + EXPORT_SYMBOL(kmem_cache_shrink); ++ #ifndef CONFIG_MEMLEAK + EXPORT_SYMBOL(kmem_cache_alloc); ++ #endif + EXPORT_SYMBOL(kmem_cache_free); ++ #ifndef CONFIG_MEMLEAK + EXPORT_SYMBOL(kmalloc); ++ #endif + EXPORT_SYMBOL(kfree); + EXPORT_SYMBOL(kfree_s); ++ #ifndef CONFIG_MEMLEAK + EXPORT_SYMBOL(vmalloc); ++ #endif + EXPORT_SYMBOL(vfree); + EXPORT_SYMBOL(mem_map); + EXPORT_SYMBOL(remap_page_range); diff -urN 2.3.29pre1/kernel/module.c 2.3.29pre1-ikd/kernel/module.c --- 2.3.29pre1/kernel/module.c Tue Sep 14 14:34:40 1999 +++ 2.3.29pre1-ikd/kernel/module.c Mon Nov 22 16:56:24 1999 @@ -6,6 +6,9 @@ #include #include #include +#if defined(CONFIG_KDB) +#include +#endif /* * Originally by Anonymous (as far as I know...) @@ -165,6 +168,9 @@ long namelen, n_namelen, i, error = -EPERM; unsigned long mod_user_size; struct module_ref *dep; +#if defined(CONFIG_KDB) + struct module_symbol *s; +#endif lock_kernel(); if (!capable(CAP_SYS_MODULE)) @@ -333,6 +339,11 @@ } atomic_dec(&mod->uc.usecount); +#if defined(CONFIG_KDB) + for(i=0,s=mod->syms; insyms; i++, s++){ + kdbaddmodsym(s->name, s->value); + } +#endif /* And set it running. */ mod->flags |= MOD_RUNNING; error = 0; @@ -771,6 +782,9 @@ { struct module_ref *dep; unsigned i; +#if defined(CONFIG_KDB) + struct module_symbol *s; +#endif /* Let the module clean up. */ @@ -781,6 +795,15 @@ mod->cleanup(); mod->flags &= ~MOD_RUNNING; } + +#if defined(CONFIG_KDB) + /* + * Remove symbols from kernel debugger + */ + for(i=0,s=mod->syms; insyms; i++, s++){ + kdbdelmodsym(s->name); + } +#endif /* Remove the module from the dependency lists. */ diff -urN 2.3.29pre1/kernel/panic.c 2.3.29pre1-ikd/kernel/panic.c --- 2.3.29pre1/kernel/panic.c Tue Sep 14 14:34:40 1999 +++ 2.3.29pre1-ikd/kernel/panic.c Mon Nov 22 16:56:24 1999 @@ -15,6 +15,9 @@ #include #include #include +#ifdef CONFIG_TRACE +#include +#endif #ifdef __alpha__ #include @@ -41,6 +44,9 @@ static char buf[1024]; va_list args; +#ifdef CONFIG_TRACE + SUSPEND_MCOUNT_TRACE; +#endif va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); diff -urN 2.3.29pre1/kernel/printk.c 2.3.29pre1-ikd/kernel/printk.c --- 2.3.29pre1/kernel/printk.c Tue Sep 14 14:35:58 1999 +++ 2.3.29pre1-ikd/kernel/printk.c Mon Nov 22 16:56:24 1999 @@ -12,6 +12,8 @@ * Modified for sysctl support, 1/8/97, Chris Horn. * Fixed SMP synchronization, 08/08/99, Manfred Spraul * manfreds@colorfullife.com + * syslog_to_console for SysRQ dumploGs. 12/04/1998. + * Keith Owens */ #include @@ -242,6 +244,45 @@ } out: return error; +} + +void syslog_to_console(void) +{ + /* + * Copy the syslog buffer to all registered consoles. Like + * sys_syslog, option 3 but to console instead of user. Raw data, + * no attempt to find record headers, message levels etc. + * Intended as a last ditch dump of syslog. + */ + unsigned long i, j, count, flags; + char *p, buf[129]; /* copy log in 128 byte chunks */ + + /* + * The logged_chars, log_start, and log_size values may + * change from an interrupt, so we disable interrupts. + */ + count = LOG_BUF_LEN; + spin_lock_irqsave(&console_lock, flags); + if (count > logged_chars) + count = logged_chars; + j = log_start + log_size - count; + spin_unlock_irqrestore(&console_lock, flags); + /* Race here, the log can change under us, we might dump garbage. + * Live with it, this is a last ditch output, waiting for locks + * could stop output. console_print should not require locks. + */ + for (i = 0, p = buf; i < count; i++) { + *p++ = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1))); + if (p == buf+sizeof(buf)-1) { + *p = '\0'; + console_print(buf); + p = buf; + } + } + if (p != buf) { + *p = '\0'; + console_print(buf); + } } asmlinkage long sys_syslog(int type, char * buf, int len) diff -urN 2.3.29pre1/kernel/sched.c 2.3.29pre1-ikd/kernel/sched.c --- 2.3.29pre1/kernel/sched.c Sat Oct 16 03:34:52 1999 +++ 2.3.29pre1-ikd/kernel/sched.c Mon Nov 22 16:56:24 1999 @@ -24,6 +24,7 @@ * current-task */ +#include #include #include #include @@ -716,6 +717,9 @@ } } +#ifdef CONFIG_DEBUG_SOFTLOCKUP + prev->deadlock_count=CONFIG_SOFTLOCKUP_THRESHOLD; +#endif /* * This just switches the register state and the * stack. diff -urN 2.3.29pre1/kernel/softirq.c 2.3.29pre1-ikd/kernel/softirq.c --- 2.3.29pre1/kernel/softirq.c Wed Mar 24 01:53:18 1999 +++ 2.3.29pre1-ikd/kernel/softirq.c Mon Nov 22 16:56:24 1999 @@ -11,10 +11,12 @@ * due bh_mask_count not atomic handling. Copyright (C) 1998 Andrea Arcangeli */ +#include #include #include #include #include +#include #include @@ -66,5 +68,8 @@ hardirq_endlock(cpu); } softirq_endlock(cpu); +#if defined(CONFIG_DEBUG_SOFTLOCKUP) && (defined(__SMP__) || defined(CONFIG_SMP)) + mcount(); +#endif } } diff -urN 2.3.29pre1/kernel/sys.c 2.3.29pre1-ikd/kernel/sys.c --- 2.3.29pre1/kernel/sys.c Tue Nov 2 12:06:25 1999 +++ 2.3.29pre1-ikd/kernel/sys.c Mon Nov 22 16:56:24 1999 @@ -141,6 +141,37 @@ return max_prio; } +/* routines to trip various softlockup conditions, driven from reboot */ +static void kstack_test1 (void); +static void kstack_test2 (void); +static void kstack_test3 (void); +static void kstack_test4 (void); + +static void kstack_test1 (void) +{ + kstack_test2(); +} + +static void kstack_test2 (void) +{ + kstack_test3(); +} + +static void kstack_test3 (void) +{ + kstack_test4(); +} + +static void kstack_test4 (void) +{ + kstack_test1(); /* curse and recurse, stack overflow */ +} + +static volatile int softlockup_count=0; +void softlockup_looptest(void) +{ + softlockup_count++; +} /* * Reboot system call: for obvious reasons only root may call it, @@ -204,6 +235,34 @@ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer); printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer); machine_restart(buffer); + break; + + case LINUX_REBOOT_CMD_OOPS: + /* Kernel oops, the machine should recover afterwards */ + *(char *)0=0; + break; + + /* Trip various software lockup conditions. Overloading sys_reboot + * because they do not justify their own syscall. These do not notify + * the reboot list. + */ + + case LINUX_REBOOT_CMD_STACKFAULT: + /* stack fault via endless recursion */ +#ifndef CONFIG_DEBUG_KSTACK + printk(KERN_WARNING "Invoking STACKFAULT without CONFIG_DEBUG_KSTACK\n" + "Machine may not recover!\n"); +#endif + kstack_test1(); + break; + + case LINUX_REBOOT_CMD_KERNEL_LOOP: + /* lockup via endless loop */ +#ifndef CONFIG_DEBUG_SOFTLOCKUP + printk(KERN_WARNING "Invoking KERNEL_LOOP without CONFIG_DEBUG_SOFTLOCKUP\n" + "Machine may not recover!\n"); +#endif + for (;;) softlockup_looptest(); break; default: diff -urN 2.3.29pre1/kernel/sysctl.c 2.3.29pre1-ikd/kernel/sysctl.c --- 2.3.29pre1/kernel/sysctl.c Sun Nov 21 03:20:20 1999 +++ 2.3.29pre1-ikd/kernel/sysctl.c Mon Nov 22 16:56:24 1999 @@ -285,7 +285,22 @@ {0} }; +#ifdef CONFIG_DEBUG_MCOUNT +extern int sysctl_disable_mcount; +#ifdef CONFIG_KSTACK_METER +extern int kstack_meter[]; +#endif +#endif + static ctl_table debug_table[] = { +#ifdef CONFIG_DEBUG_MCOUNT + {DEBUG_DISABLE_MCOUNT, "disable_mcount", &sysctl_disable_mcount, + sizeof(int), 0644, NULL, &proc_dointvec}, +#ifdef CONFIG_KSTACK_METER + {DEBUG_KSTACK_METER, "kstack_meter", &kstack_meter, 2*sizeof(int), + 0644, NULL, &proc_dointvec}, +#endif +#endif {0} }; diff -urN 2.3.29pre1/kernel/sysctl.c.orig 2.3.29pre1-ikd/kernel/sysctl.c.orig --- 2.3.29pre1/kernel/sysctl.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/kernel/sysctl.c.orig Sun Nov 21 03:20:20 1999 @@ -0,0 +1,1374 @@ +/* + * sysctl.c: General linux system control interface + * + * Begun 24 March 1995, Stephen Tweedie + * Added /proc support, Dec 1995 + * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas. + * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver. + * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver. + * Dynamic registration fixes, Stephen Tweedie. + * Added kswapd-interval, ctrl-alt-del, printk stuff, 1/8/97, Chris Horn. + * Made sysctl support optional via CONFIG_SYSCTL, 1/10/97, Chris + * Horn. + * Added proc_doulongvec_ms_jiffies_minmax, 09/08/99, Carlos H. Bauer. + * Added proc_doulongvec_minmax, 09/08/99, Carlos H. Bauer. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_ROOT_NFS +#include +#endif + +#if defined(CONFIG_SYSCTL) + +/* External variables not in a header file. */ +extern int panic_timeout; +extern int console_loglevel, C_A_D; +extern int bdf_prm[], bdflush_min[], bdflush_max[]; +extern int sysctl_overcommit_memory; +extern int max_threads; +extern int nr_queued_signals, max_queued_signals; + +#ifdef CONFIG_KMOD +extern char modprobe_path[]; +#endif +#ifdef CONFIG_CHR_DEV_SG +extern int sg_big_buff; +#endif +#ifdef CONFIG_SYSVIPC +extern size_t shm_prm[]; +extern int msg_ctlmax; +extern int msg_ctlmnb; +extern int msg_ctlmni; +extern int sem_ctls[]; +#endif + +#ifdef __sparc__ +extern char reboot_command []; +#endif +#ifdef __powerpc__ +extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap; +int proc_dol2crvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp); +#endif + +#ifdef CONFIG_BSD_PROCESS_ACCT +extern int acct_parm[]; +#endif + +extern int pgt_cache_water[]; + +static int parse_table(int *, int, void *, size_t *, void *, size_t, + ctl_table *, void **); +static int proc_doutsstring(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp); + + +static ctl_table root_table[]; +static struct ctl_table_header root_table_header = + {root_table, DNODE_SINGLE(&root_table_header)}; + +static ctl_table kern_table[]; +static ctl_table vm_table[]; +#ifdef CONFIG_NET +extern ctl_table net_table[]; +#endif +static ctl_table proc_table[]; +static ctl_table fs_table[]; +static ctl_table debug_table[]; +static ctl_table dev_table[]; +extern ctl_table random_table[]; + + +/* /proc declarations: */ + +#ifdef CONFIG_PROC_FS + +static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *); +static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *); +static int proc_sys_permission(struct inode *, int); + +struct file_operations proc_sys_file_operations = +{ + NULL, /* lseek */ + proc_readsys, /* read */ + proc_writesys, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special flush code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +struct inode_operations proc_sys_inode_operations = +{ + &proc_sys_file_operations, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* flushpage */ + NULL, /* truncate */ + proc_sys_permission, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +extern struct proc_dir_entry *proc_sys_root; + +static void register_proc_table(ctl_table *, struct proc_dir_entry *); +static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); +#endif +extern int inodes_stat[]; +extern int dentry_stat[]; + +/* The default sysctl tables: */ + +static ctl_table root_table[] = { + {CTL_KERN, "kernel", NULL, 0, 0555, kern_table}, + {CTL_VM, "vm", NULL, 0, 0555, vm_table}, +#ifdef CONFIG_NET + {CTL_NET, "net", NULL, 0, 0555, net_table}, +#endif + {CTL_PROC, "proc", NULL, 0, 0555, proc_table}, + {CTL_FS, "fs", NULL, 0, 0555, fs_table}, + {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table}, + {CTL_DEV, "dev", NULL, 0, 0555, dev_table}, + {0} +}; + +static ctl_table kern_table[] = { + {KERN_OSTYPE, "ostype", system_utsname.sysname, 64, + 0444, NULL, &proc_doutsstring, &sysctl_string}, + {KERN_OSRELEASE, "osrelease", system_utsname.release, 64, + 0444, NULL, &proc_doutsstring, &sysctl_string}, + {KERN_VERSION, "version", system_utsname.version, 64, + 0444, NULL, &proc_doutsstring, &sysctl_string}, + {KERN_NODENAME, "hostname", system_utsname.nodename, 64, + 0644, NULL, &proc_doutsstring, &sysctl_string}, + {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64, + 0644, NULL, &proc_doutsstring, &sysctl_string}, + {KERN_PANIC, "panic", &panic_timeout, sizeof(int), + 0644, NULL, &proc_dointvec}, + {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t), + 0600, NULL, &proc_dointvec_bset}, +#ifdef CONFIG_BLK_DEV_INITRD + {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int), + 0644, NULL, &proc_dointvec}, +#endif +#ifdef __sparc__ + {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command, + 256, 0644, NULL, &proc_dostring, &sysctl_string }, +#endif +#ifdef __powerpc__ + {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int), + 0644, NULL, &proc_dointvec}, + {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int), + 0644, NULL, &proc_dointvec}, + {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int), + 0644, NULL, &proc_dointvec}, + {KERN_PPC_L2CR, "l2cr", NULL, 0, + 0644, NULL, &proc_dol2crvec}, +#endif + {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int), + 0644, NULL, &proc_dointvec}, + {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int), + 0644, NULL, &proc_dointvec}, +#ifdef CONFIG_KMOD + {KERN_MODPROBE, "modprobe", &modprobe_path, 256, + 0644, NULL, &proc_dostring, &sysctl_string }, +#endif +#ifdef CONFIG_CHR_DEV_SG + {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int), + 0444, NULL, &proc_dointvec}, +#endif +#ifdef CONFIG_BSD_PROCESS_ACCT + {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int), + 0644, NULL, &proc_dointvec}, +#endif + {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int), + 0444, NULL, &proc_dointvec}, + {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int), + 0644, NULL, &proc_dointvec}, +#ifdef CONFIG_SYSVIPC + {KERN_SHMMAX, "shmmax", &shm_prm, 3*sizeof (size_t), + 0644, NULL, &proc_doulongvec_minmax}, + {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int), + 0644, NULL, &proc_dointvec}, + {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int), + 0644, NULL, &proc_dointvec}, +#endif +#ifdef CONFIG_MAGIC_SYSRQ + {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int), + 0644, NULL, &proc_dointvec}, +#endif + {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int), + 0644, NULL, &proc_dointvec}, + {KERN_RANDOM, "random", NULL, 0, 0555, random_table}, + {0} +}; + +static ctl_table vm_table[] = { + {VM_FREEPG, "freepages", + &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec}, + {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL, + &proc_dointvec_minmax, &sysctl_intvec, NULL, + &bdflush_min, &bdflush_max}, + {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory, + sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec}, + {VM_BUFFERMEM, "buffermem", + &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec}, + {VM_PAGECACHE, "pagecache", + &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec}, + {VM_PAGERDAEMON, "kswapd", + &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec}, + {VM_PGT_CACHE, "pagetable_cache", + &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec}, + {VM_PAGE_CLUSTER, "page-cluster", + &page_cluster, sizeof(int), 0600, NULL, &proc_dointvec}, + {0} +}; + +static ctl_table proc_table[] = { + {0} +}; + +static ctl_table fs_table[] = { + {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int), + 0444, NULL, &proc_dointvec}, + {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int), + 0444, NULL, &proc_dointvec}, + {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int), + 0444, NULL, &proc_dointvec}, + {FS_MAXFILE, "file-max", &max_files, sizeof(int), + 0644, NULL, &proc_dointvec}, + {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int), + 0444, NULL, &proc_dointvec}, + {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int), + 0644, NULL, &proc_dointvec}, + {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int), + 0444, NULL, &proc_dointvec}, + {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int), + 0644, NULL, &proc_dointvec}, + {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int), + 0444, NULL, &proc_dointvec}, + {0} +}; + +static ctl_table debug_table[] = { + {0} +}; + +static ctl_table dev_table[] = { + {0} +}; + + +void __init sysctl_init(void) +{ +#ifdef CONFIG_PROC_FS + register_proc_table(root_table, proc_sys_root); +#endif +} + + +int do_sysctl (int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen) +{ + int error; + struct ctl_table_header *tmp; + void *context; + + if (nlen == 0 || nlen >= CTL_MAXNAME) + return -ENOTDIR; + + if (oldval) + { + int old_len; + if (!oldlenp) + return -EFAULT; + if(get_user(old_len, oldlenp)) + return -EFAULT; + } + tmp = &root_table_header; + do { + context = NULL; + error = parse_table(name, nlen, oldval, oldlenp, + newval, newlen, tmp->ctl_table, &context); + if (context) + kfree(context); + if (error != -ENOTDIR) + return error; + tmp = tmp->DLIST_NEXT(ctl_entry); + } while (tmp != &root_table_header); + return -ENOTDIR; +} + +extern asmlinkage long sys_sysctl(struct __sysctl_args *args) +{ + struct __sysctl_args tmp; + int error; + + if(copy_from_user(&tmp, args, sizeof(tmp))) + return -EFAULT; + + lock_kernel(); + error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, + tmp.newval, tmp.newlen); + unlock_kernel(); + return error; +} + +/* Like in_group_p, but testing against egid, not fsgid */ +static int in_egroup_p(gid_t grp) +{ + if (grp != current->egid) { + int i = current->ngroups; + if (i) { + gid_t *groups = current->groups; + do { + if (*groups == grp) + goto out; + groups++; + i--; + } while (i); + } + return 0; + } +out: + return 1; +} + +/* ctl_perm does NOT grant the superuser all rights automatically, because + some sysctl variables are readonly even to root. */ + +static int test_perm(int mode, int op) +{ + if (!current->euid) + mode >>= 6; + else if (in_egroup_p(0)) + mode >>= 3; + if ((mode & op & 0007) == op) + return 0; + return -EACCES; +} + +static inline int ctl_perm(ctl_table *table, int op) +{ + return test_perm(table->mode, op); +} + +static int parse_table(int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, + ctl_table *table, void **context) +{ + int error; +repeat: + if (!nlen) + return -ENOTDIR; + + for ( ; table->ctl_name; table++) { + int n; + if(get_user(n,name)) + return -EFAULT; + if (n == table->ctl_name || + table->ctl_name == CTL_ANY) { + if (table->child) { + if (ctl_perm(table, 001)) + return -EPERM; + if (table->strategy) { + error = table->strategy( + table, name, nlen, + oldval, oldlenp, + newval, newlen, context); + if (error) + return error; + } + name++; + nlen--; + table = table->child; + goto repeat; + } + error = do_sysctl_strategy(table, name, nlen, + oldval, oldlenp, + newval, newlen, context); + return error; + } + }; + return -ENOTDIR; +} + +/* Perform the actual read/write of a sysctl table entry. */ +int do_sysctl_strategy (ctl_table *table, + int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + int op = 0, rc, len; + + if (oldval) + op |= 004; + if (newval) + op |= 002; + if (ctl_perm(table, op)) + return -EPERM; + + if (table->strategy) { + rc = table->strategy(table, name, nlen, oldval, oldlenp, + newval, newlen, context); + if (rc < 0) + return rc; + if (rc > 0) + return 0; + } + + /* If there is no strategy routine, or if the strategy returns + * zero, proceed with automatic r/w */ + if (table->data && table->maxlen) { + if (oldval && oldlenp) { + get_user(len, oldlenp); + if (len) { + if (len > table->maxlen) + len = table->maxlen; + if(copy_to_user(oldval, table->data, len)) + return -EFAULT; + if(put_user(len, oldlenp)) + return -EFAULT; + } + } + if (newval && newlen) { + len = newlen; + if (len > table->maxlen) + len = table->maxlen; + if(copy_from_user(table->data, newval, len)) + return -EFAULT; + } + } + return 0; +} + +struct ctl_table_header *register_sysctl_table(ctl_table * table, + int insert_at_head) +{ + struct ctl_table_header *tmp; + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return 0; + *tmp = ((struct ctl_table_header) {table, DNODE_NULL}); + if (insert_at_head) + DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry); + else + DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry); +#ifdef CONFIG_PROC_FS + register_proc_table(table, proc_sys_root); +#endif + return tmp; +} + +/* + * Unlink and free a ctl_table. + */ +void unregister_sysctl_table(struct ctl_table_header * header) +{ + DLIST_DELETE(header, ctl_entry); +#ifdef CONFIG_PROC_FS + unregister_proc_table(header->ctl_table, proc_sys_root); +#endif + kfree(header); +} + +/* + * /proc/sys support + */ + +#ifdef CONFIG_PROC_FS + +/* Scan the sysctl entries in table and add them all into /proc */ +static void register_proc_table(ctl_table * table, struct proc_dir_entry *root) +{ + struct proc_dir_entry *de; + int len; + mode_t mode; + + for (; table->ctl_name; table++) { + /* Can't do anything without a proc name. */ + if (!table->procname) + continue; + /* Maybe we can't do anything with it... */ + if (!table->proc_handler && !table->child) { + printk(KERN_WARNING "SYSCTL: Can't register %s\n", + table->procname); + continue; + } + + len = strlen(table->procname); + mode = table->mode; + + de = NULL; + if (table->proc_handler) + mode |= S_IFREG; + else { + mode |= S_IFDIR; + for (de = root->subdir; de; de = de->next) { + if (proc_match(len, table->procname, de)) + break; + } + /* If the subdir exists already, de is non-NULL */ + } + + if (!de) { + de = create_proc_entry(table->procname, mode, root); + if (!de) + continue; + de->data = (void *) table; + if (table->proc_handler) + de->ops = &proc_sys_inode_operations; + + } + table->de = de; + if (de->mode & S_IFDIR) + register_proc_table(table->child, de); + } +} + +/* + * Unregister a /proc sysctl table and any subdirectories. + */ +static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) +{ + struct proc_dir_entry *de; + for (; table->ctl_name; table++) { + if (!(de = table->de)) + continue; + if (de->mode & S_IFDIR) { + if (!table->child) { + printk (KERN_ALERT "Help - malformed sysctl tree on free\n"); + continue; + } + unregister_proc_table(table->child, de); + + /* Don't unregister directories which still have entries.. */ + if (de->subdir) + continue; + } + + /* Don't unregoster proc entries that are still being used.. */ + if (de->count) + continue; + + proc_unregister(root, de->low_ino); + table->de = NULL; + kfree(de); + } +} + +static ssize_t do_rw_proc(int write, struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + int op; + struct proc_dir_entry *de; + struct ctl_table *table; + size_t res; + ssize_t error; + + de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip; + if (!de || !de->data) + return -ENOTDIR; + table = (struct ctl_table *) de->data; + if (!table || !table->proc_handler) + return -ENOTDIR; + op = (write ? 002 : 004); + if (ctl_perm(table, op)) + return -EPERM; + + res = count; + + /* + * FIXME: we need to pass on ppos to the handler. + */ + + error = (*table->proc_handler) (table, write, file, buf, &res); + if (error) + return error; + return res; +} + +static ssize_t proc_readsys(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + return do_rw_proc(0, file, buf, count, ppos); +} + +static ssize_t proc_writesys(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + return do_rw_proc(1, file, (char *) buf, count, ppos); +} + +static int proc_sys_permission(struct inode *inode, int op) +{ + return test_perm(inode->i_mode, op); +} + +int proc_dostring(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int len; + char *p, c; + + if (!table->data || !table->maxlen || !*lenp || + (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + + if (write) { + len = 0; + p = buffer; + while (len < *lenp) { + if(get_user(c, p++)) + return -EFAULT; + if (c == 0 || c == '\n') + break; + len++; + } + if (len >= table->maxlen) + len = table->maxlen-1; + if(copy_from_user(table->data, buffer, len)) + return -EFAULT; + ((char *) table->data)[len] = 0; + filp->f_pos += *lenp; + } else { + len = strlen(table->data); + if (len > table->maxlen) + len = table->maxlen; + if (len > *lenp) + len = *lenp; + if (len) + if(copy_to_user(buffer, table->data, len)) + return -EFAULT; + if (len < *lenp) { + if(put_user('\n', ((char *) buffer) + len)) + return -EFAULT; + len++; + } + *lenp = len; + filp->f_pos += len; + } + return 0; +} + +/* + * Special case of dostring for the UTS structure. This has locks + * to observe. Should this be in kernel/sys.c ???? + */ + +static int proc_doutsstring(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int r; + down(&uts_sem); + r=proc_dostring(table,write,filp,buffer,lenp); + up(&uts_sem); + return r; +} + +#define OP_SET 0 +#define OP_AND 1 +#define OP_OR 2 +#define OP_MAX 3 +#define OP_MIN 4 +static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, int conv, int op) +{ + int *i, vleft, first=1, len, left, neg, val; + #define TMPBUFLEN 20 + char buf[TMPBUFLEN], *p; + + if (!table->data || !table->maxlen || !*lenp || + (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + + i = (int *) table->data; + vleft = table->maxlen / sizeof(int); + left = *lenp; + + for (; left && vleft--; i++, first=0) { + if (write) { + while (left) { + char c; + if(get_user(c,(char *) buffer)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + ((char *) buffer)++; + } + if (!left) + break; + neg = 0; + len = left; + if (len > TMPBUFLEN-1) + len = TMPBUFLEN-1; + if(copy_from_user(buf, buffer, len)) + return -EFAULT; + buf[len] = 0; + p = buf; + if (*p == '-' && left > 1) { + neg = 1; + left--, p++; + } + if (*p < '0' || *p > '9') + break; + val = simple_strtoul(p, &p, 0) * conv; + len = p-buf; + if ((len < left) && *p && !isspace(*p)) + break; + if (neg) + val = -val; + buffer += len; + left -= len; + switch(op) { + case OP_SET: *i = val; break; + case OP_AND: *i &= val; break; + case OP_OR: *i |= val; break; + case OP_MAX: if(*i < val) + *i = val; + break; + case OP_MIN: if(*i > val) + *i = val; + break; + } + } else { + p = buf; + if (!first) + *p++ = '\t'; + sprintf(p, "%d", (*i) / conv); + len = strlen(buf); + if (len > left) + len = left; + if(copy_to_user(buffer, buf, len)) + return -EFAULT; + left -= len; + buffer += len; + } + } + + if (!write && !first && left) { + if(put_user('\n', (char *) buffer)) + return -EFAULT; + left--, buffer++; + } + if (write) { + p = (char *) buffer; + while (left) { + char c; + if(get_user(c, p++)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + } + } + if (write && first) + return -EINVAL; + *lenp -= left; + filp->f_pos += *lenp; + return 0; +} + +int proc_dointvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET); +} + +/* + * init may raise the set. + */ + +int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return do_proc_dointvec(table,write,filp,buffer,lenp,1, + (current->pid == 1) ? OP_SET : OP_AND); +} + + +int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int *i, *min, *max, vleft, first=1, len, left, neg, val; + #define TMPBUFLEN 20 + char buf[TMPBUFLEN], *p; + + if (!table->data || !table->maxlen || !*lenp || + (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + + i = (int *) table->data; + min = (int *) table->extra1; + max = (int *) table->extra2; + vleft = table->maxlen / sizeof(int); + left = *lenp; + + for (; left && vleft--; i++, first=0) { + if (write) { + while (left) { + char c; + if(get_user(c, (char *) buffer)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + ((char *) buffer)++; + } + if (!left) + break; + neg = 0; + len = left; + if (len > TMPBUFLEN-1) + len = TMPBUFLEN-1; + if(copy_from_user(buf, buffer, len)) + return -EFAULT; + buf[len] = 0; + p = buf; + if (*p == '-' && left > 1) { + neg = 1; + left--, p++; + } + if (*p < '0' || *p > '9') + break; + val = simple_strtoul(p, &p, 0); + len = p-buf; + if ((len < left) && *p && !isspace(*p)) + break; + if (neg) + val = -val; + buffer += len; + left -= len; + + if (min && val < *min++) + continue; + if (max && val > *max++) + continue; + *i = val; + } else { + p = buf; + if (!first) + *p++ = '\t'; + sprintf(p, "%d", *i); + len = strlen(buf); + if (len > left) + len = left; + if(copy_to_user(buffer, buf, len)) + return -EFAULT; + left -= len; + buffer += len; + } + } + + if (!write && !first && left) { + if(put_user('\n', (char *) buffer)) + return -EFAULT; + left--, buffer++; + } + if (write) { + p = (char *) buffer; + while (left) { + char c; + if(get_user(c, p++)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + } + } + if (write && first) + return -EINVAL; + *lenp -= left; + filp->f_pos += *lenp; + return 0; +} + + +/* + * an unsigned long function version + */ + +static int do_proc_doulongvec_minmax(ctl_table *table, int write, + struct file *filp, + void *buffer, size_t *lenp, + unsigned long convmul, + unsigned long convdiv) +{ +#define TMPBUFLEN 20 + unsigned long *i, *min, *max, val; + int vleft, first=1, len, left, neg; + char buf[TMPBUFLEN], *p; + + if (!table->data || !table->maxlen || !*lenp || + (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + + i = (unsigned long *) table->data; + min = (unsigned long *) table->extra1; + max = (unsigned long *) table->extra2; + vleft = table->maxlen / sizeof(unsigned long); + left = *lenp; + + for (; left && vleft--; i++, first=0) { + if (write) { + while (left) { + char c; + if(get_user(c, (char *) buffer)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + ((char *) buffer)++; + } + if (!left) + break; + neg = 0; + len = left; + if (len > TMPBUFLEN-1) + len = TMPBUFLEN-1; + if(copy_from_user(buf, buffer, len)) + return -EFAULT; + buf[len] = 0; + p = buf; + if (*p == '-' && left > 1) { + neg = 1; + left--, p++; + } + if (*p < '0' || *p > '9') + break; + val = simple_strtoul(p, &p, 0) * convmul / convdiv ; + len = p-buf; + if ((len < left) && *p && !isspace(*p)) + break; + if (neg) + val = -val; + buffer += len; + left -= len; + + if(neg) + continue; + if (min && val < *min++) + continue; + if (max && val > *max++) + continue; + *i = val; + } else { + p = buf; + if (!first) + *p++ = '\t'; + sprintf(p, "%lu", convdiv * (*i) / convmul); + len = strlen(buf); + if (len > left) + len = left; + if(copy_to_user(buffer, buf, len)) + return -EFAULT; + left -= len; + buffer += len; + } + } + + if (!write && !first && left) { + if(put_user('\n', (char *) buffer)) + return -EFAULT; + left--, buffer++; + } + if (write) { + p = (char *) buffer; + while (left) { + char c; + if(get_user(c, p++)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + } + } + if (write && first) + return -EINVAL; + *lenp -= left; + filp->f_pos += *lenp; + return 0; +#undef TMPBUFLEN +} + +int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l); +} + +int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, + struct file *filp, + void *buffer, size_t *lenp) +{ + return do_proc_doulongvec_minmax(table, write, filp, buffer, + lenp, HZ, 1000l); +} + + +/* Like proc_dointvec, but converts seconds to jiffies */ +int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET); +} + +#else /* CONFIG_PROC_FS */ + +int proc_dostring(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +static int proc_doutsstring(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_dointvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, + struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + + +#endif /* CONFIG_PROC_FS */ + + +/* + * General sysctl support routines + */ + +/* The generic string strategy routine: */ +int sysctl_string(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + int l, len; + + if (!table->data || !table->maxlen) + return -ENOTDIR; + + if (oldval && oldlenp) { + if(get_user(len, oldlenp)) + return -EFAULT; + if (len) { + l = strlen(table->data); + if (len > l) len = l; + if (len >= table->maxlen) + len = table->maxlen; + if(copy_to_user(oldval, table->data, len)) + return -EFAULT; + if(put_user(0, ((char *) oldval) + len)) + return -EFAULT; + if(put_user(len, oldlenp)) + return -EFAULT; + } + } + if (newval && newlen) { + len = newlen; + if (len > table->maxlen) + len = table->maxlen; + if(copy_from_user(table->data, newval, len)) + return -EFAULT; + if (len == table->maxlen) + len--; + ((char *) table->data)[len] = 0; + } + return 0; +} + +/* + * This function makes sure that all of the integers in the vector + * are between the minimum and maximum values given in the arrays + * table->extra1 and table->extra2, respectively. + */ +int sysctl_intvec(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + int i, length, *vec, *min, *max; + + if (newval && newlen) { + if (newlen % sizeof(int) != 0) + return -EINVAL; + + if (!table->extra1 && !table->extra2) + return 0; + + if (newlen > table->maxlen) + newlen = table->maxlen; + length = newlen / sizeof(int); + + vec = (int *) newval; + min = (int *) table->extra1; + max = (int *) table->extra2; + + for (i = 0; i < length; i++) { + int value; + get_user(value, vec + i); + if (min && value < min[i]) + return -EINVAL; + if (max && value > max[i]) + return -EINVAL; + } + } + return 0; +} + +/* Strategy function to convert jiffies to seconds */ +int sysctl_jiffies(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + if (oldval) { + size_t olen; + if (oldlenp) { + if (get_user(olen, oldlenp)) + return -EFAULT; + if (olen!=sizeof(int)) + return -EINVAL; + } + if (put_user(*(int *)(table->data) / HZ, (int *)oldval) || + (oldlenp && put_user(sizeof(int),oldlenp))) + return -EFAULT; + } + if (newval && newlen) { + int new; + if (newlen != sizeof(int)) + return -EINVAL; + if (get_user(new, (int *)newval)) + return -EFAULT; + *(int *)(table->data) = new*HZ; + } + return 1; +} + +int do_string ( + void *oldval, size_t *oldlenp, void *newval, size_t newlen, + int rdwr, char *data, size_t max) +{ + int l = strlen(data) + 1; + if (newval && !rdwr) + return -EPERM; + if (newval && newlen >= max) + return -EINVAL; + if (oldval) { + int old_l; + if(get_user(old_l, oldlenp)) + return -EFAULT; + if (l > old_l) + return -ENOMEM; + if(put_user(l, oldlenp) || copy_to_user(oldval, data, l)) + return -EFAULT; + } + if (newval) { + if(copy_from_user(data, newval, newlen)) + return -EFAULT; + data[newlen] = 0; + } + return 0; +} + +int do_int ( + void *oldval, size_t *oldlenp, void *newval, size_t newlen, + int rdwr, int *data) +{ + if (newval && !rdwr) + return -EPERM; + if (newval && newlen != sizeof(int)) + return -EINVAL; + if (oldval) { + int old_l; + if(get_user(old_l, oldlenp)) + return -EFAULT; + if (old_l < sizeof(int)) + return -ENOMEM; + if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int))) + return -EFAULT; + } + if (newval) + if(copy_from_user(data, newval, sizeof(int))) + return -EFAULT; + return 0; +} + +int do_struct ( + void *oldval, size_t *oldlenp, void *newval, size_t newlen, + int rdwr, void *data, size_t len) +{ + if (newval && !rdwr) + return -EPERM; + if (newval && newlen != len) + return -EINVAL; + if (oldval) { + int old_l; + if(get_user(old_l, oldlenp)) + return -EFAULT; + if (old_l < len) + return -ENOMEM; + if(put_user(len, oldlenp) || copy_to_user(oldval, data, len)) + return -EFAULT; + } + if (newval) + if(copy_from_user(data, newval, len)) + return -EFAULT; + return 0; +} + + +#else /* CONFIG_SYSCTL */ + + +extern asmlinkage long sys_sysctl(struct __sysctl_args *args) +{ + return -ENOSYS; +} + +int sysctl_string(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + return -ENOSYS; +} + +int sysctl_intvec(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + return -ENOSYS; +} + +int proc_dostring(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_dointvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, + struct file *filp, + void *buffer, size_t *lenp) +{ + return -ENOSYS; +} + +struct ctl_table_header * register_sysctl_table(ctl_table * table, + int insert_at_head) +{ + return 0; +} + +void unregister_sysctl_table(struct ctl_table_header * table) +{ +} + +#endif /* CONFIG_SYSCTL */ diff -urN 2.3.29pre1/mm/Makefile 2.3.29pre1-ikd/mm/Makefile --- 2.3.29pre1/mm/Makefile Tue Oct 26 21:30:51 1999 +++ 2.3.29pre1-ikd/mm/Makefile Mon Nov 22 16:56:24 1999 @@ -16,4 +16,12 @@ O_OBJS += highmem.o endif +ifeq ($(CONFIG_MEMLEAK),y) +O_OBJS += memleak.o +endif + include $(TOPDIR)/Rules.make + +# memleak beats up cache bad enough without mcount() helping. +memleak.o : memleak.c + $(CC) $(CFLAGS:%-pg=%) -c -o $@ $< diff -urN 2.3.29pre1/mm/Makefile.orig 2.3.29pre1-ikd/mm/Makefile.orig --- 2.3.29pre1/mm/Makefile.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/mm/Makefile.orig Tue Oct 26 21:30:51 1999 @@ -0,0 +1,19 @@ +# +# Makefile for the linux memory manager. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := mm.o +O_OBJS := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ + vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \ + page_alloc.o swap_state.o swapfile.o + +ifeq ($(CONFIG_HIGHMEM),y) +O_OBJS += highmem.o +endif + +include $(TOPDIR)/Rules.make diff -urN 2.3.29pre1/mm/memleak.c 2.3.29pre1-ikd/mm/memleak.c --- 2.3.29pre1/mm/memleak.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/mm/memleak.c Mon Nov 22 16:56:24 1999 @@ -0,0 +1,266 @@ +/* + * linux/mm/memleak.c, memory leak detector + * + * Copyright (C) 1997 Ingo Molnar + * + * Maintainer: Mike Galbraith mikeg@weiden.de + * + * Changelog: + * Dec 18 1997: memleak.c - added wrapper functions for slab.c + * Dec 18 1997: include/asm-i386/pgtable.h + * converted pte_alloc_kernel, pte_alloc, pgd_alloc to macros + */ + +#include +#include +#include +#include + +#include +#include + +/* + * Design: + * + * Every 32 bytes block of memory in the system has an 'allocation map entry'. + * A map entry is a two-fields bitmap, an 'ID' pointing to the allocator, + * and a ~2 seconds granularity timestamp to see object age. + * ID 0 means the block is empty. The allocation map is a very big static + * array, and is preallocated at boot, and put at the end of memory. + * + * This method relies on the fact that no object allocated in Linux + * is smaller than 32 bytes. True that we waste ~10% memory, but the + * method is very simple, extremely fast and generic. There are lots of + * systems that can tolerate 10% less memory, but almost no system + * can tolerate the CPU load caused by O(N) or O(log(N)) 'bookeeping + * algorithms' when allocating memory in a RL system. + * + * This method is a O(1) algorithm. + * + * + * Currently wrapped allocators: + * + * generic page allocator: get_free_pages()/free_pages() + * kernel allocator: kmalloc()/kfree()/kfree_s() + * kmem_cache_create()/kmem_cache_shrink() + * kmem_cache_alloc()/kmem_cache_free() + * networking allocator: skb_alloc()/skb_free() + * + * vmalloc()/vfree() will probably never be supported by + * this method, maybe we can represent them through their + * first physical page. It's not a common allocation + * method. + */ + +#define MIN_MEMBLOCK_SIZE 32 + +#define IDX(addr) (__pa(addr)/MIN_MEMBLOCK_SIZE) + +/* + * We want to keep the allocation map as small as possible + */ +#define ID_BITS 10 +#define MAX_ID (1<", 0 }; +static unsigned int curr_id = 0; +spinlock_t memleak_alloc_lock = SPIN_LOCK_UNLOCKED; + +int alloc_addr_lock(unsigned long addr, struct alloc_struct * id) +{ + unsigned long flags, idx; + + if(!curr_id || !id) /* don't do anything if turned off */ + return 0; + + idx = IDX(addr); + + if (idx > ENTRIES) { + PROBLEM(); + return -1; + } + + spin_lock_irqsave(&memleak_alloc_lock, flags); + + /* If someone else registered ID while I was aquiring, take shortcut + * and only make the alloc_map entry. + */ + if(id->id) + goto alloc_ok; + else + { +#if 0 + printk("allocating ID.%d for %s:%d.\n",curr_id, id->file, id->line); +#endif + id->id = curr_id; + curr_id++; + if (curr_id == MAX_ID) { + printk("ID wrapped around, stopping ID allocation.\n"); + printk("Increase ID_BITS in memleak.c.\n"); + curr_id = 0; + } else + id_map[curr_id-1] = id; + } +alloc_ok: + alloc_map[idx].id = id->id; + alloc_map[idx].timestamp = jiffies>>ID_BITS; + spin_unlock_irqrestore(&memleak_alloc_lock, flags); + return 0; +} + +int alloc_addr_nolock(unsigned long addr, struct alloc_struct * id) +{ + unsigned long idx; + + if(!curr_id || !id ) /* don't do anything if turned off */ + return 0; + + idx = IDX(addr); + + if (idx > ENTRIES) { + PROBLEM(); + return -1; + } + + /* If someone else has already registered ID, take shortcut + * and only make the alloc_map entry. + */ + if(id->id) + goto alloc_ok; +#if 0 + printk("allocating ID.%d for %s:%d.\n",curr_id, id->file, id->line); +#endif + id->id = curr_id; + curr_id++; + if (curr_id == MAX_ID) { + printk("ID wrapped around, stopping ID allocation.\n"); + printk("Increase ID_BITS in memleak.c.\n"); + curr_id = 0; + } else + id_map[curr_id-1] = id; +alloc_ok: + alloc_map[idx].id = id->id; + alloc_map[idx].timestamp = jiffies>>ID_BITS; + return 0; +} + +int free_addr(unsigned long addr) +{ + unsigned idx; + + if(!curr_id) + return 0; + + idx = IDX(addr); + + if (idx > ENTRIES) { + PROBLEM(); + return -1; + } + + alloc_map[idx].id = 0; + return 0; +} + +/* + * We put the alloc table at the end of physical memory + */ +unsigned long memleak_init (unsigned long start_mem, unsigned long end_mem) +{ + unsigned long MEMSIZE, size; + + id_map[0] = &NULL_id; + + end_mem = PAGE_ALIGN(end_mem); + + MEMSIZE = end_mem-PAGE_OFFSET; + ENTRIES = MEMSIZE/(MIN_MEMBLOCK_SIZE+sizeof(struct alloc_entry))+1; + + size = ENTRIES * sizeof(struct alloc_entry); + + end_mem = PAGE_ALIGN(end_mem-size)-PAGE_SIZE; + + alloc_map = (struct alloc_entry *) end_mem; + + printk("MEMLEAK, allocating %ld KB allocation map.\n", size/1024); + + if (!alloc_map) { + PROBLEM(); + for(;;); + } + + memset(alloc_map,0,size); + curr_id = 1; + + return end_mem; +} + + +#define LINE_SIZE 128 + +static ssize_t read_allocations (struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct alloc_struct * id; + unsigned long p; + unsigned long idx; + unsigned long timestamp; + + char line [LINE_SIZE]; + + if(ppos != &file->f_pos) + return -ESPIPE; + + p = idx = *ppos; + + if (count < 0) + return -EINVAL; +repeat: + if (idx >= ENTRIES) + return 0; + + if (alloc_map[idx].id) { + id = id_map[alloc_map[idx].id]; + timestamp = (alloc_map[idx].timestamp< %s:%d (%ld)\n", + (void *)(idx*MIN_MEMBLOCK_SIZE),id->file,id->line,timestamp); + copy_to_user(buf,line,count); + } else { + if (!idx) { + count = sprintf(line,"<%p> jiffies.c:%d (%ld)\n", NULL, 0, jiffies/HZ); + copy_to_user(buf,line,count); + } else { + idx++; + *ppos = idx; + /* + * there is at least one allocation in the system + */ + goto repeat; + } + } + + idx++; + *ppos = idx; + + return count; +} + +static struct file_operations proc_memleak_operations = { + NULL, /* lseek */ + read_allocations, + NULL, /* write */ +}; + +struct inode_operations proc_memleak_inode_operations = { + &proc_memleak_operations, +}; diff -urN 2.3.29pre1/mm/page_alloc.c 2.3.29pre1-ikd/mm/page_alloc.c --- 2.3.29pre1/mm/page_alloc.c Sun Nov 21 03:20:20 1999 +++ 2.3.29pre1-ikd/mm/page_alloc.c Mon Nov 22 16:56:24 1999 @@ -7,6 +7,7 @@ * Reshaped it to be a zoned allocator, Ingo Molnar, Red Hat, 1999 */ +#define MEMLEAK_PASS_ALLOCATION #include #include #include @@ -77,6 +78,15 @@ #endif }; +#ifdef CONFIG_GFP_POISON +static unsigned long poison(unsigned long addr, unsigned long order) +{ + memset((char *) addr, 0x6b, PAGE_SIZE<> (1+(order)), (area)->map) #define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT)) +#ifdef CONFIG_GFP_POISON +#define POISON_ADDRESS(x, o) poison(ADDRESS(x), (o)) +#else +#define POISON_ADDRESS(x, o) ADDRESS(x) +#endif int __free_page (struct page *page) { diff -urN 2.3.29pre1/mm/page_alloc.c.orig 2.3.29pre1-ikd/mm/page_alloc.c.orig --- 2.3.29pre1/mm/page_alloc.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/mm/page_alloc.c.orig Sun Nov 21 03:20:20 1999 @@ -0,0 +1,544 @@ +/* + * linux/mm/page_alloc.c + * + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * Swap reorganised 29.12.95, Stephen Tweedie + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + * Reshaped it to be a zoned allocator, Ingo Molnar, Red Hat, 1999 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* for copy_to/from_user */ +#include + +int nr_swap_pages = 0; +int nr_lru_pages; +LIST_HEAD(lru_cache); + +/* + * Free area management + * + * The free_area_list arrays point to the queue heads of the free areas + * of different sizes + */ + +#if CONFIG_AP1000 +/* the AP+ needs to allocate 8MB contiguous, aligned chunks of ram + for the ring buffers */ +#define MAX_ORDER 12 +#else +#define MAX_ORDER 10 +#endif + +typedef struct free_area_struct { + struct list_head free_list; + unsigned int * map; +} free_area_t; + +#define ZONE_DMA 0 +#define ZONE_NORMAL 1 + +#ifdef CONFIG_HIGHMEM +# define ZONE_HIGHMEM 2 +# define NR_ZONES 3 +#else +# define NR_ZONES 2 +#endif + +typedef struct zone_struct { + spinlock_t lock; + unsigned long offset; + unsigned long size; + free_area_t free_area[MAX_ORDER]; + + unsigned long free_pages; + unsigned long pages_low, pages_high; + int low_on_memory; + char * name; +} zone_t; + +static zone_t zones[NR_ZONES] = + { + { name: "DMA" }, + { name: "Normal" }, +#ifdef CONFIG_HIGHMEM + { name: "HighMem" } +#endif + }; + +/* + * Free_page() adds the page to the free lists. This is optimized for + * fast normal cases (no error jumps taken normally). + * + * The way to optimize jumps for gcc-2.2.2 is to: + * - select the "normal" case and put it inside the if () { XXX } + * - no else-statements if you can avoid them + * + * With the above two rules, you get a straight-line execution path + * for the normal case, giving better asm-code. + */ + +#define memlist_init(x) INIT_LIST_HEAD(x) +#define memlist_add_head list_add +#define memlist_add_tail list_add_tail +#define memlist_del list_del +#define memlist_entry list_entry +#define memlist_next(x) ((x)->next) +#define memlist_prev(x) ((x)->prev) + +/* + * Temporary debugging check. + */ +#define BAD_RANGE(zone,x) ((((x)-mem_map) < zone->offset) || (((x)-mem_map) >= zone->offset+zone->size)) + +/* + * Buddy system. Hairy. You really aren't expected to understand this + * + * Hint: -mask = 1+~mask + */ + +static inline void free_pages_ok (struct page *page, unsigned long map_nr, unsigned long order) +{ + struct free_area_struct *area; + unsigned long index, page_idx, mask, offset; + unsigned long flags; + struct page *buddy; + zone_t *zone; + int i; + + /* + * Which zone is this page belonging to. + * + * (NR_ZONES is low, and we do not want (yet) to introduce + * put page->zone, it increases the size of mem_map[] + * unnecesserily. This small loop is basically equivalent + * to the previous #ifdef jungle, speed-wise.) + */ + i = NR_ZONES-1; + zone = zones + i; + for ( ; i >= 0; i--, zone--) + if (map_nr >= zone->offset) + break; + + mask = (~0UL) << order; + offset = zone->offset; + area = zone->free_area; + area += order; + page_idx = map_nr - zone->offset; + page_idx &= mask; + index = page_idx >> (1 + order); + mask = (~0UL) << order; + + spin_lock_irqsave(&zone->lock, flags); + + zone->free_pages -= mask; + + while (mask + (1 << (MAX_ORDER-1))) { + if (!test_and_change_bit(index, area->map)) + /* + * the buddy page is still allocated. + */ + break; + /* + * Move the buddy up one level. + */ + buddy = mem_map + offset + (page_idx ^ -mask); + page = mem_map + offset + page_idx; + if (BAD_RANGE(zone,buddy)) + BUG(); + if (BAD_RANGE(zone,page)) + BUG(); + + memlist_del(&buddy->list); + mask <<= 1; + area++; + index >>= 1; + page_idx &= mask; + } + memlist_add_head(&mem_map[offset + page_idx].list, &area->free_list); + + spin_unlock_irqrestore(&zone->lock, flags); +} + +/* + * Some ugly macros to speed up __get_free_pages().. + */ +#define MARK_USED(index, order, area) \ + change_bit((index) >> (1+(order)), (area)->map) +#define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT)) + +int __free_page (struct page *page) +{ + if (!PageReserved(page) && put_page_testzero(page)) { + if (PageSwapCache(page)) + PAGE_BUG(page); + if (PageLocked(page)) + PAGE_BUG(page); + + free_pages_ok(page, page-mem_map, 0); + return 1; + } + return 0; +} + +int free_pages (unsigned long addr, unsigned long order) +{ + unsigned long map_nr = MAP_NR(addr); + + if (map_nr < max_mapnr) { + mem_map_t * map = mem_map + map_nr; + if (!PageReserved(map) && put_page_testzero(map)) { + if (PageSwapCache(map)) + PAGE_BUG(map); + if (PageLocked(map)) + PAGE_BUG(map); + free_pages_ok(map, map_nr, order); + return 1; + } + } + return 0; +} + +static inline unsigned long EXPAND (zone_t *zone, struct page *map, unsigned long index, + int low, int high, struct free_area_struct * area) +{ + unsigned long size = 1 << high; + + while (high > low) { + if (BAD_RANGE(zone,map)) + BUG(); + area--; + high--; + size >>= 1; + memlist_add_head(&(map)->list, &(area)->free_list); + MARK_USED(index, high, area); + index += size; + map += size; + } + set_page_count(map, 1); + return index; +} + +static inline struct page * rmqueue (zone_t *zone, unsigned long order) +{ + struct free_area_struct * area = zone->free_area + order; + unsigned long curr_order = order, map_nr; + struct list_head *head, *curr; + unsigned long flags; + struct page *page; + + spin_lock_irqsave(&zone->lock, flags); + do { + head = &area->free_list; + curr = memlist_next(head); + + if (curr != head) { + unsigned int index; + + page = memlist_entry(curr, struct page, list); + memlist_del(curr); + map_nr = page - mem_map; + index = map_nr - zone->offset; + MARK_USED(index, curr_order, area); + zone->free_pages -= 1 << order; + map_nr = zone->offset + EXPAND(zone, page, index, order, curr_order, area); + spin_unlock_irqrestore(&zone->lock, flags); + + page = mem_map + map_nr; + if (BAD_RANGE(zone,page)) + BUG(); + return page; + } + curr_order++; + area++; + } while (curr_order < MAX_ORDER); + spin_unlock_irqrestore(&zone->lock, flags); + + return NULL; +} + +static inline int balance_memory (zone_t *zone, int gfp_mask) +{ + int freed; + + if (zone->free_pages > zone->pages_low) { + if (!zone->low_on_memory) + return 1; + /* + * Simple hysteresis: exit 'low memory mode' if + * the upper limit has been reached: + */ + if (zone->free_pages >= zone->pages_high) { + zone->low_on_memory = 0; + return 1; + } + } + zone->low_on_memory = 1; + + current->flags |= PF_MEMALLOC; + freed = try_to_free_pages(gfp_mask); + current->flags &= ~PF_MEMALLOC; + + if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH))) + return 0; + return 1; +} + +static inline struct page * __get_pages (zone_t *zone, unsigned int gfp_mask, + unsigned long order) +{ + struct page *page; + + if (order >= MAX_ORDER) + goto nopage; + + /* + * If anyone calls gfp from interrupts nonatomically then it + * will sooner or later tripped up by a schedule(). + */ + + /* + * If this is a recursive call, we'd better + * do our best to just allocate things without + * further thought. + */ + if (!(current->flags & PF_MEMALLOC)) + if (!balance_memory(zone, gfp_mask)) + goto nopage; + /* + * We are falling back to lower-level zones if allocation + * in a higher zone fails. This assumes a hierarchical + * dependency between zones, which is true currently. If + * you need something else then move this loop outside + * this function, into the zone-specific allocator. + */ + do { + page = rmqueue(zone, order); + if (page) + return page; + } while (zone-- != zones) ; + + /* + * If we can schedule, do so, and make sure to yield. + * We may be a real-time process, and if kswapd is + * waiting for us we need to allow it to run a bit. + */ + if (gfp_mask & __GFP_WAIT) { + current->policy |= SCHED_YIELD; + schedule(); + } + +nopage: + return NULL; +} + +static inline zone_t * gfp_mask_to_zone (int gfp_mask) +{ + zone_t *zone; + +#if CONFIG_HIGHMEM + if (gfp_mask & __GFP_HIGHMEM) + zone = zones + ZONE_HIGHMEM; + else +#endif + if (gfp_mask & __GFP_DMA) + zone = zones + ZONE_DMA; + else + zone = zones + ZONE_NORMAL; + return zone; +} + +unsigned long __get_free_pages (int gfp_mask, unsigned long order) +{ + struct page *page; + + page = __get_pages(gfp_mask_to_zone(gfp_mask), gfp_mask, order); + if (!page) + return 0; + return page_address(page); +} + +struct page * alloc_pages (int gfp_mask, unsigned long order) +{ + return __get_pages(gfp_mask_to_zone(gfp_mask), gfp_mask, order); +} + +/* + * Total amount of free (allocatable) RAM: + */ +unsigned int nr_free_pages (void) +{ + unsigned int sum; + zone_t *zone; + + sum = 0; + for (zone = zones; zone < zones+NR_ZONES; zone++) + sum += zone->free_pages; + return sum; +} + +/* + * Amount of free RAM allocatable as buffer memory: + */ +unsigned int nr_free_buffer_pages (void) +{ + unsigned int sum; + zone_t *zone; + + sum = nr_lru_pages; + for (zone = zones; zone <= zones+ZONE_NORMAL; zone++) + sum += zone->free_pages; + return sum; +} + +#if CONFIG_HIGHMEM +unsigned int nr_free_highpages (void) +{ + return zones[ZONE_HIGHMEM].free_pages; +} +#endif + +/* + * Show free area list (used inside shift_scroll-lock stuff) + * We also calculate the percentage fragmentation. We do this by counting the + * memory on each free list with the exception of the first item on the list. + */ +void show_free_areas(void) +{ + unsigned long order; + unsigned type; + + printk("Free pages: %6dkB (%6dkB HighMem)\n", + nr_free_pages()<<(PAGE_SHIFT-10), + nr_free_highpages()<<(PAGE_SHIFT-10)); + printk("( Free: %d, lru_cache: %d (%d %d %d) )\n", + nr_free_pages(), + nr_lru_pages, + freepages.min, + freepages.low, + freepages.high); + + for (type = 0; type < NR_ZONES; type++) { + zone_t *zone = zones + type; + unsigned long total = 0; + + printk(" %s: ", zone->name); + for (order = 0; order < MAX_ORDER; order++) { + unsigned long i, nr; + + nr = 0; + for (i = 0; i < zone->size; i += 1<offset + i; + if (!page_count(page)) + nr++; + } + total += nr * ((PAGE_SIZE>>10) << order); + printk("%lu*%lukB ", nr, (unsigned long)((PAGE_SIZE>>10) << order)); + } + printk("= %lukB)\n", total); + } + +#ifdef SWAP_CACHE_INFO + show_swap_cache_info(); +#endif +} + +#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) + +/* + * Set up the zone data structures: + * - mark all pages reserved + * - mark all memory queues empty + * - clear the memory bitmaps + */ +void __init free_area_init(unsigned int *zones_size) +{ + mem_map_t * p; + unsigned long i, j; + unsigned long map_size; + unsigned int totalpages, offset; + + totalpages = 0; + for (i = 0; i < NR_ZONES; i++) + totalpages += zones_size[i]; + printk("totalpages: %08x\n", totalpages); + + i = totalpages >> 7; + /* + * Select nr of pages we try to keep free for important stuff + * with a minimum of 10 pages and a maximum of 256 pages, so + * that we don't waste too much memory on large systems. + * This is fairly arbitrary, but based on some behaviour + * analysis. + */ + i = totalpages >> 7; + if (i < 10) + i = 10; + if (i > 256) + i = 256; + freepages.min = i; + freepages.low = i * 2; + freepages.high = i * 3; + + /* + * Some architectures (with lots of mem and discontinous memory + * maps) have to search for a good mem_map area: + */ + map_size = totalpages*sizeof(struct page); + mem_map = (struct page *) alloc_bootmem(map_size); + memset(mem_map, 0, map_size); + + /* + * Initially all pages are reserved - free ones are freed + * up by free_all_bootmem() once the early boot process is + * done. + */ + for (p = mem_map; p < mem_map + totalpages; p++) { + set_page_count(p, 0); + p->flags = (1 << PG_DMA); + SetPageReserved(p); + init_waitqueue_head(&p->wait); + memlist_init(&p->list); + } + + offset = 0; + for (j = 0; j < NR_ZONES; j++) { + zone_t *zone = zones + j; + unsigned long mask = -1; + unsigned long size; + + size = zones_size[j]; + zone->size = size; + zone->offset = offset; + zone->pages_low = freepages.low; + zone->pages_high = freepages.high; + zone->low_on_memory = 0; + + offset += size; + for (i = 0; i < MAX_ORDER; i++) { + unsigned long bitmap_size; + unsigned int * map; + memlist_init(&zone->free_area[i].free_list); + mask += mask; + size = (size + ~mask) & mask; + bitmap_size = size >> i; + bitmap_size = (bitmap_size + 7) >> 3; + bitmap_size = LONG_ALIGN(bitmap_size); + map = (unsigned int *) alloc_bootmem(bitmap_size); + zone->free_area[i].map = map; + memset((void *) map, 0, bitmap_size); + } + } +} diff -urN 2.3.29pre1/mm/page_alloc.c.rej 2.3.29pre1-ikd/mm/page_alloc.c.rej --- 2.3.29pre1/mm/page_alloc.c.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/mm/page_alloc.c.rej Mon Nov 22 16:56:24 1999 @@ -0,0 +1,79 @@ +*************** +*** 112,117 **** + nr_free_bigpages -= mask; + } + #endif + map_nr &= mask; + nr_free_pages -= mask; + while (mask + (1 << (NR_MEM_LISTS-1))) { +--- 122,134 ---- + nr_free_bigpages -= mask; + } + #endif ++ #ifdef CONFIG_GFP_POISON ++ #ifdef CONFIG_BIGMEM ++ else ++ #endif ++ poison(PAGE_OFFSET + (map_nr << PAGE_SHIFT), order); ++ #endif ++ MEMLEAK_FREE((PAGE_OFFSET + ((map_nr) << PAGE_SHIFT))); /*ADDRESS macro below*/ + map_nr &= mask; + nr_free_pages -= mask; + while (mask + (1 << (NR_MEM_LISTS-1))) { +*************** +*** 196,201 **** + nr_free_pages -= 1 << order; \ + nr_free_bigpages -= 1 << order; \ + EXPAND(ret, map_nr, order, new_order, area); \ + spin_unlock_irqrestore(&page_alloc_lock, flags); \ + return ADDRESS(map_nr); \ + } \ +--- 218,224 ---- + nr_free_pages -= 1 << order; \ + nr_free_bigpages -= 1 << order; \ + EXPAND(ret, map_nr, order, new_order, area); \ ++ MEMLEAK_ALLOC_NOLOCK(ADDRESS(map_nr)); \ + spin_unlock_irqrestore(&page_alloc_lock, flags); \ + return ADDRESS(map_nr); \ + } \ +*************** +*** 216,223 **** + MARK_USED(map_nr, new_order, area); \ + nr_free_pages -= 1 << order; \ + EXPAND(ret, map_nr, order, new_order, area); \ + spin_unlock_irqrestore(&page_alloc_lock,flags);\ +- return ADDRESS(map_nr); \ + } \ + prev = ret; \ + ret = ret->next; \ +--- 239,247 ---- + MARK_USED(map_nr, new_order, area); \ + nr_free_pages -= 1 << order; \ + EXPAND(ret, map_nr, order, new_order, area); \ ++ MEMLEAK_ALLOC_NOLOCK(ADDRESS(map_nr)); \ + spin_unlock_irqrestore(&page_alloc_lock,flags);\ ++ return POISON_ADDRESS(map_nr, order); \ + } \ + prev = ret; \ + ret = ret->next; \ +*************** +*** 238,244 **** + set_page_count(map, 1); \ + } while (0) + + unsigned long __get_free_pages(int gfp_mask, unsigned long order) + { + unsigned long flags; + +--- 262,272 ---- + set_page_count(map, 1); \ + } while (0) + ++ #ifndef CONFIG_MEMLEAK + unsigned long __get_free_pages(int gfp_mask, unsigned long order) ++ #else ++ unsigned long __get_free_pages_wrap(int gfp_mask, unsigned long order, struct alloc_struct *IDPTR) ++ #endif + { + unsigned long flags; + diff -urN 2.3.29pre1/mm/slab.c 2.3.29pre1-ikd/mm/slab.c --- 2.3.29pre1/mm/slab.c Tue Nov 2 12:06:25 1999 +++ 2.3.29pre1-ikd/mm/slab.c Mon Nov 22 16:56:24 1999 @@ -102,10 +102,19 @@ * is less than 512 (PAGE_SIZE<<3), but greater than 256. */ +#define MEMLEAK_PASS_ALLOCATION +#define MEMLEAK_UNWRAP_SLAB + #include #include #include #include +#include +#include +#include + +#include +#include /* If there is a different PAGE_SIZE around, and it works with this allocator, * then change the following. @@ -127,7 +136,11 @@ * SLAB_SELFTEST - 1 to perform a few tests, mainly for development. */ #define SLAB_MGMT_CHECKS 1 +#ifndef CONFIG_SLAB_POISON #define SLAB_DEBUG_SUPPORT 0 +#else +#define SLAB_DEBUG_SUPPORT 1 +#endif #define SLAB_STATS 0 #define SLAB_SELFTEST 0 @@ -677,9 +690,15 @@ * NOTE: The 'name' is assumed to be memory that is _not_ going to disappear. */ kmem_cache_t * +#ifndef CONFIG_MEMLEAK kmem_cache_create(const char *name, size_t size, size_t offset, unsigned long flags, void (*ctor)(void*, kmem_cache_t *, unsigned long), void (*dtor)(void*, kmem_cache_t *, unsigned long)) +#else +kmem_cache_create_wrap(const char *name, size_t size, size_t offset, + unsigned long flags, void (*ctor)(void*, kmem_cache_t *, unsigned long), + void (*dtor)(void*, kmem_cache_t *, unsigned long), struct alloc_struct *IDPTR) +#endif { const char *func_nm= KERN_ERR "kmem_create: "; kmem_cache_t *searchp; @@ -688,6 +707,9 @@ size_t left_over; size_t align; +#ifdef CONFIG_SLAB_POISON + flags |= SLAB_POISON; +#endif /* Sanity checks... */ #if SLAB_MGMT_CHECKS if (!name) { @@ -1118,12 +1140,17 @@ kmem_cache_free(&cache_cache, cachep); + MEMLEAK_FREE(cachep); return 0; } /* Get the memory for a slab management obj. */ static inline kmem_slab_t * +#ifndef CONFIG_MEMLEAK kmem_cache_slabmgmt(kmem_cache_t *cachep, void *objp, int local_flags) +#else +kmem_cache_slabmgmt_wrap(kmem_cache_t *cachep, void *objp, int local_flags, struct alloc_struct *IDPTR) +#endif { kmem_slab_t *slabp; @@ -1211,7 +1238,11 @@ * kmem_cache_alloc() when there are no active objs left in a cache. */ static int +#ifndef CONFIG_MEMLEAK kmem_cache_grow(kmem_cache_t * cachep, int flags) +#else +kmem_cache_grow_wrap(kmem_cache_t * cachep, int flags, struct alloc_struct *IDPTR) +#endif { kmem_slab_t *slabp; struct page *page; @@ -1421,7 +1452,11 @@ /* Returns a ptr to an obj in the given cache. */ static inline void * +#ifndef CONFIG_MEMLEAK __kmem_cache_alloc(kmem_cache_t *cachep, int flags) +#else +__kmem_cache_alloc_wrap(kmem_cache_t *cachep, int flags, struct alloc_struct *IDPTR) +#endif { kmem_slab_t *slabp; kmem_bufctl_t *bufp; @@ -1459,6 +1494,7 @@ * obj has been removed from the slab. Should be safe to drop * the lock here. */ + MEMLEAK_ALLOC_NOLOCK(objp); spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); #if SLAB_DEBUG_SUPPORT if (cachep->c_flags & SLAB_RED_ZONE) @@ -1591,6 +1627,7 @@ kmem_poison_obj(cachep, objp); } #endif /* SLAB_DEBUG_SUPPORT */ + MEMLEAK_FREE(objp); spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); return; } @@ -1666,7 +1703,11 @@ } void * +#ifndef CONFIG_MEMLEAK kmem_cache_alloc(kmem_cache_t *cachep, int flags) +#else +kmem_cache_alloc_wrap(kmem_cache_t *cachep, int flags, struct alloc_struct *IDPTR) +#endif { return __kmem_cache_alloc(cachep, flags); } @@ -1678,7 +1719,11 @@ } void * +#ifndef CONFIG_MEMLEAK kmalloc(size_t size, int flags) +#else +kmalloc_wrap(size_t size, int flags, struct alloc_struct *IDPTR) +#endif { cache_sizes_t *csizep = cache_sizes; diff -urN 2.3.29pre1/mm/slab.c.orig 2.3.29pre1-ikd/mm/slab.c.orig --- 2.3.29pre1/mm/slab.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/mm/slab.c.orig Tue Nov 2 12:06:25 1999 @@ -0,0 +1,2015 @@ +/* + * linux/mm/slab.c + * Written by Mark Hemment, 1996/97. + * (markhe@nextd.demon.co.uk) + * + * kmem_cache_destroy() + some cleanup - 1999 Andrea Arcangeli + * + * 11 April '97. Started multi-threading - markhe + * The global cache-chain is protected by the semaphore 'cache_chain_sem'. + * The sem is only needed when accessing/extending the cache-chain, which + * can never happen inside an interrupt (kmem_cache_create(), + * kmem_cache_shrink() and kmem_cache_reap()). + * This is a medium-term exclusion lock. + * + * Each cache has its own lock; 'c_spinlock'. This lock is needed only + * when accessing non-constant members of a cache-struct. + * Note: 'constant members' are assigned a value in kmem_cache_create() before + * the cache is linked into the cache-chain. The values never change, so not + * even a multi-reader lock is needed for these members. + * The c_spinlock is only ever held for a few cycles. + * + * To prevent kmem_cache_shrink() trying to shrink a 'growing' cache (which + * maybe be sleeping and therefore not holding the semaphore/lock), the + * c_growing field is used. This also prevents reaping from a cache. + * + * Note, caches can _never_ be destroyed. When a sub-system (eg module) has + * finished with a cache, it can only be shrunk. This leaves the cache empty, + * but already enabled for re-use, eg. during a module re-load. + * + * Notes: + * o Constructors/deconstructors are called while the cache-lock + * is _not_ held. Therefore they _must_ be threaded. + * o Constructors must not attempt to allocate memory from the + * same cache that they are a constructor for - infinite loop! + * (There is no easy way to trap this.) + * o The per-cache locks must be obtained with local-interrupts disabled. + * o When compiled with debug support, and an object-verify (upon release) + * is request for a cache, the verify-function is called with the cache + * lock held. This helps debugging. + * o The functions called from try_to_free_page() must not attempt + * to allocate memory from a cache which is being grown. + * The buffer sub-system might try to allocate memory, via buffer_cachep. + * As this pri is passed to the SLAB, and then (if necessary) onto the + * gfp() funcs (which avoid calling try_to_free_page()), no deadlock + * should happen. + * + * The positioning of the per-cache lock is tricky. If the lock is + * placed on the same h/w cache line as commonly accessed members + * the number of L1 cache-line faults is reduced. However, this can + * lead to the cache-line ping-ponging between processors when the + * lock is in contention (and the common members are being accessed). + * Decided to keep it away from common members. + * + * More fine-graining is possible, with per-slab locks...but this might be + * taking fine graining too far, but would have the advantage; + * During most allocs/frees no writes occur to the cache-struct. + * Therefore a multi-reader/one writer lock could be used (the writer + * needed when the slab chain is being link/unlinked). + * As we would not have an exclusion lock for the cache-structure, one + * would be needed per-slab (for updating s_free ptr, and/or the contents + * of s_index). + * The above locking would allow parallel operations to different slabs within + * the same cache with reduced spinning. + * + * Per-engine slab caches, backed by a global cache (as in Mach's Zone allocator), + * would allow most allocations from the same cache to execute in parallel. + * + * At present, each engine can be growing a cache. This should be blocked. + * + * It is not currently 100% safe to examine the page_struct outside of a kernel + * or global cli lock. The risk is v. small, and non-fatal. + * + * Calls to printk() are not 100% safe (the function is not threaded). However, + * printk() is only used under an error condition, and the risk is v. small (not + * sure if the console write functions 'enjoy' executing multiple contexts in + * parallel. I guess they don't...). + * Note, for most calls to printk() any held cache-lock is dropped. This is not + * always done for text size reasons - having *_unlock() everywhere is bloat. + */ + +/* + * An implementation of the Slab Allocator as described in outline in; + * UNIX Internals: The New Frontiers by Uresh Vahalia + * Pub: Prentice Hall ISBN 0-13-101908-2 + * or with a little more detail in; + * The Slab Allocator: An Object-Caching Kernel Memory Allocator + * Jeff Bonwick (Sun Microsystems). + * Presented at: USENIX Summer 1994 Technical Conference + */ + +/* + * This implementation deviates from Bonwick's paper as it + * does not use a hash-table for large objects, but rather a per slab + * index to hold the bufctls. This allows the bufctl structure to + * be small (one word), but limits the number of objects a slab (not + * a cache) can contain when off-slab bufctls are used. The limit is the + * size of the largest general cache that does not use off-slab bufctls, + * divided by the size of a bufctl. For 32bit archs, is this 256/4 = 64. + * This is not serious, as it is only for large objects, when it is unwise + * to have too many per slab. + * Note: This limit can be raised by introducing a general cache whose size + * is less than 512 (PAGE_SIZE<<3), but greater than 256. + */ + +#include +#include +#include +#include + +/* If there is a different PAGE_SIZE around, and it works with this allocator, + * then change the following. + */ +#if (PAGE_SIZE != 8192 && PAGE_SIZE != 4096 && PAGE_SIZE != 32768) +#error Your page size is probably not correctly supported - please check +#endif + +/* SLAB_MGMT_CHECKS - 1 to enable extra checks in kmem_cache_create(). + * 0 if you wish to reduce memory usage. + * + * SLAB_DEBUG_SUPPORT - 1 for kmem_cache_create() to honour; SLAB_DEBUG_FREE, + * SLAB_DEBUG_INITIAL, SLAB_RED_ZONE & SLAB_POISON. + * 0 for faster, smaller, code (especially in the critical paths). + * + * SLAB_STATS - 1 to collect stats for /proc/slabinfo. + * 0 for faster, smaller, code (especially in the critical paths). + * + * SLAB_SELFTEST - 1 to perform a few tests, mainly for development. + */ +#define SLAB_MGMT_CHECKS 1 +#define SLAB_DEBUG_SUPPORT 0 +#define SLAB_STATS 0 +#define SLAB_SELFTEST 0 + +/* Shouldn't this be in a header file somewhere? */ +#define BYTES_PER_WORD sizeof(void *) + +/* Legal flag mask for kmem_cache_create(). */ +#if SLAB_DEBUG_SUPPORT +#if 0 +#define SLAB_C_MASK (SLAB_DEBUG_FREE|SLAB_DEBUG_INITIAL|SLAB_RED_ZONE| \ + SLAB_POISON|SLAB_HWCACHE_ALIGN|SLAB_NO_REAP| \ + SLAB_HIGH_PACK) +#endif +#define SLAB_C_MASK (SLAB_DEBUG_FREE|SLAB_DEBUG_INITIAL|SLAB_RED_ZONE| \ + SLAB_POISON|SLAB_HWCACHE_ALIGN|SLAB_NO_REAP) +#else +#if 0 +#define SLAB_C_MASK (SLAB_HWCACHE_ALIGN|SLAB_NO_REAP|SLAB_HIGH_PACK) +#endif +#define SLAB_C_MASK (SLAB_HWCACHE_ALIGN|SLAB_NO_REAP) +#endif /* SLAB_DEBUG_SUPPORT */ + +/* Slab management struct. + * Manages the objs in a slab. Placed either at the end of mem allocated + * for a slab, or from an internal obj cache (cache_slabp). + * Slabs are chained into a partially ordered list; fully used first, partial + * next, and then fully free slabs. + * The first 4 members are referenced during an alloc/free operation, and + * should always appear on the same cache line. + * Note: The offset between some members _must_ match offsets within + * the kmem_cache_t - see kmem_cache_init() for the checks. */ + +#define SLAB_OFFSET_BITS 16 /* could make this larger for 64bit archs */ + +typedef struct kmem_slab_s { + struct kmem_bufctl_s *s_freep; /* ptr to first inactive obj in slab */ + struct kmem_bufctl_s *s_index; + unsigned long s_magic; + unsigned long s_inuse; /* num of objs active in slab */ + + struct kmem_slab_s *s_nextp; + struct kmem_slab_s *s_prevp; + void *s_mem; /* addr of first obj in slab */ + unsigned long s_offset:SLAB_OFFSET_BITS, + s_dma:1; +} kmem_slab_t; + +/* When the slab management is on-slab, this gives the size to use. */ +#define slab_align_size (L1_CACHE_ALIGN(sizeof(kmem_slab_t))) + +/* Test for end of slab chain. */ +#define kmem_slab_end(x) ((kmem_slab_t*)&((x)->c_offset)) + +/* s_magic */ +#define SLAB_MAGIC_ALLOC 0xA5C32F2BUL /* slab is alive */ +#define SLAB_MAGIC_DESTROYED 0xB2F23C5AUL /* slab has been destroyed */ + +/* Bufctl's are used for linking objs within a slab, identifying what slab an obj + * is in, and the address of the associated obj (for sanity checking with off-slab + * bufctls). What a bufctl contains depends upon the state of the obj and + * the organisation of the cache. + */ +typedef struct kmem_bufctl_s { + union { + struct kmem_bufctl_s *buf_nextp; + kmem_slab_t *buf_slabp; /* slab for obj */ + void * buf_objp; + } u; +} kmem_bufctl_t; + +/* ...shorthand... */ +#define buf_nextp u.buf_nextp +#define buf_slabp u.buf_slabp +#define buf_objp u.buf_objp + +#if SLAB_DEBUG_SUPPORT +/* Magic nums for obj red zoning. + * Placed in the first word before and the first word after an obj. + */ +#define SLAB_RED_MAGIC1 0x5A2CF071UL /* when obj is active */ +#define SLAB_RED_MAGIC2 0x170FC2A5UL /* when obj is inactive */ + +/* ...and for poisoning */ +#define SLAB_POISON_BYTE 0x5a /* byte value for poisoning */ +#define SLAB_POISON_END 0xa5 /* end-byte of poisoning */ + +#endif /* SLAB_DEBUG_SUPPORT */ + +/* Cache struct - manages a cache. + * First four members are commonly referenced during an alloc/free operation. + */ +struct kmem_cache_s { + kmem_slab_t *c_freep; /* first slab w. free objs */ + unsigned long c_flags; /* constant flags */ + unsigned long c_offset; + unsigned long c_num; /* # of objs per slab */ + + unsigned long c_magic; + unsigned long c_inuse; /* kept at zero */ + kmem_slab_t *c_firstp; /* first slab in chain */ + kmem_slab_t *c_lastp; /* last slab in chain */ + + spinlock_t c_spinlock; + unsigned long c_growing; + unsigned long c_dflags; /* dynamic flags */ + size_t c_org_size; + unsigned long c_gfporder; /* order of pgs per slab (2^n) */ + void (*c_ctor)(void *, kmem_cache_t *, unsigned long); /* constructor func */ + void (*c_dtor)(void *, kmem_cache_t *, unsigned long); /* de-constructor func */ + unsigned long c_align; /* alignment of objs */ + size_t c_colour; /* cache colouring range */ + size_t c_colour_next;/* cache colouring */ + unsigned long c_failures; + const char *c_name; + struct kmem_cache_s *c_nextp; + kmem_cache_t *c_index_cachep; +#if SLAB_STATS + unsigned long c_num_active; + unsigned long c_num_allocations; + unsigned long c_high_mark; + unsigned long c_grown; + unsigned long c_reaped; + atomic_t c_errors; +#endif /* SLAB_STATS */ +}; + +/* internal c_flags */ +#define SLAB_CFLGS_OFF_SLAB 0x010000UL /* slab management in own cache */ +#define SLAB_CFLGS_BUFCTL 0x020000UL /* bufctls in own cache */ +#define SLAB_CFLGS_GENERAL 0x080000UL /* a general cache */ + +/* c_dflags (dynamic flags). Need to hold the spinlock to access this member */ +#define SLAB_CFLGS_GROWN 0x000002UL /* don't reap a recently grown */ + +#define SLAB_OFF_SLAB(x) ((x) & SLAB_CFLGS_OFF_SLAB) +#define SLAB_BUFCTL(x) ((x) & SLAB_CFLGS_BUFCTL) +#define SLAB_GROWN(x) ((x) & SLAB_CFLGS_GROWN) + +#if SLAB_STATS +#define SLAB_STATS_INC_ACTIVE(x) ((x)->c_num_active++) +#define SLAB_STATS_DEC_ACTIVE(x) ((x)->c_num_active--) +#define SLAB_STATS_INC_ALLOCED(x) ((x)->c_num_allocations++) +#define SLAB_STATS_INC_GROWN(x) ((x)->c_grown++) +#define SLAB_STATS_INC_REAPED(x) ((x)->c_reaped++) +#define SLAB_STATS_SET_HIGH(x) do { if ((x)->c_num_active > (x)->c_high_mark) \ + (x)->c_high_mark = (x)->c_num_active; \ + } while (0) +#define SLAB_STATS_INC_ERR(x) (atomic_inc(&(x)->c_errors)) +#else +#define SLAB_STATS_INC_ACTIVE(x) +#define SLAB_STATS_DEC_ACTIVE(x) +#define SLAB_STATS_INC_ALLOCED(x) +#define SLAB_STATS_INC_GROWN(x) +#define SLAB_STATS_INC_REAPED(x) +#define SLAB_STATS_SET_HIGH(x) +#define SLAB_STATS_INC_ERR(x) +#endif /* SLAB_STATS */ + +#if SLAB_SELFTEST +#if !SLAB_DEBUG_SUPPORT +#error Debug support needed for self-test +#endif +static void kmem_self_test(void); +#endif /* SLAB_SELFTEST */ + +/* c_magic - used to detect 'out of slabs' in __kmem_cache_alloc() */ +#define SLAB_C_MAGIC 0x4F17A36DUL + +/* maximum size of an obj (in 2^order pages) */ +#define SLAB_OBJ_MAX_ORDER 5 /* 32 pages */ + +/* maximum num of pages for a slab (prevents large requests to the VM layer) */ +#define SLAB_MAX_GFP_ORDER 5 /* 32 pages */ + +/* the 'preferred' minimum num of objs per slab - maybe less for large objs */ +#define SLAB_MIN_OBJS_PER_SLAB 4 + +/* If the num of objs per slab is <= SLAB_MIN_OBJS_PER_SLAB, + * then the page order must be less than this before trying the next order. + */ +#define SLAB_BREAK_GFP_ORDER_HI 2 +#define SLAB_BREAK_GFP_ORDER_LO 1 +static int slab_break_gfp_order = SLAB_BREAK_GFP_ORDER_LO; + +/* Macros for storing/retrieving the cachep and or slab from the + * global 'mem_map'. With off-slab bufctls, these are used to find the + * slab an obj belongs to. With kmalloc(), and kfree(), these are used + * to find the cache which an obj belongs to. + */ +#define SLAB_SET_PAGE_CACHE(pg,x) ((pg)->list.next = (struct list_head *)(x)) +#define SLAB_GET_PAGE_CACHE(pg) ((kmem_cache_t *)(pg)->list.next) +#define SLAB_SET_PAGE_SLAB(pg,x) ((pg)->list.prev = (struct list_head *)(x)) +#define SLAB_GET_PAGE_SLAB(pg) ((kmem_slab_t *)(pg)->list.prev) + +/* Size description struct for general caches. */ +typedef struct cache_sizes { + size_t cs_size; + kmem_cache_t *cs_cachep; +} cache_sizes_t; + +static cache_sizes_t cache_sizes[] = { +#if PAGE_SIZE == 4096 + { 32, NULL}, +#endif + { 64, NULL}, + { 128, NULL}, + { 256, NULL}, + { 512, NULL}, + {1024, NULL}, + {2048, NULL}, + {4096, NULL}, + {8192, NULL}, + {16384, NULL}, + {32768, NULL}, + {65536, NULL}, + {131072, NULL}, + {0, NULL} +}; + +/* Names for the general caches. Not placed into the sizes struct for + * a good reason; the string ptr is not needed while searching in kmalloc(), + * and would 'get-in-the-way' in the h/w cache. + */ +static char *cache_sizes_name[] = { +#if PAGE_SIZE == 4096 + "size-32", +#endif + "size-64", + "size-128", + "size-256", + "size-512", + "size-1024", + "size-2048", + "size-4096", + "size-8192", + "size-16384", + "size-32768", + "size-65536", + "size-131072" +}; + +/* internal cache of cache description objs */ +static kmem_cache_t cache_cache = { +/* freep, flags */ kmem_slab_end(&cache_cache), SLAB_NO_REAP, +/* offset, num */ sizeof(kmem_cache_t), 0, +/* c_magic, c_inuse */ SLAB_C_MAGIC, 0, +/* firstp, lastp */ kmem_slab_end(&cache_cache), kmem_slab_end(&cache_cache), +/* spinlock */ SPIN_LOCK_UNLOCKED, +/* growing */ 0, +/* dflags */ 0, +/* org_size, gfp */ 0, 0, +/* ctor, dtor, align */ NULL, NULL, L1_CACHE_BYTES, +/* colour, colour_next */ 0, 0, +/* failures */ 0, +/* name */ "kmem_cache", +/* nextp */ &cache_cache, +/* index */ NULL, +}; + +/* Guard access to the cache-chain. */ +static struct semaphore cache_chain_sem; + +/* Place maintainer for reaping. */ +static kmem_cache_t *clock_searchp = &cache_cache; + +/* Internal slab management cache, for when slab management is off-slab. */ +static kmem_cache_t *cache_slabp = NULL; + +/* Max number of objs-per-slab for caches which use bufctl's. + * Needed to avoid a possible looping condition in kmem_cache_grow(). + */ +static unsigned long bufctl_limit = 0; + +/* Initialisation - setup the `cache' cache. */ +void __init kmem_cache_init(void) +{ + size_t size, i; + +#define kmem_slab_offset(x) ((unsigned long)&((kmem_slab_t *)0)->x) +#define kmem_slab_diff(a,b) (kmem_slab_offset(a) - kmem_slab_offset(b)) +#define kmem_cache_offset(x) ((unsigned long)&((kmem_cache_t *)0)->x) +#define kmem_cache_diff(a,b) (kmem_cache_offset(a) - kmem_cache_offset(b)) + + /* Sanity checks... */ + if (kmem_cache_diff(c_firstp, c_magic) != kmem_slab_diff(s_nextp, s_magic) || + kmem_cache_diff(c_firstp, c_inuse) != kmem_slab_diff(s_nextp, s_inuse) || + ((kmem_cache_offset(c_lastp) - + ((unsigned long) kmem_slab_end((kmem_cache_t*)NULL))) != + kmem_slab_offset(s_prevp)) || + kmem_cache_diff(c_lastp, c_firstp) != kmem_slab_diff(s_prevp, s_nextp)) { + /* Offsets to the magic are incorrect, either the structures have + * been incorrectly changed, or adjustments are needed for your + * architecture. + */ + panic("kmem_cache_init(): Offsets are wrong - I've been messed with!"); + /* NOTREACHED */ + } +#undef kmem_cache_offset +#undef kmem_cache_diff +#undef kmem_slab_offset +#undef kmem_slab_diff + + init_MUTEX(&cache_chain_sem); + + size = cache_cache.c_offset + sizeof(kmem_bufctl_t); + size += (L1_CACHE_BYTES-1); + size &= ~(L1_CACHE_BYTES-1); + cache_cache.c_offset = size-sizeof(kmem_bufctl_t); + + i = (PAGE_SIZE< (32 << 20) >> PAGE_SHIFT) + slab_break_gfp_order = SLAB_BREAK_GFP_ORDER_HI; +} + +/* Initialisation - setup remaining internal and general caches. + * Called after the gfp() functions have been enabled, and before smp_init(). + */ +void __init kmem_cache_sizes_init(void) +{ + unsigned int found = 0; + + cache_slabp = kmem_cache_create("slab_cache", sizeof(kmem_slab_t), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + if (cache_slabp) { + char **names = cache_sizes_name; + cache_sizes_t *sizes = cache_sizes; + do { + /* For performance, all the general caches are L1 aligned. + * This should be particularly beneficial on SMP boxes, as it + * eliminates "false sharing". + * Note for systems short on memory removing the alignment will + * allow tighter packing of the smaller caches. */ + if (!(sizes->cs_cachep = + kmem_cache_create(*names++, sizes->cs_size, + 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) + goto panic_time; + if (!found) { + /* Inc off-slab bufctl limit until the ceiling is hit. */ + if (SLAB_BUFCTL(sizes->cs_cachep->c_flags)) + found++; + else + bufctl_limit = + (sizes->cs_size/sizeof(kmem_bufctl_t)); + } + sizes->cs_cachep->c_flags |= SLAB_CFLGS_GENERAL; + sizes++; + } while (sizes->cs_size); +#if SLAB_SELFTEST + kmem_self_test(); +#endif /* SLAB_SELFTEST */ + return; + } +panic_time: + panic("kmem_cache_sizes_init: Error creating caches"); + /* NOTREACHED */ +} + +/* Interface to system's page allocator. Dma pts to non-zero if all + * of memory is DMAable. No need to hold the cache-lock. + */ +static inline void * +kmem_getpages(kmem_cache_t *cachep, unsigned long flags, unsigned int *dma) +{ + void *addr; + + *dma = flags & SLAB_DMA; + addr = (void*) __get_free_pages(flags, cachep->c_gfporder); + /* Assume that now we have the pages no one else can legally + * messes with the 'struct page's. + * However vm_scan() might try to test the structure to see if + * it is a named-page or buffer-page. The members it tests are + * of no interest here..... + */ + if (!*dma && addr) { + /* Need to check if can dma. */ + struct page *page = mem_map + MAP_NR(addr); + *dma = 1<c_gfporder; + while ((*dma)--) { + if (!PageDMA(page)) { + *dma = 0; + break; + } + page++; + } + } + return addr; +} + +/* Interface to system's page release. */ +static inline void +kmem_freepages(kmem_cache_t *cachep, void *addr) +{ + unsigned long i = (1<c_gfporder); + struct page *page = &mem_map[MAP_NR(addr)]; + + /* free_pages() does not clear the type bit - we do that. + * The pages have been unlinked from their cache-slab, + * but their 'struct page's might be accessed in + * vm_scan(). Shouldn't be a worry. + */ + while (i--) { + PageClearSlab(page); + page++; + } + free_pages((unsigned long)addr, cachep->c_gfporder); +} + +#if SLAB_DEBUG_SUPPORT +static inline void +kmem_poison_obj(kmem_cache_t *cachep, void *addr) +{ + memset(addr, SLAB_POISON_BYTE, cachep->c_org_size); + *(unsigned char *)(addr+cachep->c_org_size-1) = SLAB_POISON_END; +} + +static inline int +kmem_check_poison_obj(kmem_cache_t *cachep, void *addr) +{ + void *end; + end = memchr(addr, SLAB_POISON_END, cachep->c_org_size); + if (end != (addr+cachep->c_org_size-1)) + return 1; + return 0; +} +#endif /* SLAB_DEBUG_SUPPORT */ + +/* Three slab chain funcs - all called with ints disabled and the appropriate + * cache-lock held. + */ +static inline void +kmem_slab_unlink(kmem_slab_t *slabp) +{ + kmem_slab_t *prevp = slabp->s_prevp; + kmem_slab_t *nextp = slabp->s_nextp; + prevp->s_nextp = nextp; + nextp->s_prevp = prevp; +} + +static inline void +kmem_slab_link_end(kmem_cache_t *cachep, kmem_slab_t *slabp) +{ + kmem_slab_t *lastp = cachep->c_lastp; + slabp->s_nextp = kmem_slab_end(cachep); + slabp->s_prevp = lastp; + cachep->c_lastp = slabp; + lastp->s_nextp = slabp; +} + +static inline void +kmem_slab_link_free(kmem_cache_t *cachep, kmem_slab_t *slabp) +{ + kmem_slab_t *nextp = cachep->c_freep; + kmem_slab_t *prevp = nextp->s_prevp; + slabp->s_nextp = nextp; + slabp->s_prevp = prevp; + nextp->s_prevp = slabp; + slabp->s_prevp->s_nextp = slabp; +} + +/* Destroy all the objs in a slab, and release the mem back to the system. + * Before calling the slab must have been unlinked from the cache. + * The cache-lock is not held/needed. + */ +static void +kmem_slab_destroy(kmem_cache_t *cachep, kmem_slab_t *slabp) +{ + if (cachep->c_dtor +#if SLAB_DEBUG_SUPPORT + || cachep->c_flags & (SLAB_POISON | SLAB_RED_ZONE) +#endif /*SLAB_DEBUG_SUPPORT*/ + ) { + /* Doesn't use the bufctl ptrs to find objs. */ + unsigned long num = cachep->c_num; + void *objp = slabp->s_mem; + do { +#if SLAB_DEBUG_SUPPORT + if (cachep->c_flags & SLAB_RED_ZONE) { + if (*((unsigned long*)(objp)) != SLAB_RED_MAGIC1) + printk(KERN_ERR "kmem_slab_destroy: " + "Bad front redzone - %s\n", + cachep->c_name); + objp += BYTES_PER_WORD; + if (*((unsigned long*)(objp+cachep->c_org_size)) != + SLAB_RED_MAGIC1) + printk(KERN_ERR "kmem_slab_destroy: " + "Bad rear redzone - %s\n", + cachep->c_name); + } + if (cachep->c_dtor) +#endif /*SLAB_DEBUG_SUPPORT*/ + (cachep->c_dtor)(objp, cachep, 0); +#if SLAB_DEBUG_SUPPORT + else if (cachep->c_flags & SLAB_POISON) { + if (kmem_check_poison_obj(cachep, objp)) + printk(KERN_ERR "kmem_slab_destroy: " + "Bad poison - %s\n", cachep->c_name); + } + if (cachep->c_flags & SLAB_RED_ZONE) + objp -= BYTES_PER_WORD; +#endif /* SLAB_DEBUG_SUPPORT */ + objp += cachep->c_offset; + if (!slabp->s_index) + objp += sizeof(kmem_bufctl_t); + } while (--num); + } + + slabp->s_magic = SLAB_MAGIC_DESTROYED; + if (slabp->s_index) + kmem_cache_free(cachep->c_index_cachep, slabp->s_index); + kmem_freepages(cachep, slabp->s_mem-slabp->s_offset); + if (SLAB_OFF_SLAB(cachep->c_flags)) + kmem_cache_free(cache_slabp, slabp); +} + +/* Cal the num objs, wastage, and bytes left over for a given slab size. */ +static inline size_t +kmem_cache_cal_waste(unsigned long gfporder, size_t size, size_t extra, + unsigned long flags, size_t *left_over, unsigned long *num) +{ + size_t wastage = PAGE_SIZE< ((1< size) { + printk("%sOffset weird %d - %s\n", func_nm, (int) offset, name); + offset = 0; + } + +#if SLAB_DEBUG_SUPPORT + if ((flags & SLAB_DEBUG_INITIAL) && !ctor) { + /* No constructor, but inital state check requested */ + printk("%sNo con, but init state check requested - %s\n", func_nm, name); + flags &= ~SLAB_DEBUG_INITIAL; + } + + if ((flags & SLAB_POISON) && ctor) { + /* request for poisoning, but we can't do that with a constructor */ + printk("%sPoisoning requested, but con given - %s\n", func_nm, name); + flags &= ~SLAB_POISON; + } +#if 0 + if ((flags & SLAB_HIGH_PACK) && ctor) { + printk("%sHigh pack requested, but con given - %s\n", func_nm, name); + flags &= ~SLAB_HIGH_PACK; + } + if ((flags & SLAB_HIGH_PACK) && (flags & (SLAB_POISON|SLAB_RED_ZONE))) { + printk("%sHigh pack requested, but with poisoning/red-zoning - %s\n", + func_nm, name); + flags &= ~SLAB_HIGH_PACK; + } +#endif +#endif /* SLAB_DEBUG_SUPPORT */ +#endif /* SLAB_MGMT_CHECKS */ + + /* Always checks flags, a caller might be expecting debug + * support which isn't available. + */ + if (flags & ~SLAB_C_MASK) { + printk("%sIllgl flg %lX - %s\n", func_nm, flags, name); + flags &= SLAB_C_MASK; + } + + /* Get cache's description obj. */ + cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL); + if (!cachep) + goto opps; + memset(cachep, 0, sizeof(kmem_cache_t)); + + /* Check that size is in terms of words. This is needed to avoid + * unaligned accesses for some archs when redzoning is used, and makes + * sure any on-slab bufctl's are also correctly aligned. + */ + if (size & (BYTES_PER_WORD-1)) { + size += (BYTES_PER_WORD-1); + size &= ~(BYTES_PER_WORD-1); + printk("%sForcing size word alignment - %s\n", func_nm, name); + } + + cachep->c_org_size = size; +#if SLAB_DEBUG_SUPPORT + if (flags & SLAB_RED_ZONE) { + /* There is no point trying to honour cache alignment when redzoning. */ + flags &= ~SLAB_HWCACHE_ALIGN; + size += 2*BYTES_PER_WORD; /* words for redzone */ + } +#endif /* SLAB_DEBUG_SUPPORT */ + + align = BYTES_PER_WORD; + if (flags & SLAB_HWCACHE_ALIGN) + align = L1_CACHE_BYTES; + + /* Determine if the slab management and/or bufclts are 'on' or 'off' slab. */ + extra = sizeof(kmem_bufctl_t); + if (size < (PAGE_SIZE>>3)) { + /* Size is small(ish). Use packing where bufctl size per + * obj is low, and slab management is on-slab. + */ +#if 0 + if ((flags & SLAB_HIGH_PACK)) { + /* Special high packing for small objects + * (mainly for vm_mapping structs, but + * others can use it). + */ + if (size == (L1_CACHE_BYTES/4) || size == (L1_CACHE_BYTES/2) || + size == L1_CACHE_BYTES) { + /* The bufctl is stored with the object. */ + extra = 0; + } else + flags &= ~SLAB_HIGH_PACK; + } +#endif + } else { + /* Size is large, assume best to place the slab management obj + * off-slab (should allow better packing of objs). + */ + flags |= SLAB_CFLGS_OFF_SLAB; + if (!(size & ~PAGE_MASK) || size == (PAGE_SIZE/2) + || size == (PAGE_SIZE/4) || size == (PAGE_SIZE/8)) { + /* To avoid waste the bufctls are off-slab... */ + flags |= SLAB_CFLGS_BUFCTL; + extra = 0; + } /* else slab management is off-slab, but freelist pointers are on. */ + } + size += extra; + + if (flags & SLAB_HWCACHE_ALIGN) { + /* Need to adjust size so that objs are cache aligned. */ + if (size > (L1_CACHE_BYTES/2)) { + size_t words = size % L1_CACHE_BYTES; + if (words) + size += (L1_CACHE_BYTES-words); + } else { + /* Small obj size, can get at least two per cache line. */ + int num_per_line = L1_CACHE_BYTES/size; + left_over = L1_CACHE_BYTES - (num_per_line*size); + if (left_over) { + /* Need to adjust size so objs cache align. */ + if (left_over%num_per_line) { + /* Odd num of objs per line - fixup. */ + num_per_line--; + left_over += size; + } + size += (left_over/num_per_line); + } + } + } else if (!(size%L1_CACHE_BYTES)) { + /* Size happens to cache align... */ + flags |= SLAB_HWCACHE_ALIGN; + align = L1_CACHE_BYTES; + } + + /* Cal size (in pages) of slabs, and the num of objs per slab. + * This could be made much more intelligent. For now, try to avoid + * using high page-orders for slabs. When the gfp() funcs are more + * friendly towards high-order requests, this should be changed. + */ + do { + size_t wastage; + unsigned int break_flag = 0; +cal_wastage: + wastage = kmem_cache_cal_waste(cachep->c_gfporder, size, extra, + flags, &left_over, &cachep->c_num); + if (!cachep->c_num) + goto next; + if (break_flag) + break; + if (SLAB_BUFCTL(flags) && cachep->c_num > bufctl_limit) { + /* Oops, this num of objs will cause problems. */ + cachep->c_gfporder--; + break_flag++; + goto cal_wastage; + } + if (cachep->c_gfporder == SLAB_MAX_GFP_ORDER) + break; + + /* Large num of objs is good, but v. large slabs are currently + * bad for the gfp()s. + */ + if (cachep->c_num <= SLAB_MIN_OBJS_PER_SLAB) { + if (cachep->c_gfporder < slab_break_gfp_order) + goto next; + } + + /* Stop caches with small objs having a large num of pages. */ + if (left_over <= slab_align_size) + break; + if ((wastage*8) <= (PAGE_SIZE<c_gfporder)) + break; /* Acceptable internal fragmentation. */ +next: + cachep->c_gfporder++; + } while (1); + + /* If the slab has been placed off-slab, and we have enough space then + * move it on-slab. This is at the expense of any extra colouring. + */ + if ((flags & SLAB_CFLGS_OFF_SLAB) && !SLAB_BUFCTL(flags) && + left_over >= slab_align_size) { + flags &= ~SLAB_CFLGS_OFF_SLAB; + left_over -= slab_align_size; + } + + /* Offset must be a multiple of the alignment. */ + offset += (align-1); + offset &= ~(align-1); + + /* Mess around with the offset alignment. */ + if (!left_over) { + offset = 0; + } else if (left_over < offset) { + offset = align; + if (flags & SLAB_HWCACHE_ALIGN) { + if (left_over < offset) + offset = 0; + } else { + /* Offset is BYTES_PER_WORD, and left_over is at + * least BYTES_PER_WORD. + */ + if (left_over >= (BYTES_PER_WORD*2)) { + offset >>= 1; + if (left_over >= (BYTES_PER_WORD*4)) + offset >>= 1; + } + } + } else if (!offset) { + /* No offset requested, but space enough - give one. */ + offset = left_over/align; + if (flags & SLAB_HWCACHE_ALIGN) { + if (offset >= 8) { + /* A large number of colours - use a larger alignment. */ + align <<= 1; + } + } else { + if (offset >= 10) { + align <<= 1; + if (offset >= 16) + align <<= 1; + } + } + offset = align; + } + +#if 0 +printk("%s: Left_over:%d Align:%d Size:%d\n", name, left_over, offset, size); +#endif + + if ((cachep->c_align = (unsigned long) offset)) + cachep->c_colour = (left_over/offset); + cachep->c_colour_next = cachep->c_colour; + + /* If the bufctl's are on-slab, c_offset does not include the size of bufctl. */ + if (!SLAB_BUFCTL(flags)) + size -= sizeof(kmem_bufctl_t); + else + cachep->c_index_cachep = + kmem_find_general_cachep(cachep->c_num*sizeof(kmem_bufctl_t)); + cachep->c_offset = (unsigned long) size; + cachep->c_freep = kmem_slab_end(cachep); + cachep->c_firstp = kmem_slab_end(cachep); + cachep->c_lastp = kmem_slab_end(cachep); + cachep->c_flags = flags; + cachep->c_ctor = ctor; + cachep->c_dtor = dtor; + cachep->c_magic = SLAB_C_MAGIC; + cachep->c_name = name; /* Simply point to the name. */ + spin_lock_init(&cachep->c_spinlock); + + /* Need the semaphore to access the chain. */ + down(&cache_chain_sem); + searchp = &cache_cache; + do { + /* The name field is constant - no lock needed. */ + if (!strcmp(searchp->c_name, name)) { + printk("%sDup name - %s\n", func_nm, name); + break; + } + searchp = searchp->c_nextp; + } while (searchp != &cache_cache); + + /* There is no reason to lock our new cache before we + * link it in - no one knows about it yet... + */ + cachep->c_nextp = cache_cache.c_nextp; + cache_cache.c_nextp = cachep; + up(&cache_chain_sem); +opps: + return cachep; +} + +/* + * This check if the kmem_cache_t pointer is chained in the cache_cache + * list. -arca + */ +static int is_chained_kmem_cache(kmem_cache_t * cachep) +{ + kmem_cache_t * searchp; + int ret = 0; + + /* Find the cache in the chain of caches. */ + down(&cache_chain_sem); + for (searchp = &cache_cache; searchp->c_nextp != &cache_cache; + searchp = searchp->c_nextp) { + if (searchp->c_nextp != cachep) + continue; + + /* Accessing clock_searchp is safe - we hold the mutex. */ + if (cachep == clock_searchp) + clock_searchp = cachep->c_nextp; + ret = 1; + break; + } + up(&cache_chain_sem); + + return ret; +} + +/* returns 0 if every slab is been freed -arca */ +static int __kmem_cache_shrink(kmem_cache_t *cachep) +{ + kmem_slab_t *slabp; + int ret; + + spin_lock_irq(&cachep->c_spinlock); + + /* If the cache is growing, stop shrinking. */ + while (!cachep->c_growing) { + slabp = cachep->c_lastp; + if (slabp->s_inuse || slabp == kmem_slab_end(cachep)) + break; + kmem_slab_unlink(slabp); + spin_unlock_irq(&cachep->c_spinlock); + kmem_slab_destroy(cachep, slabp); + spin_lock_irq(&cachep->c_spinlock); + } + ret = 1; + if (cachep->c_lastp == kmem_slab_end(cachep)) + ret = 0; /* Cache is empty. */ + spin_unlock_irq(&cachep->c_spinlock); + return ret; +} + +/* Shrink a cache. Releases as many slabs as possible for a cache. + * It is expected this function will be called by a module when it is + * unloaded. The cache is _not_ removed, this creates too many problems and + * the cache-structure does not take up much room. A module should keep its + * cache pointer(s) in unloaded memory, so when reloaded it knows the cache + * is available. To help debugging, a zero exit status indicates all slabs + * were released. + */ +int +kmem_cache_shrink(kmem_cache_t *cachep) +{ + if (!cachep) { + printk(KERN_ERR "kmem_shrink: NULL ptr\n"); + return 2; + } + if (in_interrupt()) { + printk(KERN_ERR "kmem_shrink: Called during int - %s\n", cachep->c_name); + return 2; + } + + if (!is_chained_kmem_cache(cachep)) { + printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n", + cachep); + return 2; + } + + return __kmem_cache_shrink(cachep); +} + +/* + * Remove a kmem_cache_t object from the slab cache. When returns 0 it + * completed succesfully. -arca + */ +int kmem_cache_destroy(kmem_cache_t * cachep) +{ + kmem_cache_t * prev; + int ret; + + if (!cachep) { + printk(KERN_ERR "kmem_destroy: NULL ptr\n"); + return 1; + } + if (in_interrupt()) { + printk(KERN_ERR "kmem_destroy: Called during int - %s\n", + cachep->c_name); + return 1; + } + + ret = 0; + /* Find the cache in the chain of caches. */ + down(&cache_chain_sem); + for (prev = &cache_cache; prev->c_nextp != &cache_cache; + prev = prev->c_nextp) { + if (prev->c_nextp != cachep) + continue; + + /* Accessing clock_searchp is safe - we hold the mutex. */ + if (cachep == clock_searchp) + clock_searchp = cachep->c_nextp; + + /* remove the cachep from the cache_cache list. -arca */ + prev->c_nextp = cachep->c_nextp; + + ret = 1; + break; + } + up(&cache_chain_sem); + + if (!ret) { + printk(KERN_ERR "kmem_destroy: Invalid cache addr %p\n", + cachep); + return 1; + } + + if (__kmem_cache_shrink(cachep)) { + printk(KERN_ERR "kmem_destroy: Can't free all objects %p\n", + cachep); + down(&cache_chain_sem); + cachep->c_nextp = cache_cache.c_nextp; + cache_cache.c_nextp = cachep; + up(&cache_chain_sem); + return 1; + } + + kmem_cache_free(&cache_cache, cachep); + + return 0; +} + +/* Get the memory for a slab management obj. */ +static inline kmem_slab_t * +kmem_cache_slabmgmt(kmem_cache_t *cachep, void *objp, int local_flags) +{ + kmem_slab_t *slabp; + + if (SLAB_OFF_SLAB(cachep->c_flags)) { + /* Slab management obj is off-slab. */ + slabp = kmem_cache_alloc(cache_slabp, local_flags); + } else { + /* Slab management at end of slab memory, placed so that + * the position is 'coloured'. + */ + void *end; + end = objp + (cachep->c_num * cachep->c_offset); + if (!SLAB_BUFCTL(cachep->c_flags)) + end += (cachep->c_num * sizeof(kmem_bufctl_t)); + slabp = (kmem_slab_t *) L1_CACHE_ALIGN((unsigned long)end); + } + + if (slabp) { + slabp->s_inuse = 0; + slabp->s_dma = 0; + slabp->s_index = NULL; + } + + return slabp; +} + +static inline void +kmem_cache_init_objs(kmem_cache_t * cachep, kmem_slab_t * slabp, void *objp, + unsigned long ctor_flags) +{ + kmem_bufctl_t **bufpp = &slabp->s_freep; + unsigned long num = cachep->c_num-1; + + do { +#if SLAB_DEBUG_SUPPORT + if (cachep->c_flags & SLAB_RED_ZONE) { + *((unsigned long*)(objp)) = SLAB_RED_MAGIC1; + objp += BYTES_PER_WORD; + *((unsigned long*)(objp+cachep->c_org_size)) = SLAB_RED_MAGIC1; + } +#endif /* SLAB_DEBUG_SUPPORT */ + + /* Constructors are not allowed to allocate memory from the same cache + * which they are a constructor for. Otherwise, deadlock. + * They must also be threaded. + */ + if (cachep->c_ctor) + cachep->c_ctor(objp, cachep, ctor_flags); +#if SLAB_DEBUG_SUPPORT + else if (cachep->c_flags & SLAB_POISON) { + /* need to poison the objs */ + kmem_poison_obj(cachep, objp); + } + + if (cachep->c_flags & SLAB_RED_ZONE) { + if (*((unsigned long*)(objp+cachep->c_org_size)) != + SLAB_RED_MAGIC1) { + *((unsigned long*)(objp+cachep->c_org_size)) = + SLAB_RED_MAGIC1; + printk(KERN_ERR "kmem_init_obj: Bad rear redzone " + "after constructor - %s\n", cachep->c_name); + } + objp -= BYTES_PER_WORD; + if (*((unsigned long*)(objp)) != SLAB_RED_MAGIC1) { + *((unsigned long*)(objp)) = SLAB_RED_MAGIC1; + printk(KERN_ERR "kmem_init_obj: Bad front redzone " + "after constructor - %s\n", cachep->c_name); + } + } +#endif /* SLAB_DEBUG_SUPPORT */ + + objp += cachep->c_offset; + if (!slabp->s_index) { + *bufpp = objp; + objp += sizeof(kmem_bufctl_t); + } else + *bufpp = &slabp->s_index[num]; + bufpp = &(*bufpp)->buf_nextp; + } while (num--); + + *bufpp = NULL; +} + +/* Grow (by 1) the number of slabs within a cache. This is called by + * kmem_cache_alloc() when there are no active objs left in a cache. + */ +static int +kmem_cache_grow(kmem_cache_t * cachep, int flags) +{ + kmem_slab_t *slabp; + struct page *page; + void *objp; + size_t offset; + unsigned int dma, local_flags; + unsigned long ctor_flags; + unsigned long save_flags; + + /* Be lazy and only check for valid flags here, + * keeping it out of the critical path in kmem_cache_alloc(). + */ + if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW)) { + printk(KERN_WARNING "kmem_grow: Illegal flgs %X (correcting) - %s\n", + flags, cachep->c_name); + flags &= (SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW); + } + + if (flags & SLAB_NO_GROW) + return 0; + + /* The test for missing atomic flag is performed here, rather than + * the more obvious place, simply to reduce the critical path length + * in kmem_cache_alloc(). If a caller is slightly mis-behaving they + * will eventually be caught here (where it matters). + */ + if (in_interrupt() && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) { + printk(KERN_ERR "kmem_grow: Called nonatomically from int - %s\n", + cachep->c_name); + flags &= ~SLAB_LEVEL_MASK; + flags |= SLAB_ATOMIC; + } + ctor_flags = SLAB_CTOR_CONSTRUCTOR; + local_flags = (flags & SLAB_LEVEL_MASK); + if (local_flags == SLAB_ATOMIC) { + /* Not allowed to sleep. Need to tell a constructor about + * this - it might need to know... + */ + ctor_flags |= SLAB_CTOR_ATOMIC; + } + + /* About to mess with non-constant members - lock. */ + spin_lock_irqsave(&cachep->c_spinlock, save_flags); + + /* Get colour for the slab, and cal the next value. */ + if (!(offset = cachep->c_colour_next--)) + cachep->c_colour_next = cachep->c_colour; + offset *= cachep->c_align; + cachep->c_dflags = SLAB_CFLGS_GROWN; + + cachep->c_growing++; + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + + /* A series of memory allocations for a new slab. + * Neither the cache-chain semaphore, or cache-lock, are + * held, but the incrementing c_growing prevents this + * this cache from being reaped or shrunk. + * Note: The cache could be selected in for reaping in + * kmem_cache_reap(), but when the final test is made the + * growing value will be seen. + */ + + /* Get mem for the objs. */ + if (!(objp = kmem_getpages(cachep, flags, &dma))) + goto failed; + + /* Get slab management. */ + if (!(slabp = kmem_cache_slabmgmt(cachep, objp+offset, local_flags))) + goto opps1; + if (dma) + slabp->s_dma = 1; + if (SLAB_BUFCTL(cachep->c_flags)) { + slabp->s_index = kmem_cache_alloc(cachep->c_index_cachep, local_flags); + if (!slabp->s_index) + goto opps2; + } + + /* Nasty!!!!!! I hope this is OK. */ + dma = 1 << cachep->c_gfporder; + page = &mem_map[MAP_NR(objp)]; + do { + SLAB_SET_PAGE_CACHE(page, cachep); + SLAB_SET_PAGE_SLAB(page, slabp); + PageSetSlab(page); + page++; + } while (--dma); + + slabp->s_offset = offset; /* It will fit... */ + objp += offset; /* Address of first object. */ + slabp->s_mem = objp; + + /* For on-slab bufctls, c_offset is the distance between the start of + * an obj and its related bufctl. For off-slab bufctls, c_offset is + * the distance between objs in the slab. + */ + kmem_cache_init_objs(cachep, slabp, objp, ctor_flags); + + spin_lock_irq(&cachep->c_spinlock); + + /* Make slab active. */ + slabp->s_magic = SLAB_MAGIC_ALLOC; + kmem_slab_link_end(cachep, slabp); + if (cachep->c_freep == kmem_slab_end(cachep)) + cachep->c_freep = slabp; + SLAB_STATS_INC_GROWN(cachep); + cachep->c_failures = 0; + cachep->c_growing--; + + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + return 1; +opps2: + if (SLAB_OFF_SLAB(cachep->c_flags)) + kmem_cache_free(cache_slabp, slabp); +opps1: + kmem_freepages(cachep, objp); +failed: + spin_lock_irq(&cachep->c_spinlock); + cachep->c_growing--; + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + return 0; +} + +static void +kmem_report_alloc_err(const char *str, kmem_cache_t * cachep) +{ + if (cachep) + SLAB_STATS_INC_ERR(cachep); /* this is atomic */ + printk(KERN_ERR "kmem_alloc: %s (name=%s)\n", + str, cachep ? cachep->c_name : "unknown"); +} + +static void +kmem_report_free_err(const char *str, const void *objp, kmem_cache_t * cachep) +{ + if (cachep) + SLAB_STATS_INC_ERR(cachep); + printk(KERN_ERR "kmem_free: %s (objp=%p, name=%s)\n", + str, objp, cachep ? cachep->c_name : "unknown"); +} + +/* Search for a slab whose objs are suitable for DMA. + * Note: since testing the first free slab (in __kmem_cache_alloc()), + * ints must not have been enabled, or the cache-lock released! + */ +static inline kmem_slab_t * +kmem_cache_search_dma(kmem_cache_t * cachep) +{ + kmem_slab_t *slabp = cachep->c_freep->s_nextp; + + for (; slabp != kmem_slab_end(cachep); slabp = slabp->s_nextp) { + if (!(slabp->s_dma)) + continue; + kmem_slab_unlink(slabp); + kmem_slab_link_free(cachep, slabp); + cachep->c_freep = slabp; + break; + } + return slabp; +} + +#if SLAB_DEBUG_SUPPORT +/* Perform extra freeing checks. Currently, this check is only for caches + * that use bufctl structures within the slab. Those which use bufctl's + * from the internal cache have a reasonable check when the address is + * searched for. Called with the cache-lock held. + */ +static void * +kmem_extra_free_checks(kmem_cache_t * cachep, kmem_bufctl_t *search_bufp, + kmem_bufctl_t *bufp, void * objp) +{ + if (SLAB_BUFCTL(cachep->c_flags)) + return objp; + + /* Check slab's freelist to see if this obj is there. */ + for (; search_bufp; search_bufp = search_bufp->buf_nextp) { + if (search_bufp != bufp) + continue; + return NULL; + } + return objp; +} +#endif /* SLAB_DEBUG_SUPPORT */ + +/* Called with cache lock held. */ +static inline void +kmem_cache_full_free(kmem_cache_t *cachep, kmem_slab_t *slabp) +{ + if (slabp->s_nextp->s_inuse) { + /* Not at correct position. */ + if (cachep->c_freep == slabp) + cachep->c_freep = slabp->s_nextp; + kmem_slab_unlink(slabp); + kmem_slab_link_end(cachep, slabp); + } +} + +/* Called with cache lock held. */ +static inline void +kmem_cache_one_free(kmem_cache_t *cachep, kmem_slab_t *slabp) +{ + if (slabp->s_nextp->s_inuse == cachep->c_num) { + kmem_slab_unlink(slabp); + kmem_slab_link_free(cachep, slabp); + } + cachep->c_freep = slabp; +} + +/* Returns a ptr to an obj in the given cache. */ +static inline void * +__kmem_cache_alloc(kmem_cache_t *cachep, int flags) +{ + kmem_slab_t *slabp; + kmem_bufctl_t *bufp; + void *objp; + unsigned long save_flags; + + /* Sanity check. */ + if (!cachep) + goto nul_ptr; + spin_lock_irqsave(&cachep->c_spinlock, save_flags); +try_again: + /* Get slab alloc is to come from. */ + slabp = cachep->c_freep; + + /* Magic is a sanity check _and_ says if we need a new slab. */ + if (slabp->s_magic != SLAB_MAGIC_ALLOC) + goto alloc_new_slab; + /* DMA requests are 'rare' - keep out of the critical path. */ + if (flags & SLAB_DMA) + goto search_dma; +try_again_dma: + SLAB_STATS_INC_ALLOCED(cachep); + SLAB_STATS_INC_ACTIVE(cachep); + SLAB_STATS_SET_HIGH(cachep); + slabp->s_inuse++; + bufp = slabp->s_freep; + slabp->s_freep = bufp->buf_nextp; + if (slabp->s_freep) { +ret_obj: + if (!slabp->s_index) { + bufp->buf_slabp = slabp; + objp = ((void*)bufp) - cachep->c_offset; +finished: + /* The lock is not needed by the red-zone or poison ops, and the + * obj has been removed from the slab. Should be safe to drop + * the lock here. + */ + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); +#if SLAB_DEBUG_SUPPORT + if (cachep->c_flags & SLAB_RED_ZONE) + goto red_zone; +ret_red: + if ((cachep->c_flags & SLAB_POISON) && kmem_check_poison_obj(cachep, objp)) + kmem_report_alloc_err("Bad poison", cachep); +#endif /* SLAB_DEBUG_SUPPORT */ + return objp; + } + /* Update index ptr. */ + objp = ((bufp-slabp->s_index)*cachep->c_offset) + slabp->s_mem; + bufp->buf_objp = objp; + goto finished; + } + cachep->c_freep = slabp->s_nextp; + goto ret_obj; + +#if SLAB_DEBUG_SUPPORT +red_zone: + /* Set alloc red-zone, and check old one. */ + if (xchg((unsigned long *)objp, SLAB_RED_MAGIC2) != SLAB_RED_MAGIC1) + kmem_report_alloc_err("Bad front redzone", cachep); + objp += BYTES_PER_WORD; + if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC2) != SLAB_RED_MAGIC1) + kmem_report_alloc_err("Bad rear redzone", cachep); + goto ret_red; +#endif /* SLAB_DEBUG_SUPPORT */ + +search_dma: + if (slabp->s_dma || (slabp = kmem_cache_search_dma(cachep))!=kmem_slab_end(cachep)) + goto try_again_dma; +alloc_new_slab: + /* Either out of slabs, or magic number corruption. */ + if (slabp == kmem_slab_end(cachep)) { + /* Need a new slab. Release the lock before calling kmem_cache_grow(). + * This allows objs to be released back into the cache while growing. + */ + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + if (kmem_cache_grow(cachep, flags)) { + /* Someone may have stolen our objs. Doesn't matter, we'll + * just come back here again. + */ + spin_lock_irq(&cachep->c_spinlock); + goto try_again; + } + /* Couldn't grow, but some objs may have been freed. */ + spin_lock_irq(&cachep->c_spinlock); + if (cachep->c_freep != kmem_slab_end(cachep)) { + if ((flags & SLAB_ATOMIC) == 0) + goto try_again; + } + } else { + /* Very serious error - maybe panic() here? */ + kmem_report_alloc_err("Bad slab magic (corrupt)", cachep); + } + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); +err_exit: + return NULL; +nul_ptr: + kmem_report_alloc_err("NULL ptr", NULL); + goto err_exit; +} + +/* Release an obj back to its cache. If the obj has a constructed state, + * it should be in this state _before_ it is released. + */ +static inline void +__kmem_cache_free(kmem_cache_t *cachep, const void *objp) +{ + kmem_slab_t *slabp; + kmem_bufctl_t *bufp; + unsigned long save_flags; + + /* Basic sanity checks. */ + if (!cachep || !objp) + goto null_addr; + +#if SLAB_DEBUG_SUPPORT + /* A verify func is called without the cache-lock held. */ + if (cachep->c_flags & SLAB_DEBUG_INITIAL) + goto init_state_check; +finished_initial: + + if (cachep->c_flags & SLAB_RED_ZONE) + goto red_zone; +return_red: +#endif /* SLAB_DEBUG_SUPPORT */ + + spin_lock_irqsave(&cachep->c_spinlock, save_flags); + + if (SLAB_BUFCTL(cachep->c_flags)) + goto bufctl; + bufp = (kmem_bufctl_t *)(objp+cachep->c_offset); + + /* Get slab for the object. */ +#if 0 + /* _NASTY_IF/ELSE_, but avoids a 'distant' memory ref for some objects. + * Is this worth while? XXX + */ + if (cachep->c_flags & SLAB_HIGH_PACK) + slabp = SLAB_GET_PAGE_SLAB(&mem_map[MAP_NR(bufp)]); + else +#endif + slabp = bufp->buf_slabp; + +check_magic: + if (slabp->s_magic != SLAB_MAGIC_ALLOC) /* Sanity check. */ + goto bad_slab; + +#if SLAB_DEBUG_SUPPORT + if (cachep->c_flags & SLAB_DEBUG_FREE) + goto extra_checks; +passed_extra: +#endif /* SLAB_DEBUG_SUPPORT */ + + if (slabp->s_inuse) { /* Sanity check. */ + SLAB_STATS_DEC_ACTIVE(cachep); + slabp->s_inuse--; + bufp->buf_nextp = slabp->s_freep; + slabp->s_freep = bufp; + if (bufp->buf_nextp) { + if (slabp->s_inuse) { + /* (hopefully) The most common case. */ +finished: +#if SLAB_DEBUG_SUPPORT + if (cachep->c_flags & SLAB_POISON) { + if (cachep->c_flags & SLAB_RED_ZONE) + objp += BYTES_PER_WORD; + kmem_poison_obj(cachep, objp); + } +#endif /* SLAB_DEBUG_SUPPORT */ + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + return; + } + kmem_cache_full_free(cachep, slabp); + goto finished; + } + kmem_cache_one_free(cachep, slabp); + goto finished; + } + + /* Don't add to freelist. */ + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + kmem_report_free_err("free with no active objs", objp, cachep); + return; +bufctl: + /* No 'extra' checks are performed for objs stored this way, finding + * the obj is check enough. + */ + slabp = SLAB_GET_PAGE_SLAB(&mem_map[MAP_NR(objp)]); + bufp = &slabp->s_index[(objp - slabp->s_mem)/cachep->c_offset]; + if (bufp->buf_objp == objp) + goto check_magic; + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + kmem_report_free_err("Either bad obj addr or double free", objp, cachep); + return; +#if SLAB_DEBUG_SUPPORT +init_state_check: + /* Need to call the slab's constructor so the + * caller can perform a verify of its state (debugging). + */ + cachep->c_ctor(objp, cachep, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY); + goto finished_initial; +extra_checks: + if (!kmem_extra_free_checks(cachep, slabp->s_freep, bufp, objp)) { + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + kmem_report_free_err("Double free detected during checks", objp, cachep); + return; + } + goto passed_extra; +red_zone: + /* We do not hold the cache-lock while checking the red-zone. + */ + objp -= BYTES_PER_WORD; + if (xchg((unsigned long *)objp, SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) { + /* Either write before start of obj, or a double free. */ + kmem_report_free_err("Bad front redzone", objp, cachep); + } + if (xchg((unsigned long *)(objp+cachep->c_org_size+BYTES_PER_WORD), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) { + /* Either write past end of obj, or a double free. */ + kmem_report_free_err("Bad rear redzone", objp, cachep); + } + goto return_red; +#endif /* SLAB_DEBUG_SUPPORT */ + +bad_slab: + /* Slab doesn't contain the correct magic num. */ + if (slabp->s_magic == SLAB_MAGIC_DESTROYED) { + /* Magic num says this is a destroyed slab. */ + kmem_report_free_err("free from inactive slab", objp, cachep); + } else + kmem_report_free_err("Bad obj addr", objp, cachep); + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + +#if 1 +/* FORCE A KERNEL DUMP WHEN THIS HAPPENS. SPEAK IN ALL CAPS. GET THE CALL CHAIN. */ + BUG(); +#endif + + return; +null_addr: + kmem_report_free_err("NULL ptr", objp, cachep); + return; +} + +void * +kmem_cache_alloc(kmem_cache_t *cachep, int flags) +{ + return __kmem_cache_alloc(cachep, flags); +} + +void +kmem_cache_free(kmem_cache_t *cachep, void *objp) +{ + __kmem_cache_free(cachep, objp); +} + +void * +kmalloc(size_t size, int flags) +{ + cache_sizes_t *csizep = cache_sizes; + + for (; csizep->cs_size; csizep++) { + if (size > csizep->cs_size) + continue; + return __kmem_cache_alloc(csizep->cs_cachep, flags); + } + printk(KERN_ERR "kmalloc: Size (%lu) too large\n", (unsigned long) size); + return NULL; +} + +void +kfree(const void *objp) +{ + struct page *page; + int nr; + + if (!objp) + goto null_ptr; + nr = MAP_NR(objp); + if (nr >= max_mapnr) + goto bad_ptr; + + /* Assume we own the page structure - hence no locking. + * If someone is misbehaving (for example, calling us with a bad + * address), then access to the page structure can race with the + * kmem_slab_destroy() code. Need to add a spin_lock to each page + * structure, which would be useful in threading the gfp() functions.... + */ + page = &mem_map[nr]; + if (PageSlab(page)) { + kmem_cache_t *cachep; + + /* Here, we again assume the obj address is good. + * If it isn't, and happens to map onto another + * general cache page which has no active objs, then + * we race. + */ + cachep = SLAB_GET_PAGE_CACHE(page); + if (cachep && (cachep->c_flags & SLAB_CFLGS_GENERAL)) { + __kmem_cache_free(cachep, objp); + return; + } + } +bad_ptr: + printk(KERN_ERR "kfree: Bad obj %p\n", objp); + +#if 1 +/* FORCE A KERNEL DUMP WHEN THIS HAPPENS. SPEAK IN ALL CAPS. GET THE CALL CHAIN. */ +*(int *) 0 = 0; +#endif + +null_ptr: + return; +} + +void +kfree_s(const void *objp, size_t size) +{ + struct page *page; + int nr; + + if (!objp) + goto null_ptr; + nr = MAP_NR(objp); + if (nr >= max_mapnr) + goto null_ptr; + /* See comment in kfree() */ + page = &mem_map[nr]; + if (PageSlab(page)) { + kmem_cache_t *cachep; + /* See comment in kfree() */ + cachep = SLAB_GET_PAGE_CACHE(page); + if (cachep && cachep->c_flags & SLAB_CFLGS_GENERAL) { + if (size <= cachep->c_org_size) { /* XXX better check */ + __kmem_cache_free(cachep, objp); + return; + } + } + } +null_ptr: + printk(KERN_ERR "kfree_s: Bad obj %p\n", objp); + return; +} + +kmem_cache_t * +kmem_find_general_cachep(size_t size) +{ + cache_sizes_t *csizep = cache_sizes; + + /* This function could be moved to the header file, and + * made inline so consumers can quickly determine what + * cache pointer they require. + */ + for (; csizep->cs_size; csizep++) { + if (size > csizep->cs_size) + continue; + break; + } + return csizep->cs_cachep; +} + + +/* Called from try_to_free_page(). + * This function _cannot_ be called within a int, but it + * can be interrupted. + */ +void +kmem_cache_reap(int gfp_mask) +{ + kmem_slab_t *slabp; + kmem_cache_t *searchp; + kmem_cache_t *best_cachep; + unsigned int scan; + unsigned int reap_level; + + if (in_interrupt()) { + printk("kmem_cache_reap() called within int!\n"); + return; + } + + /* We really need a test semaphore op so we can avoid sleeping when + * !wait is true. + */ + down(&cache_chain_sem); + + scan = 10; + reap_level = 0; + + best_cachep = NULL; + searchp = clock_searchp; + do { + unsigned int full_free; + unsigned int dma_flag; + + /* It's safe to test this without holding the cache-lock. */ + if (searchp->c_flags & SLAB_NO_REAP) + goto next; + spin_lock_irq(&searchp->c_spinlock); + if (searchp->c_growing) + goto next_unlock; + if (searchp->c_dflags & SLAB_CFLGS_GROWN) { + searchp->c_dflags &= ~SLAB_CFLGS_GROWN; + goto next_unlock; + } + /* Sanity check for corruption of static values. */ + if (searchp->c_inuse || searchp->c_magic != SLAB_C_MAGIC) { + spin_unlock_irq(&searchp->c_spinlock); + printk(KERN_ERR "kmem_reap: Corrupted cache struct for %s\n", searchp->c_name); + goto next; + } + dma_flag = 0; + full_free = 0; + + /* Count the fully free slabs. There should not be not many, + * since we are holding the cache lock. + */ + slabp = searchp->c_lastp; + while (!slabp->s_inuse && slabp != kmem_slab_end(searchp)) { + slabp = slabp->s_prevp; + full_free++; + if (slabp->s_dma) + dma_flag++; + } + spin_unlock_irq(&searchp->c_spinlock); + + if ((gfp_mask & GFP_DMA) && !dma_flag) + goto next; + + if (full_free) { + if (full_free >= 10) { + best_cachep = searchp; + break; + } + + /* Try to avoid slabs with constructors and/or + * more than one page per slab (as it can be difficult + * to get high orders from gfp()). + */ + if (full_free >= reap_level) { + reap_level = full_free; + best_cachep = searchp; + } + } + goto next; +next_unlock: + spin_unlock_irq(&searchp->c_spinlock); +next: + searchp = searchp->c_nextp; + } while (--scan && searchp != clock_searchp); + + clock_searchp = searchp; + up(&cache_chain_sem); + + if (!best_cachep) { + /* couldn't find anything to reap */ + return; + } + + spin_lock_irq(&best_cachep->c_spinlock); + while (!best_cachep->c_growing && + !(slabp = best_cachep->c_lastp)->s_inuse && + slabp != kmem_slab_end(best_cachep)) { + if (gfp_mask & GFP_DMA) { + do { + if (slabp->s_dma) + goto good_dma; + slabp = slabp->s_prevp; + } while (!slabp->s_inuse && slabp != kmem_slab_end(best_cachep)); + + /* Didn't found a DMA slab (there was a free one - + * must have been become active). + */ + goto dma_fail; +good_dma: + } + if (slabp == best_cachep->c_freep) + best_cachep->c_freep = slabp->s_nextp; + kmem_slab_unlink(slabp); + SLAB_STATS_INC_REAPED(best_cachep); + + /* Safe to drop the lock. The slab is no longer linked to the + * cache. + */ + spin_unlock_irq(&best_cachep->c_spinlock); + kmem_slab_destroy(best_cachep, slabp); + spin_lock_irq(&best_cachep->c_spinlock); + } +dma_fail: + spin_unlock_irq(&best_cachep->c_spinlock); + return; +} + +#if SLAB_SELFTEST +/* A few v. simple tests */ +static void +kmem_self_test(void) +{ + kmem_cache_t *test_cachep; + + printk(KERN_INFO "kmem_test() - start\n"); + test_cachep = kmem_cache_create("test-cachep", 16, 0, SLAB_RED_ZONE|SLAB_POISON, NULL, NULL); + if (test_cachep) { + char *objp = kmem_cache_alloc(test_cachep, SLAB_KERNEL); + if (objp) { + /* Write in front and past end, red-zone test. */ + *(objp-1) = 1; + *(objp+16) = 1; + kmem_cache_free(test_cachep, objp); + + /* Mess up poisoning. */ + *objp = 10; + objp = kmem_cache_alloc(test_cachep, SLAB_KERNEL); + kmem_cache_free(test_cachep, objp); + + /* Mess up poisoning (again). */ + *objp = 10; + kmem_cache_shrink(test_cachep); + } + } + printk(KERN_INFO "kmem_test() - finished\n"); +} +#endif /* SLAB_SELFTEST */ + +#if defined(CONFIG_PROC_FS) +/* /proc/slabinfo + * cache-name num-active-objs total-objs num-active-slabs total-slabs num-pages-per-slab + */ +int +get_slabinfo(char *buf) +{ + kmem_cache_t *cachep; + kmem_slab_t *slabp; + unsigned long active_objs; + unsigned long save_flags; + unsigned long num_slabs; + unsigned long num_objs; + int len=0; +#if SLAB_STATS + unsigned long active_slabs; +#endif /* SLAB_STATS */ + + __save_flags(save_flags); + + /* Output format version, so at least we can change it without _too_ + * many complaints. + */ +#if SLAB_STATS + len = sprintf(buf, "slabinfo - version: 1.0 (statistics)\n"); +#else + len = sprintf(buf, "slabinfo - version: 1.0\n"); +#endif /* SLAB_STATS */ + down(&cache_chain_sem); + cachep = &cache_cache; + do { +#if SLAB_STATS + active_slabs = 0; +#endif /* SLAB_STATS */ + num_slabs = active_objs = 0; + spin_lock_irq(&cachep->c_spinlock); + for (slabp = cachep->c_firstp; slabp != kmem_slab_end(cachep); slabp = slabp->s_nextp) { + active_objs += slabp->s_inuse; + num_slabs++; +#if SLAB_STATS + if (slabp->s_inuse) + active_slabs++; +#endif /* SLAB_STATS */ + } + num_objs = cachep->c_num*num_slabs; +#if SLAB_STATS + { + unsigned long errors; + unsigned long high = cachep->c_high_mark; + unsigned long grown = cachep->c_grown; + unsigned long reaped = cachep->c_reaped; + unsigned long allocs = cachep->c_num_allocations; + errors = (unsigned long) atomic_read(&cachep->c_errors); + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + len += sprintf(buf+len, "%-16s %6lu %6lu %4lu %4lu %4lu %6lu %7lu %5lu %4lu %4lu\n", + cachep->c_name, active_objs, num_objs, active_slabs, num_slabs, + (1<c_gfporder)*num_slabs, + high, allocs, grown, reaped, errors); + } +#else + spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); + len += sprintf(buf+len, "%-17s %6lu %6lu\n", cachep->c_name, active_objs, num_objs); +#endif /* SLAB_STATS */ + } while ((cachep = cachep->c_nextp) != &cache_cache); + up(&cache_chain_sem); + + return len; +} +#endif /* CONFIG_PROC_FS */ diff -urN 2.3.29pre1/mm/vmalloc.c 2.3.29pre1-ikd/mm/vmalloc.c --- 2.3.29pre1/mm/vmalloc.c Sun Nov 21 03:20:44 1999 +++ 2.3.29pre1-ikd/mm/vmalloc.c Mon Nov 22 16:56:25 1999 @@ -85,7 +85,12 @@ flush_tlb_all(); } +#ifndef CONFIG_MEMLEAK static inline int alloc_area_pte(pte_t * pte, unsigned long address, unsigned long size) +#else +static inline int alloc_area_pte_wrap(pte_t * pte, unsigned long address, + unsigned long size, struct alloc_struct *IDPTR) +#endif { unsigned long end; @@ -107,7 +112,12 @@ return 0; } +#ifndef CONFIG_MEMLEAK static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size) +#else +static inline int alloc_area_pmd_wrap(pmd_t * pmd, unsigned long address, + unsigned long size, struct alloc_struct *IDPTR) +#endif { unsigned long end; @@ -127,7 +137,12 @@ return 0; } +#ifndef CONFIG_MEMLEAK int vmalloc_area_pages(unsigned long address, unsigned long size) +#else +int vmalloc_area_pages_wrap(unsigned long address, unsigned long size, + struct alloc_struct *IDPTR ) +#endif { pgd_t * dir; unsigned long end = address + size; @@ -199,7 +214,11 @@ printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr); } +#ifndef CONFIG_MEMLEAK void * vmalloc(unsigned long size) +#else +void * vmalloc_wrap(unsigned long size, struct alloc_struct *IDPTR) +#endif { void * addr; struct vm_struct *area; diff -urN 2.3.29pre1/mm/vmalloc.c.orig 2.3.29pre1-ikd/mm/vmalloc.c.orig --- 2.3.29pre1/mm/vmalloc.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/mm/vmalloc.c.orig Sun Nov 21 03:20:44 1999 @@ -0,0 +1,260 @@ +/* + * linux/mm/vmalloc.c + * + * Copyright (C) 1993 Linus Torvalds + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + */ + +#include +#include + +#include + +struct vm_struct * vmlist = NULL; + +static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return; + } + pte = pte_offset(pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t page = *pte; + pte_clear(pte); + address += PAGE_SIZE; + pte++; + if (pte_none(page)) + continue; + if (pte_present(page)) { + unsigned long map_nr = pte_pagenr(page); + if (map_nr < max_mapnr) + __free_page(mem_map + map_nr); + continue; + } + printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n"); + } while (address < end); +} + +static inline void free_area_pmd(pgd_t * dir, unsigned long address, unsigned long size) +{ + pmd_t * pmd; + unsigned long end; + + if (pgd_none(*dir)) + return; + if (pgd_bad(*dir)) { + pgd_ERROR(*dir); + pgd_clear(dir); + return; + } + pmd = pmd_offset(dir, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + free_area_pte(pmd, address, end - address); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); +} + +void vmfree_area_pages(unsigned long address, unsigned long size) +{ + pgd_t * dir; + unsigned long end = address + size; + + dir = pgd_offset_k(address); + flush_cache_all(); + do { + free_area_pmd(dir, address, end - address); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + flush_tlb_all(); +} + +static inline int alloc_area_pte(pte_t * pte, unsigned long address, unsigned long size) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + struct page * page; + if (!pte_none(*pte)) + printk(KERN_ERR "alloc_area_pte: page already exists\n"); + page = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); + if (!page) + return -ENOMEM; + set_pte(pte, mk_pte(page, PAGE_KERNEL)); + address += PAGE_SIZE; + pte++; + } while (address < end); + return 0; +} + +static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + pte_t * pte = pte_alloc_kernel(pmd, address); + if (!pte) + return -ENOMEM; + if (alloc_area_pte(pte, address, end - address)) + return -ENOMEM; + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +int vmalloc_area_pages(unsigned long address, unsigned long size) +{ + pgd_t * dir; + unsigned long end = address + size; + + dir = pgd_offset_k(address); + flush_cache_all(); + do { + pmd_t *pmd; + pgd_t olddir = *dir; + + pmd = pmd_alloc_kernel(dir, address); + if (!pmd) + return -ENOMEM; + if (alloc_area_pmd(pmd, address, end - address)) + return -ENOMEM; + if (pgd_val(olddir) != pgd_val(*dir)) + set_pgdir(address, *dir); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + flush_tlb_all(); + return 0; +} + +struct vm_struct * get_vm_area(unsigned long size, unsigned long flags) +{ + unsigned long addr; + struct vm_struct **p, *tmp, *area; + + area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL); + if (!area) + return NULL; + addr = VMALLOC_START; + for (p = &vmlist; (tmp = *p) ; p = &tmp->next) { + if (size + addr < (unsigned long) tmp->addr) + break; + addr = tmp->size + (unsigned long) tmp->addr; + if (addr > VMALLOC_END-size) { + kfree(area); + return NULL; + } + } + area->flags = flags; + area->addr = (void *)addr; + area->size = size + PAGE_SIZE; + area->next = *p; + *p = area; + return area; +} + +void vfree(void * addr) +{ + struct vm_struct **p, *tmp; + + if (!addr) + return; + if ((PAGE_SIZE-1) & (unsigned long) addr) { + printk(KERN_ERR "Trying to vfree() bad address (%p)\n", addr); + return; + } + for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) { + if (tmp->addr == addr) { + *p = tmp->next; + vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size); + kfree(tmp); + return; + } + } + printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr); +} + +void * vmalloc(unsigned long size) +{ + void * addr; + struct vm_struct *area; + + size = PAGE_ALIGN(size); + if (!size || (size >> PAGE_SHIFT) > max_mapnr) { + BUG(); + return NULL; + } + area = get_vm_area(size, VM_ALLOC); + if (!area) { + BUG(); + return NULL; + } + addr = area->addr; + if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size)) { + vfree(addr); + BUG(); + return NULL; + } + return addr; +} + +long vread(char *buf, char *addr, unsigned long count) +{ + struct vm_struct *tmp; + char *vaddr, *buf_start = buf; + unsigned long n; + + /* Don't allow overflow */ + if ((unsigned long) addr + count < count) + count = -(unsigned long) addr; + + for (tmp = vmlist; tmp; tmp = tmp->next) { + vaddr = (char *) tmp->addr; + if (addr >= vaddr + tmp->size - PAGE_SIZE) + continue; + while (addr < vaddr) { + if (count == 0) + goto finished; + put_user('\0', buf); + buf++; + addr++; + count--; + } + n = vaddr + tmp->size - PAGE_SIZE - addr; + do { + if (count == 0) + goto finished; + put_user(*addr, buf); + buf++; + addr++; + count--; + } while (--n > 0); + } +finished: + return buf - buf_start; +} diff -urN 2.3.29pre1/mm/vmalloc.c.rej 2.3.29pre1-ikd/mm/vmalloc.c.rej --- 2.3.29pre1/mm/vmalloc.c.rej Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/mm/vmalloc.c.rej Mon Nov 22 16:56:25 1999 @@ -0,0 +1,93 @@ +*************** +*** 5,17 **** + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + */ + + #include + #include + + #include + + static struct vm_struct * vmlist = NULL; + + static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size) + { + pte_t * pte; +--- 5,60 ---- + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + */ + ++ #define MEMLEAK_PASS_ALLOCATION ++ #define MEMLEAK_UNWRAP_VMALLOC ++ #define MEMLEAK_UNWRAP_SLAB ++ ++ #include + #include + #include ++ #include + + #include + + static struct vm_struct * vmlist = NULL; + ++ #if defined(CONFIG_KDB) ++ /* kdb_vmlist_check ++ * Check to determine if an address is within a vmalloced range. ++ * Parameters: ++ * starta -- Starting address of region to check ++ * enda -- Ending address of region to check ++ * Returns: ++ * 0 -- [starta,enda] not within a vmalloc area ++ * 1 -- [starta,enda] within a vmalloc area ++ * Locking: ++ * None. ++ * Remarks: ++ * Shouldn't acquire locks. Always called with all interrupts ++ * disabled and other cpus halted. Yet, if a breakpoint or fault ++ * occurs while the vmlist is in an indeterminate state, this ++ * function could fail. ++ */ ++ int ++ kdb_vmlist_check(unsigned long starta, unsigned long enda) ++ { ++ struct vm_struct *vp; ++ ++ for(vp=vmlist; vp; vp = vp->next) { ++ unsigned long end = (unsigned long)vp->addr + vp->size; ++ ++ end -= PAGE_SIZE; /* Unbias for guard page */ ++ ++ if ((starta >= (unsigned long)vp->addr) ++ && (starta < end) ++ && (enda < end)) { ++ return 1; ++ } ++ } ++ return 0; ++ } ++ #endif ++ + static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size) + { + pte_t * pte; +*************** +*** 152,158 **** + return 0; + } + + struct vm_struct * get_vm_area(unsigned long size) + { + unsigned long addr; + struct vm_struct **p, *tmp, *area; +--- 210,220 ---- + return 0; + } + ++ #ifndef CONFIG_MEMLEAK + struct vm_struct * get_vm_area(unsigned long size) ++ #else ++ struct vm_struct * get_vm_area_wrap(unsigned long size, struct alloc_struct *IDPTR) ++ #endif + { + unsigned long addr; + struct vm_struct **p, *tmp, *area; diff -urN 2.3.29pre1/net/core/skbuff.c 2.3.29pre1-ikd/net/core/skbuff.c --- 2.3.29pre1/net/core/skbuff.c Tue Oct 26 21:30:51 1999 +++ 2.3.29pre1-ikd/net/core/skbuff.c Mon Nov 22 16:56:25 1999 @@ -36,6 +36,10 @@ * The functions in this file will not compile correctly with gcc 2.4.x */ +#define MEMLEAK_PASS_ALLOCATION +#define MEMLEAK_UNWRAP_SKBUFF +#define MEMLEAK_UNWRAP_SLAB + #include #include #include @@ -65,6 +69,8 @@ #include #endif +#include + /* * Resource tracking variables */ @@ -117,7 +123,12 @@ * */ +#ifndef CONFIG_MEMLEAK struct sk_buff *alloc_skb(unsigned int size,int gfp_mask) +#else +struct sk_buff *alloc_skb_wrap(unsigned int size,int gfp_mask, + struct alloc_struct * IDPTR) +#endif { struct sk_buff *skb; u8 *data; @@ -249,7 +260,12 @@ * Duplicate an sk_buff. The new one is not owned by a socket. */ +#ifndef CONFIG_MEMLEAK struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) +#else +struct sk_buff *skb_clone_wrap(struct sk_buff *skb, int gfp_mask, + struct alloc_struct * IDPTR) +#endif { struct sk_buff *n; @@ -279,7 +295,12 @@ * This is slower, and copies the whole data area */ +#ifndef CONFIG_MEMLEAK struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask) +#else +struct sk_buff *skb_copy_wrap(struct sk_buff *skb, int gfp_mask, + struct alloc_struct * IDPTR) +#endif { struct sk_buff *n; unsigned long offset; @@ -334,7 +355,12 @@ return n; } +#ifndef CONFIG_MEMLEAK struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, int newheadroom) +#else +struct sk_buff *skb_realloc_headroom_wrap(struct sk_buff *skb, + int newheadroom, struct alloc_struct * IDPTR) +#endif { struct sk_buff *n; unsigned long offset; diff -urN 2.3.29pre1/net/core/skbuff.c.orig 2.3.29pre1-ikd/net/core/skbuff.c.orig --- 2.3.29pre1/net/core/skbuff.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/net/core/skbuff.c.orig Tue Oct 26 21:30:51 1999 @@ -0,0 +1,413 @@ +/* + * Routines having to do with the 'struct sk_buff' memory handlers. + * + * Authors: Alan Cox + * Florian La Roche + * + * Version: $Id: skbuff.c,v 1.60 1999/08/23 07:02:01 davem Exp $ + * + * Fixes: + * Alan Cox : Fixed the worst of the load balancer bugs. + * Dave Platt : Interrupt stacking fix. + * Richard Kooijman : Timestamp fixes. + * Alan Cox : Changed buffer format. + * 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 + * Alan Cox : skb_copy copy arp field + * Andi Kleen : slabified it. + * + * NOTE: + * The __skb_ routines should be called with interrupts + * disabled, or you better be *real* sure that the operation is atomic + * with respect to whatever list is being frobbed (e.g. via lock_sock() + * or via disabling bottom half handlers, etc). + * + * 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 the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * The functions in this file will not compile correctly with gcc 2.4.x + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_ATM +#include +#endif + +/* + * Resource tracking variables + */ + +static atomic_t net_skbcount = ATOMIC_INIT(0); +static atomic_t net_allocs = ATOMIC_INIT(0); +static atomic_t net_fails = ATOMIC_INIT(0); + +extern atomic_t ip_frag_mem; + +static kmem_cache_t *skbuff_head_cache; + +/* + * Keep out-of-line to prevent kernel bloat. + * __builtin_return_address is not used because it is not always + * reliable. + */ + +void skb_over_panic(struct sk_buff *skb, int sz, void *here) +{ + printk("skput:over: %p:%d put:%d dev:%s", + here, skb->len, sz, skb->dev ? skb->dev->name : ""); + *(int*)0 = 0; +} + +void skb_under_panic(struct sk_buff *skb, int sz, void *here) +{ + printk("skput:under: %p:%d put:%d dev:%s", + here, skb->len, sz, skb->dev ? skb->dev->name : ""); + *(int*)0 = 0; +} + +void show_net_buffers(void) +{ + printk("Networking buffers in use : %u\n", + atomic_read(&net_skbcount)); + printk("Total network buffer allocations : %u\n", + atomic_read(&net_allocs)); + printk("Total failed network buffer allocs : %u\n", + atomic_read(&net_fails)); +#ifdef CONFIG_INET + printk("IP fragment buffer size : %u\n", + atomic_read(&ip_frag_mem)); +#endif +} + +/* Allocate a new skbuff. We do this ourselves so we can fill in a few + * 'private' fields and also do memory statistics to find all the + * [BEEP] leaks. + * + */ + +struct sk_buff *alloc_skb(unsigned int size,int gfp_mask) +{ + struct sk_buff *skb; + u8 *data; + + if (in_interrupt() && (gfp_mask & __GFP_WAIT)) { + static int count = 0; + if (++count < 5) { + printk(KERN_ERR "alloc_skb called nonatomically " + "from interrupt %p\n", NET_CALLER(size)); + *(int*)0 = 0; + } + gfp_mask &= ~__GFP_WAIT; + } + + /* Get the HEAD */ + skb = kmem_cache_alloc(skbuff_head_cache, gfp_mask); + if (skb == NULL) + goto nohead; + + /* Get the DATA. Size must match skb_add_mtu(). */ + size = ((size + 15) & ~15); + data = kmalloc(size + sizeof(atomic_t), gfp_mask); + if (data == NULL) + goto nodata; + + /* Note that this counter is useless now - you can just look in the + * skbuff_head entry in /proc/slabinfo. We keep it only for emergency + * cases. + */ + atomic_inc(&net_allocs); + + /* XXX: does not include slab overhead */ + skb->truesize = size + sizeof(struct sk_buff); + + atomic_inc(&net_skbcount); + + /* Load the data pointers. */ + skb->head = data; + skb->data = data; + skb->tail = data; + skb->end = data + size; + + /* Set up other state */ + skb->len = 0; + skb->is_clone = 0; + skb->cloned = 0; + +#ifdef CONFIG_ATM + ATM_SKB(skb)->iovcnt = 0; +#endif + + atomic_set(&skb->users, 1); + atomic_set(skb_datarefp(skb), 1); + return skb; + +nodata: + kmem_cache_free(skbuff_head_cache, skb); +nohead: + atomic_inc(&net_fails); + return NULL; +} + + +/* + * Slab constructor for a skb head. + */ +static inline void skb_headerinit(void *p, kmem_cache_t *cache, + unsigned long flags) +{ + struct sk_buff *skb = p; + + skb->destructor = NULL; + skb->pkt_type = PACKET_HOST; /* Default type */ + skb->pkt_bridged = 0; /* Not bridged */ + skb->prev = skb->next = NULL; + skb->list = NULL; + skb->sk = NULL; + skb->stamp.tv_sec=0; /* No idea about time */ + skb->ip_summed = 0; + skb->security = 0; /* By default packets are insecure */ + skb->dst = NULL; + skb->rx_dev = NULL; +#ifdef CONFIG_NETFILTER + skb->nfmark = skb->nfreason = skb->nfcache = 0; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif +#endif + memset(skb->cb, 0, sizeof(skb->cb)); + skb->priority = 0; +} + +/* + * Free an skbuff by memory without cleaning the state. + */ +void kfree_skbmem(struct sk_buff *skb) +{ + if (!skb->cloned || atomic_dec_and_test(skb_datarefp(skb))) + kfree(skb->head); + + kmem_cache_free(skbuff_head_cache, skb); + atomic_dec(&net_skbcount); +} + +/* + * Free an sk_buff. Release anything attached to the buffer. Clean the state. + */ + +void __kfree_skb(struct sk_buff *skb) +{ + if (skb->list) { + printk(KERN_WARNING "Warning: kfree_skb passed an skb still " + "on a list (from %p).\n", NET_CALLER(skb)); + *(int*)0 = 0; + } + + dst_release(skb->dst); + if(skb->destructor) + skb->destructor(skb); +#ifdef CONFIG_NET + if(skb->rx_dev) + dev_put(skb->rx_dev); +#endif + skb_headerinit(skb, NULL, 0); /* clean state */ + kfree_skbmem(skb); +} + +/* + * Duplicate an sk_buff. The new one is not owned by a socket. + */ + +struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) +{ + struct sk_buff *n; + + n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); + if (!n) + return NULL; + + memcpy(n, skb, sizeof(*n)); + atomic_inc(skb_datarefp(skb)); + skb->cloned = 1; + + atomic_inc(&net_allocs); + atomic_inc(&net_skbcount); + dst_clone(n->dst); + n->rx_dev = NULL; + n->cloned = 1; + n->next = n->prev = NULL; + n->list = NULL; + n->sk = NULL; + n->is_clone = 1; + atomic_set(&n->users, 1); + n->destructor = NULL; + return n; +} + +/* + * This is slower, and copies the whole data area + */ + +struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask) +{ + struct sk_buff *n; + unsigned long offset; + + /* + * Allocate the copy buffer + */ + + n=alloc_skb(skb->end - skb->head, gfp_mask); + if(n==NULL) + return NULL; + + /* + * Shift between the two data areas in bytes + */ + + offset=n->head-skb->head; + + /* Set the data pointer */ + skb_reserve(n,skb->data-skb->head); + /* Set the tail pointer and length */ + skb_put(n,skb->len); + /* Copy the bytes */ + memcpy(n->head,skb->head,skb->end-skb->head); + n->csum = skb->csum; + n->list=NULL; + n->sk=NULL; + n->dev=skb->dev; + n->rx_dev=NULL; + n->priority=skb->priority; + n->protocol=skb->protocol; + n->dst=dst_clone(skb->dst); + n->h.raw=skb->h.raw+offset; + n->nh.raw=skb->nh.raw+offset; + n->mac.raw=skb->mac.raw+offset; + memcpy(n->cb, skb->cb, sizeof(skb->cb)); + n->used=skb->used; + n->is_clone=0; + atomic_set(&n->users, 1); + n->pkt_type=skb->pkt_type; + n->stamp=skb->stamp; + n->destructor = NULL; + n->security=skb->security; +#ifdef CONFIG_NETFILTER + n->nfmark=skb->nfmark; + n->nfreason=skb->nfreason; + n->nfcache=skb->nfcache; +#ifdef CONFIG_NETFILTER_DEBUG + n->nf_debug=skb->nf_debug; +#endif +#endif + return n; +} + +struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, int newheadroom) +{ + struct sk_buff *n; + unsigned long offset; + + /* + * Allocate the copy buffer + */ + + n=alloc_skb((skb->end-skb->data)+newheadroom, GFP_ATOMIC); + if(n==NULL) + return NULL; + + skb_reserve(n,newheadroom); + + /* + * Shift between the two data areas in bytes + */ + + offset=n->data-skb->data; + + /* Set the tail pointer and length */ + skb_put(n,skb->len); + /* Copy the bytes */ + memcpy(n->data,skb->data,skb->len); + n->list=NULL; + n->sk=NULL; + n->priority=skb->priority; + n->protocol=skb->protocol; + n->dev=skb->dev; + n->rx_dev=NULL; + n->dst=dst_clone(skb->dst); + n->h.raw=skb->h.raw+offset; + n->nh.raw=skb->nh.raw+offset; + n->mac.raw=skb->mac.raw+offset; + memcpy(n->cb, skb->cb, sizeof(skb->cb)); + n->used=skb->used; + n->is_clone=0; + atomic_set(&n->users, 1); + n->pkt_type=skb->pkt_type; + n->stamp=skb->stamp; + n->destructor = NULL; + n->security=skb->security; +#ifdef CONFIG_NETFILTER + n->nfmark=skb->nfmark; + n->nfreason=skb->nfreason; + n->nfcache=skb->nfcache; +#ifdef CONFIG_NETFILTER_DEBUG + n->nf_debug=skb->nf_debug; +#endif +#endif + return n; +} + +#if 0 +/* + * Tune the memory allocator for a new MTU size. + */ +void skb_add_mtu(int mtu) +{ + /* Must match allocation in alloc_skb */ + mtu = ((mtu + 15) & ~15) + sizeof(atomic_t); + + kmem_add_cache_size(mtu); +} +#endif + +void __init skb_init(void) +{ + skbuff_head_cache = kmem_cache_create("skbuff_head_cache", + sizeof(struct sk_buff), + 0, + SLAB_HWCACHE_ALIGN, + skb_headerinit, NULL); + if (!skbuff_head_cache) + panic("cannot create skbuff cache"); +} diff -urN 2.3.29pre1/net/core/sock.c 2.3.29pre1-ikd/net/core/sock.c --- 2.3.29pre1/net/core/sock.c Tue Oct 12 18:13:38 1999 +++ 2.3.29pre1-ikd/net/core/sock.c Mon Nov 22 16:56:25 1999 @@ -89,6 +89,11 @@ * 2 of the License, or (at your option) any later version. */ +#define MEMLEAK_PASS_ALLOCATION +#define MEMLEAK_UNWRAP_SOCK +#define MEMLEAK_UNWRAP_SKBUFF +#define MEMLEAK_UNWRAP_SLAB + #include #include #include @@ -129,6 +134,8 @@ #include #endif +#include + #define min(a,b) ((a)<(b)?(a):(b)) /* Run time adjustable parameters. */ @@ -495,7 +502,11 @@ * usage. */ +#ifndef CONFIG_MEMLEAK struct sock *sk_alloc(int family, int priority, int zero_it) +#else +struct sock *sk_alloc_wrap(int family, int priority, int zero_it, struct alloc_struct *IDPTR) +#endif { struct sock *sk = kmem_cache_alloc(sk_cachep, priority); @@ -571,10 +582,14 @@ sock_put(skb->sk); } +#ifndef CONFIG_MEMLEAK /* * Allocate a skb from the socket's send buffer. */ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority) +#else +struct sk_buff *sock_wmalloc_wrap(struct sock *sk, unsigned long size, int force, int priority, struct alloc_struct *IDPTR) +#endif { if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) { struct sk_buff * skb = alloc_skb(size, priority); @@ -586,10 +601,14 @@ return NULL; } +#ifndef CONFIG_MEMLEAK /* * Allocate a skb from the socket's receive buffer. */ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority) +#else +struct sk_buff *sock_rmalloc_wrap(struct sock *sk, unsigned long size, int force, int priority, struct alloc_struct *IDPTR) +#endif { if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) { struct sk_buff *skb = alloc_skb(size, priority); @@ -601,10 +620,14 @@ return NULL; } +#ifndef CONFIG_MEMLEAK /* * Allocate a memory block from the socket's option memory buffer. */ void *sock_kmalloc(struct sock *sk, int size, int priority) +#else +void *sock_kmalloc_wrap(struct sock *sk, int size, int priority, struct alloc_struct *IDPTR) +#endif { if ((unsigned)size <= sysctl_optmem_max && atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) { @@ -690,8 +713,13 @@ * Generic send/receive buffer handlers */ +#ifndef CONFIG_MEMLEAK struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigned long fallback, int noblock, int *errcode) +#else +struct sk_buff *sock_alloc_send_skb_wrap(struct sock *sk, unsigned long size, + unsigned long fallback, int noblock, int *errcode, struct alloc_struct *IDPTR) +#endif { int err; struct sk_buff *skb; diff -urN 2.3.29pre1/net/netsyms.c 2.3.29pre1-ikd/net/netsyms.c --- 2.3.29pre1/net/netsyms.c Sun Nov 21 03:20:44 1999 +++ 2.3.29pre1-ikd/net/netsyms.c Mon Nov 22 16:56:25 1999 @@ -118,10 +118,17 @@ EXPORT_SYMBOL(sock_getsockopt); EXPORT_SYMBOL(sock_sendmsg); EXPORT_SYMBOL(sock_recvmsg); +#ifndef CONFIG_MEMLEAK EXPORT_SYMBOL(sk_alloc); +#endif EXPORT_SYMBOL(sk_free); EXPORT_SYMBOL(sock_wake_async); +#ifndef CONFIG_MEMLEAK EXPORT_SYMBOL(sock_alloc_send_skb); +#else +EXPORT_SYMBOL(sk_alloc_wrap); +EXPORT_SYMBOL(sock_alloc_send_skb_wrap); +#endif EXPORT_SYMBOL(sock_init_data); EXPORT_SYMBOL(sock_no_release); EXPORT_SYMBOL(sock_no_bind); @@ -141,17 +148,28 @@ EXPORT_SYMBOL(sock_no_mmap); EXPORT_SYMBOL(sock_rfree); EXPORT_SYMBOL(sock_wfree); +#ifndef CONFIG_MEMLEAK EXPORT_SYMBOL(sock_wmalloc); EXPORT_SYMBOL(sock_rmalloc); +#else +EXPORT_SYMBOL(sock_wmalloc_wrap); +EXPORT_SYMBOL(sock_rmalloc_wrap); +#endif EXPORT_SYMBOL(sock_rspace); EXPORT_SYMBOL(skb_recv_datagram); EXPORT_SYMBOL(skb_free_datagram); EXPORT_SYMBOL(skb_copy_datagram); EXPORT_SYMBOL(skb_copy_datagram_iovec); +#ifndef CONFIG_MEMLEAK EXPORT_SYMBOL(skb_realloc_headroom); +#endif EXPORT_SYMBOL(datagram_poll); EXPORT_SYMBOL(put_cmsg); +#ifndef CONFIG_MEMLEAK EXPORT_SYMBOL(sock_kmalloc); +#else +EXPORT_SYMBOL(sock_kmalloc_wrap); +#endif EXPORT_SYMBOL(sock_kfree_s); #ifdef CONFIG_FILTER @@ -479,10 +497,19 @@ EXPORT_SYMBOL(fddi_setup); #endif /* CONFIG_FDDI */ EXPORT_SYMBOL(eth_copy_and_sum); +#ifndef CONFIG_MEMLEAK EXPORT_SYMBOL(alloc_skb); +#endif EXPORT_SYMBOL(__kfree_skb); +#ifndef CONFIG_MEMLEAK EXPORT_SYMBOL(skb_clone); EXPORT_SYMBOL(skb_copy); +#else +EXPORT_SYMBOL(alloc_skb_wrap); +EXPORT_SYMBOL(skb_clone_wrap); +EXPORT_SYMBOL(skb_copy_wrap); +EXPORT_SYMBOL(skb_realloc_headroom_wrap); +#endif EXPORT_SYMBOL(netif_rx); EXPORT_SYMBOL(dev_add_pack); EXPORT_SYMBOL(dev_remove_pack); diff -urN 2.3.29pre1/net/netsyms.c.orig 2.3.29pre1-ikd/net/netsyms.c.orig --- 2.3.29pre1/net/netsyms.c.orig Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/net/netsyms.c.orig Sun Nov 21 03:20:44 1999 @@ -0,0 +1,580 @@ +/* + * linux/net/netsyms.c + * + * Symbol table for the linux networking subsystem. Moved here to + * make life simpler in ksyms.c. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HIPPI +#include +#endif +#include +#include + +#ifdef CONFIG_BRIDGE +#include +#endif + +#ifdef CONFIG_NET +extern __u32 sysctl_wmem_max; +extern __u32 sysctl_rmem_max; +#endif + +#ifdef CONFIG_INET +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct net_proto_family inet_family_ops; + +#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE) +#include +#include +#include +#include +#include + +extern int tcp_tw_death_row_slot; +extern int sysctl_local_port_range[2]; +extern int tcp_port_rover; +extern int udp_port_rover; +#endif + +#endif + +#include + +#if defined(CONFIG_ULTRA) || defined(CONFIG_WD80x3) || \ + defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \ + defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \ + defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \ + defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \ + defined(CONFIG_LNE390) || defined(CONFIG_NE3210) || \ + defined(CONFIG_NE2K_PCI) || defined(CONFIG_APNE) || \ + defined(CONFIG_DAYNAPORT) +#include "../drivers/net/8390.h" +#endif + +#ifdef CONFIG_IPX_MODULE +extern struct datalink_proto *make_EII_client(void); +extern struct datalink_proto *make_8023_client(void); +extern void destroy_EII_client(struct datalink_proto *); +extern void destroy_8023_client(struct datalink_proto *); +#endif + +#ifdef CONFIG_ATALK_MODULE +#include +#endif + +#ifdef CONFIG_SYSCTL +extern int sysctl_max_syn_backlog; +#endif + +/* Skbuff symbols. */ +EXPORT_SYMBOL(skb_over_panic); +EXPORT_SYMBOL(skb_under_panic); + +/* Socket layer registration */ +EXPORT_SYMBOL(sock_register); +EXPORT_SYMBOL(sock_unregister); + +/* Socket locking */ +EXPORT_SYMBOL(__lock_sock); +EXPORT_SYMBOL(__release_sock); + +/* Socket layer support routines */ +EXPORT_SYMBOL(memcpy_fromiovec); +EXPORT_SYMBOL(memcpy_tokerneliovec); +EXPORT_SYMBOL(sock_create); +EXPORT_SYMBOL(sock_alloc); +EXPORT_SYMBOL(sock_release); +EXPORT_SYMBOL(sock_setsockopt); +EXPORT_SYMBOL(sock_getsockopt); +EXPORT_SYMBOL(sock_sendmsg); +EXPORT_SYMBOL(sock_recvmsg); +EXPORT_SYMBOL(sk_alloc); +EXPORT_SYMBOL(sk_free); +EXPORT_SYMBOL(sock_wake_async); +EXPORT_SYMBOL(sock_alloc_send_skb); +EXPORT_SYMBOL(sock_init_data); +EXPORT_SYMBOL(sock_no_release); +EXPORT_SYMBOL(sock_no_bind); +EXPORT_SYMBOL(sock_no_connect); +EXPORT_SYMBOL(sock_no_socketpair); +EXPORT_SYMBOL(sock_no_accept); +EXPORT_SYMBOL(sock_no_getname); +EXPORT_SYMBOL(sock_no_poll); +EXPORT_SYMBOL(sock_no_ioctl); +EXPORT_SYMBOL(sock_no_listen); +EXPORT_SYMBOL(sock_no_shutdown); +EXPORT_SYMBOL(sock_no_getsockopt); +EXPORT_SYMBOL(sock_no_setsockopt); +EXPORT_SYMBOL(sock_no_fcntl); +EXPORT_SYMBOL(sock_no_sendmsg); +EXPORT_SYMBOL(sock_no_recvmsg); +EXPORT_SYMBOL(sock_no_mmap); +EXPORT_SYMBOL(sock_rfree); +EXPORT_SYMBOL(sock_wfree); +EXPORT_SYMBOL(sock_wmalloc); +EXPORT_SYMBOL(sock_rmalloc); +EXPORT_SYMBOL(sock_rspace); +EXPORT_SYMBOL(skb_recv_datagram); +EXPORT_SYMBOL(skb_free_datagram); +EXPORT_SYMBOL(skb_copy_datagram); +EXPORT_SYMBOL(skb_copy_datagram_iovec); +EXPORT_SYMBOL(skb_realloc_headroom); +EXPORT_SYMBOL(datagram_poll); +EXPORT_SYMBOL(put_cmsg); +EXPORT_SYMBOL(sock_kmalloc); +EXPORT_SYMBOL(sock_kfree_s); + +#ifdef CONFIG_FILTER +EXPORT_SYMBOL(sk_run_filter); +#endif + +EXPORT_SYMBOL(neigh_table_init); +EXPORT_SYMBOL(neigh_table_clear); +EXPORT_SYMBOL(neigh_resolve_output); +EXPORT_SYMBOL(neigh_connected_output); +EXPORT_SYMBOL(neigh_update); +EXPORT_SYMBOL(neigh_create); +EXPORT_SYMBOL(neigh_lookup); +EXPORT_SYMBOL(__neigh_event_send); +EXPORT_SYMBOL(neigh_event_ns); +EXPORT_SYMBOL(neigh_ifdown); +#ifdef CONFIG_ARPD +EXPORT_SYMBOL(neigh_app_ns); +#endif +#ifdef CONFIG_SYSCTL +EXPORT_SYMBOL(neigh_sysctl_register); +#endif +EXPORT_SYMBOL(pneigh_lookup); +EXPORT_SYMBOL(pneigh_enqueue); +EXPORT_SYMBOL(neigh_destroy); +EXPORT_SYMBOL(neigh_parms_alloc); +EXPORT_SYMBOL(neigh_parms_release); +EXPORT_SYMBOL(neigh_rand_reach_time); +EXPORT_SYMBOL(neigh_compat_output); + +/* dst_entry */ +EXPORT_SYMBOL(dst_alloc); +EXPORT_SYMBOL(__dst_free); +EXPORT_SYMBOL(dst_destroy); + +/* misc. support routines */ +EXPORT_SYMBOL(net_ratelimit); +EXPORT_SYMBOL(net_random); +EXPORT_SYMBOL(net_srandom); + +/* Needed by smbfs.o */ +EXPORT_SYMBOL(__scm_destroy); +EXPORT_SYMBOL(__scm_send); + +/* Needed by unix.o */ +EXPORT_SYMBOL(scm_fp_dup); +EXPORT_SYMBOL(max_files); +EXPORT_SYMBOL(do_mknod); +EXPORT_SYMBOL(memcpy_toiovec); +EXPORT_SYMBOL(csum_partial); + +#ifdef CONFIG_IPX_MODULE +EXPORT_SYMBOL(make_8023_client); +EXPORT_SYMBOL(destroy_8023_client); +EXPORT_SYMBOL(make_EII_client); +EXPORT_SYMBOL(destroy_EII_client); +#endif + +EXPORT_SYMBOL(sklist_destroy_socket); +EXPORT_SYMBOL(sklist_insert_socket); + +EXPORT_SYMBOL(scm_detach_fds); + +#ifdef CONFIG_BRIDGE +EXPORT_SYMBOL(br_ioctl); +EXPORT_SYMBOL(port_info); +EXPORT_SYMBOL(br_avl_find_addr); +#endif + +#ifdef CONFIG_INET +/* Internet layer registration */ +EXPORT_SYMBOL(inet_add_protocol); +EXPORT_SYMBOL(inet_del_protocol); +EXPORT_SYMBOL(ip_route_output); +EXPORT_SYMBOL(ip_route_input); +EXPORT_SYMBOL(icmp_send); +EXPORT_SYMBOL(ip_options_compile); +EXPORT_SYMBOL(ip_options_undo); +EXPORT_SYMBOL(arp_send); +EXPORT_SYMBOL(arp_broken_ops); +EXPORT_SYMBOL(ip_id_count); +EXPORT_SYMBOL(ip_send_check); +EXPORT_SYMBOL(ip_fragment); +EXPORT_SYMBOL(inet_family_ops); +EXPORT_SYMBOL(in_aton); +EXPORT_SYMBOL(ip_mc_inc_group); +EXPORT_SYMBOL(ip_mc_dec_group); +EXPORT_SYMBOL(ip_finish_output); +EXPORT_SYMBOL(inet_dgram_ops); +EXPORT_SYMBOL(ip_cmsg_recv); +EXPORT_SYMBOL(inet_addr_type); +EXPORT_SYMBOL(inet_select_addr); +EXPORT_SYMBOL(ip_dev_find); +EXPORT_SYMBOL(inetdev_by_index); +EXPORT_SYMBOL(in_dev_finish_destroy); +EXPORT_SYMBOL(ip_defrag); + +/* Route manipulation */ +EXPORT_SYMBOL(ip_rt_ioctl); +EXPORT_SYMBOL(devinet_ioctl); + +/* needed for ip_gre -cw */ +EXPORT_SYMBOL(ip_statistics); + +#ifdef CONFIG_DLCI_MODULE +extern int (*dlci_ioctl_hook)(unsigned int, void *); +EXPORT_SYMBOL(dlci_ioctl_hook); +#endif + + +#ifdef CONFIG_IPV6 +EXPORT_SYMBOL(ipv6_addr_type); +EXPORT_SYMBOL(icmpv6_send); +#endif +#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE) +/* inet functions common to v4 and v6 */ +EXPORT_SYMBOL(inet_stream_ops); +EXPORT_SYMBOL(inet_release); +EXPORT_SYMBOL(inet_stream_connect); +EXPORT_SYMBOL(inet_dgram_connect); +EXPORT_SYMBOL(inet_accept); +EXPORT_SYMBOL(inet_poll); +EXPORT_SYMBOL(inet_listen); +EXPORT_SYMBOL(inet_shutdown); +EXPORT_SYMBOL(inet_setsockopt); +EXPORT_SYMBOL(inet_getsockopt); +EXPORT_SYMBOL(inet_sendmsg); +EXPORT_SYMBOL(inet_recvmsg); +EXPORT_SYMBOL(inet_sock_nr); +EXPORT_SYMBOL(inet_sock_destruct); +EXPORT_SYMBOL(inet_sock_release); + +/* Socket demultiplexing. */ +EXPORT_SYMBOL(tcp_ehash); +EXPORT_SYMBOL(tcp_ehash_size); +EXPORT_SYMBOL(tcp_listening_hash); +EXPORT_SYMBOL(tcp_lhash_lock); +EXPORT_SYMBOL(tcp_lhash_users); +EXPORT_SYMBOL(tcp_lhash_wait); +EXPORT_SYMBOL(tcp_listen_wlock); +EXPORT_SYMBOL(tcp_bhash); +EXPORT_SYMBOL(tcp_bhash_size); +EXPORT_SYMBOL(tcp_portalloc_lock); +EXPORT_SYMBOL(udp_hash); +EXPORT_SYMBOL(udp_hash_lock); + +EXPORT_SYMBOL(tcp_destroy_sock); +EXPORT_SYMBOL(ip_queue_xmit); +EXPORT_SYMBOL(memcpy_fromiovecend); +EXPORT_SYMBOL(csum_partial_copy_fromiovecend); +EXPORT_SYMBOL(tcp_keepalive_timer); +EXPORT_SYMBOL(tcp_v4_lookup_listener); +/* UDP/TCP exported functions for TCPv6 */ +EXPORT_SYMBOL(udp_ioctl); +EXPORT_SYMBOL(udp_connect); +EXPORT_SYMBOL(udp_disconnect); +EXPORT_SYMBOL(udp_sendmsg); +EXPORT_SYMBOL(tcp_close); +EXPORT_SYMBOL(tcp_disconnect); +EXPORT_SYMBOL(tcp_accept); +EXPORT_SYMBOL(tcp_write_wakeup); +EXPORT_SYMBOL(tcp_read_wakeup); +EXPORT_SYMBOL(tcp_write_space); +EXPORT_SYMBOL(tcp_poll); +EXPORT_SYMBOL(tcp_ioctl); +EXPORT_SYMBOL(tcp_shutdown); +EXPORT_SYMBOL(tcp_setsockopt); +EXPORT_SYMBOL(tcp_getsockopt); +EXPORT_SYMBOL(tcp_recvmsg); +EXPORT_SYMBOL(tcp_send_synack); +EXPORT_SYMBOL(tcp_check_req); +EXPORT_SYMBOL(tcp_reset_xmit_timer); +EXPORT_SYMBOL(tcp_parse_options); +EXPORT_SYMBOL(tcp_rcv_established); +EXPORT_SYMBOL(tcp_init_xmit_timers); +EXPORT_SYMBOL(tcp_clear_xmit_timers); +EXPORT_SYMBOL(tcp_slt_array); +EXPORT_SYMBOL(__tcp_inc_slow_timer); +EXPORT_SYMBOL(tcp_statistics); +EXPORT_SYMBOL(tcp_rcv_state_process); +EXPORT_SYMBOL(tcp_timewait_state_process); +EXPORT_SYMBOL(tcp_timewait_cachep); +EXPORT_SYMBOL(tcp_timewait_kill); +EXPORT_SYMBOL(tcp_do_sendmsg); +EXPORT_SYMBOL(tcp_v4_rebuild_header); +EXPORT_SYMBOL(tcp_v4_send_check); +EXPORT_SYMBOL(tcp_v4_conn_request); +EXPORT_SYMBOL(tcp_create_openreq_child); +EXPORT_SYMBOL(tcp_bucket_create); +EXPORT_SYMBOL(__tcp_put_port); +EXPORT_SYMBOL(tcp_put_port); +EXPORT_SYMBOL(tcp_inherit_port); +EXPORT_SYMBOL(tcp_v4_syn_recv_sock); +EXPORT_SYMBOL(tcp_v4_do_rcv); +EXPORT_SYMBOL(tcp_v4_connect); +EXPORT_SYMBOL(tcp_v4_hash_connecting); +EXPORT_SYMBOL(tcp_unhash); +EXPORT_SYMBOL(udp_prot); +EXPORT_SYMBOL(tcp_prot); +EXPORT_SYMBOL(tcp_openreq_cachep); +EXPORT_SYMBOL(ipv4_specific); +EXPORT_SYMBOL(tcp_simple_retransmit); +EXPORT_SYMBOL(tcp_transmit_skb); +EXPORT_SYMBOL(tcp_connect); +EXPORT_SYMBOL(tcp_make_synack); +EXPORT_SYMBOL(tcp_tw_death_row_slot); +EXPORT_SYMBOL(tcp_tw_deschedule); +EXPORT_SYMBOL(sysctl_local_port_range); +EXPORT_SYMBOL(tcp_port_rover); +EXPORT_SYMBOL(udp_port_rover); +EXPORT_SYMBOL(tcp_sync_mss); +EXPORT_SYMBOL(net_statistics); + +EXPORT_SYMBOL(xrlim_allow); + +EXPORT_SYMBOL(tcp_write_xmit); +EXPORT_SYMBOL(dev_loopback_xmit); + +#ifdef CONFIG_SYSCTL +EXPORT_SYMBOL(sysctl_max_syn_backlog); +#endif +#endif + +#ifdef CONFIG_NETLINK +EXPORT_SYMBOL(netlink_set_err); +EXPORT_SYMBOL(netlink_broadcast); +EXPORT_SYMBOL(netlink_unicast); +EXPORT_SYMBOL(netlink_kernel_create); +EXPORT_SYMBOL(netlink_dump_start); +EXPORT_SYMBOL(netlink_ack); +#if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) +EXPORT_SYMBOL(netlink_attach); +EXPORT_SYMBOL(netlink_detach); +EXPORT_SYMBOL(netlink_post); +#endif +#endif + +#ifdef CONFIG_RTNETLINK +EXPORT_SYMBOL(rtattr_parse); +EXPORT_SYMBOL(rtnetlink_links); +EXPORT_SYMBOL(__rta_fill); +EXPORT_SYMBOL(rtnetlink_dump_ifinfo); +EXPORT_SYMBOL(rtnetlink_put_metrics); +EXPORT_SYMBOL(rtnl); +EXPORT_SYMBOL(neigh_delete); +EXPORT_SYMBOL(neigh_add); +EXPORT_SYMBOL(neigh_dump_info); +#endif + +EXPORT_SYMBOL(dev_set_allmulti); +EXPORT_SYMBOL(dev_set_promiscuity); +EXPORT_SYMBOL(sklist_remove_socket); +EXPORT_SYMBOL(rtnl_sem); +EXPORT_SYMBOL(rtnl_lock); +EXPORT_SYMBOL(rtnl_unlock); + + +/* Used by at least ipip.c. */ +EXPORT_SYMBOL(ipv4_config); +EXPORT_SYMBOL(dev_open); + +/* Used by other modules */ +EXPORT_SYMBOL(in_ntoa); + +EXPORT_SYMBOL(ip_rcv); +EXPORT_SYMBOL(arp_rcv); +EXPORT_SYMBOL(arp_tbl); +EXPORT_SYMBOL(arp_find); + +#endif /* CONFIG_INET */ + +#if defined(CONFIG_ULTRA) || defined(CONFIG_WD80x3) || \ + defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \ + defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \ + defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \ + defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \ + defined(CONFIG_LNE390) || defined(CONFIG_NE3210) || \ + defined(CONFIG_NE2K_PCI) || defined(CONFIG_APNE) || \ + defined(CONFIG_DAYNAPORT) +/* If 8390 NIC support is built in, we will need these. */ +EXPORT_SYMBOL(ei_open); +EXPORT_SYMBOL(ei_close); +EXPORT_SYMBOL(ei_interrupt); +EXPORT_SYMBOL(ethdev_init); +EXPORT_SYMBOL(NS8390_init); +#endif + +#ifdef CONFIG_TR +EXPORT_SYMBOL(tr_setup); +EXPORT_SYMBOL(tr_type_trans); +EXPORT_SYMBOL(register_trdev); +EXPORT_SYMBOL(unregister_trdev); +EXPORT_SYMBOL(init_trdev); +#endif + +#ifdef CONFIG_NET_FC +EXPORT_SYMBOL(register_fcdev); +EXPORT_SYMBOL(unregister_fcdev); +EXPORT_SYMBOL(init_fcdev); +#endif + +/* Device callback registration */ +EXPORT_SYMBOL(register_netdevice_notifier); +EXPORT_SYMBOL(unregister_netdevice_notifier); + +/* support for loadable net drivers */ +#ifdef CONFIG_NET +EXPORT_SYMBOL(init_etherdev); +EXPORT_SYMBOL(loopback_dev); +EXPORT_SYMBOL(register_netdevice); +EXPORT_SYMBOL(unregister_netdevice); +EXPORT_SYMBOL(register_netdev); +EXPORT_SYMBOL(unregister_netdev); +EXPORT_SYMBOL(netdev_state_change); +EXPORT_SYMBOL(ether_setup); +EXPORT_SYMBOL(dev_new_index); +EXPORT_SYMBOL(dev_get_by_index); +EXPORT_SYMBOL(__dev_get_by_index); +EXPORT_SYMBOL(dev_get_by_name); +EXPORT_SYMBOL(__dev_get_by_name); +EXPORT_SYMBOL(netdev_finish_unregister); +EXPORT_SYMBOL(eth_type_trans); +#ifdef CONFIG_FDDI +EXPORT_SYMBOL(fddi_type_trans); +EXPORT_SYMBOL(fddi_setup); +#endif /* CONFIG_FDDI */ +EXPORT_SYMBOL(eth_copy_and_sum); +EXPORT_SYMBOL(alloc_skb); +EXPORT_SYMBOL(__kfree_skb); +EXPORT_SYMBOL(skb_clone); +EXPORT_SYMBOL(skb_copy); +EXPORT_SYMBOL(netif_rx); +EXPORT_SYMBOL(dev_add_pack); +EXPORT_SYMBOL(dev_remove_pack); +EXPORT_SYMBOL(dev_get); +EXPORT_SYMBOL(dev_alloc); +EXPORT_SYMBOL(dev_alloc_name); +#ifdef CONFIG_KMOD +EXPORT_SYMBOL(dev_load); +#endif +EXPORT_SYMBOL(dev_ioctl); +EXPORT_SYMBOL(dev_queue_xmit); +EXPORT_SYMBOL(netdev_dropping); +#ifdef CONFIG_NET_FASTROUTE +EXPORT_SYMBOL(dev_fastroute_stat); +#endif +#ifdef CONFIG_NET_HW_FLOWCONTROL +EXPORT_SYMBOL(netdev_register_fc); +EXPORT_SYMBOL(netdev_unregister_fc); +EXPORT_SYMBOL(netdev_fc_xoff); +#endif +EXPORT_SYMBOL(dev_base); +EXPORT_SYMBOL(dev_base_lock); +EXPORT_SYMBOL(dev_close); +EXPORT_SYMBOL(dev_mc_add); +EXPORT_SYMBOL(dev_mc_delete); +EXPORT_SYMBOL(dev_mc_upload); +EXPORT_SYMBOL(n_tty_ioctl); +EXPORT_SYMBOL(tty_register_ldisc); +EXPORT_SYMBOL(kill_fasync); + +EXPORT_SYMBOL(if_port_text); + +#ifdef CONFIG_HIPPI +EXPORT_SYMBOL(hippi_type_trans); +EXPORT_SYMBOL(init_hippi_dev); +EXPORT_SYMBOL(unregister_hipdev); +#endif + +EXPORT_SYMBOL(sysctl_wmem_max); +EXPORT_SYMBOL(sysctl_rmem_max); + +#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) +#include +EXPORT_SYMBOL(ltalk_setup); +#endif + + +/* Packet scheduler modules want these. */ +EXPORT_SYMBOL(qdisc_destroy); +EXPORT_SYMBOL(qdisc_reset); +EXPORT_SYMBOL(qdisc_restart); +EXPORT_SYMBOL(qdisc_head); +EXPORT_SYMBOL(qdisc_create_dflt); +EXPORT_SYMBOL(noop_qdisc); +#ifdef CONFIG_NET_SCHED +PSCHED_EXPORTLIST; +EXPORT_SYMBOL(pfifo_qdisc_ops); +EXPORT_SYMBOL(register_qdisc); +EXPORT_SYMBOL(unregister_qdisc); +EXPORT_SYMBOL(qdisc_get_rtab); +EXPORT_SYMBOL(qdisc_put_rtab); +EXPORT_SYMBOL(qdisc_copy_stats); +#ifdef CONFIG_NET_ESTIMATOR +EXPORT_SYMBOL(qdisc_new_estimator); +EXPORT_SYMBOL(qdisc_kill_estimator); +#endif +#ifdef CONFIG_NET_CLS_POLICE +EXPORT_SYMBOL(tcf_police); +EXPORT_SYMBOL(tcf_police_locate); +EXPORT_SYMBOL(tcf_police_destroy); +#ifdef CONFIG_RTNETLINK +EXPORT_SYMBOL(tcf_police_dump); +#endif +#endif +#endif +#ifdef CONFIG_NET_CLS +EXPORT_SYMBOL(register_tcf_proto_ops); +EXPORT_SYMBOL(unregister_tcf_proto_ops); +#endif +#ifdef CONFIG_NETFILTER +#include +EXPORT_SYMBOL(nf_register_hook); +EXPORT_SYMBOL(nf_unregister_hook); +EXPORT_SYMBOL(nf_register_sockopt); +EXPORT_SYMBOL(nf_unregister_sockopt); +EXPORT_SYMBOL(nf_getinfo); +EXPORT_SYMBOL(nf_reinject); +EXPORT_SYMBOL(nf_register_interest); +EXPORT_SYMBOL(nf_unregister_interest); +EXPORT_SYMBOL(nf_hook_slow); +#endif + +EXPORT_SYMBOL(register_gifconf); + +#endif /* CONFIG_NET */ diff -urN 2.3.29pre1/scripts/Makefile 2.3.29pre1-ikd/scripts/Makefile --- 2.3.29pre1/scripts/Makefile Mon Jan 18 02:29:25 1999 +++ 2.3.29pre1-ikd/scripts/Makefile Mon Nov 22 16:56:25 1999 @@ -1,6 +1,20 @@ HEADER=header.tk TAIL=tail.tk +# +# include dependency files they exist +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + +# +# Routines in this directory are external to the kernel but partake of the +# kernel namespace. Since they are external, they are not candidates for +# profiling. +# +override CFLAGS := $(CFLAGS:%-pg=%-g -c) + # Previous versions always remade kconfig.tk because they always depended # on soundscript. This runs fairly fast, and I can't find all the # Config.in files to depend on anyways. So I'll force it to remake. @@ -33,7 +47,11 @@ tkparse.o tkcond.o tkgen.o: $(HOSTCC) $(HOSTCFLAGS) -c -o $@ $(@:.o=.c) +ktrace: ktrace.o + $(CC) -o ktrace ktrace.o + clean: rm -f *~ kconfig.tk *.o tkparse mkdep split-include + rm -f ktrace include $(TOPDIR)/Rules.make diff -urN 2.3.29pre1/scripts/genkdbsym.awk 2.3.29pre1-ikd/scripts/genkdbsym.awk --- 2.3.29pre1/scripts/genkdbsym.awk Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/genkdbsym.awk Mon Nov 22 16:56:25 1999 @@ -0,0 +1,33 @@ +BEGIN { + printf("#include \n"); + printf("#include \"ksym.h\"\n\n"); + printf("\n__ksymtab_t __attribute__ ((section(\"kdbsymtab\"))) __kdbsymtab[KDBMAXSYMTABSIZE] = {\n"); + symcount = 0 + printf("/* Generated file */\n") > "ksym.h"; + printf("char __attribute__ ((section(\"kdbstrings\"))) kdb_null[]=\"\";\n") >> "ksym.h"; + } + + { + if ( $2 == "?" || index($3, "__vendorstr_") || + index($3, "__devicestr_") || + index($3, "__devices_") || + index($3, "__setup_str_") ) + next; + symname = sprintf("_kdbs%d", symcount); + printf("{%s, 0x%s},\n", symname, $1); + printf("char __attribute__ ((section(\"kdbstrings\"))) %s[] = \"%s\";\n", symname, $3) >> "ksym.h"; + symcount = symcount + 1 + } + +END { + printf(" [%d ... KDBMAXSYMTABSIZE-1] = {kdb_null, 0xf}};\n", symcount); + printf("int __attribute__ ((section(\"kdbsymtab\"))) __kdbsymtabsize = %d;\n", symcount); + printf("int __attribute__ ((section(\"kdbsymtab\"))) __kdbmaxsymtabsize = KDBMAXSYMTABSIZE;\n"); + + # Now that we know sysmcount, we can set __kdbsymtabsize to the exact + # value and reserve an additional 10% of kdbsymtab's size as free + # space for the imported symbols of kernel modules. We don't need + # very much space, as kdb only adds registered symbols at this time. + + printf("#define KDBMAXSYMTABSIZE %d\n", symcount + (symcount / 10) + 1) >> "ksym.h"; + } diff -urN 2.3.29pre1/scripts/ktrace.c 2.3.29pre1-ikd/scripts/ktrace.c --- 2.3.29pre1/scripts/ktrace.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/ktrace.c Mon Nov 22 16:56:25 1999 @@ -0,0 +1,481 @@ +/* ktrace.c + * + * Read /proc/trace and System.map (or equivalent) and print the trace entries. + * Prints the time taken between trace calls, "(????)" if the next entry for the + * current processor cannot be found. Prints the current pid, if the next entry + * for the current processor is for a different pid, prints "pid(old->new)". + * If compiled for SMP, the trace table contains the logical processor number, + * this is printed as "cpu(n)". + * + * The System.map can be the standard System.map for the kernel, in which case + * module traces will not resolve very well. It can be a merged System.map + * containing module entries as well, see make_System_map.pl for an example, + * ftp://ftp.ocs.com.au/pub/. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_TRACE +#include + +/* + * Dumbomarbitrary limits + */ + +#define LINE_LIMIT 100 +#define SYSMAP_LIMIT 30000 + +static struct trace_table * tt; + +struct sysmap_entry { + profiler_pc_t pc; + char * name; +}; + +static struct sysmap_entry sysmap_table [SYSMAP_LIMIT]; + +static int sysmap_entries = 0; +static int default_speed = 150, speed, lock = 0; +static char *default_map = "/usr/src/linux/System.map", *map, *dump; +static char *prog_name; + +static void usage(void) +{ + fprintf(stderr, "usage: %s\n", prog_name); + fprintf(stderr, "\t[--speed MHz] [-s MHz]\t\t\thow fast is your processor?\n"); + fprintf(stderr, "\t[--map System.map] [-m System.map]\twhere is your system map?\n"); + fprintf(stderr, "\t[--lock] [-l]\t\t\t\twait for the lock on /proc/trace\n"); + fprintf(stderr, "\t[--dump filename] [-d filename]\t\tread trace dump from filename\n"); + fprintf(stderr, "Default --speed is %d\n", default_speed); + fprintf(stderr, "Default --map is %s\n", default_map); + exit(1); +} + +static void read_sysmap (void) +{ + profiler_pc_t pc; + char type; + int i, len; + + FILE * file; + char str [LINE_LIMIT+1]; + + file=fopen(map, "r"); + + if (!file) { + fprintf(stderr,"System.map '%s' missing.\n", map); + usage(); + } + + sysmap_table[0].pc = 0; + sysmap_table[0].name = "
\n"; + + sysmap_entries=1; + + while (fscanf(file, "%lx %1c", &pc, &type) == 2) { + i=sysmap_entries++; + if (!fgets(str, LINE_LIMIT, file)) { + perror("ouch, System.map format error.\n"); + exit(-1); + } + sysmap_table[i].pc = pc; + sysmap_table[i].name = malloc(LINE_LIMIT); + if (!sysmap_table[i].name) { + perror("ouch, outta mem.\n"); + exit(-1); + } + /* + * Dirty trick to strip off end of line: + */ + len = strlen(str); + str[len-1]=0; + strcpy (sysmap_table[i].name, str); + } + + printf("read %d lines from System.map.\n", sysmap_entries-1); + + sysmap_table[sysmap_entries].pc = ~1; + sysmap_table[sysmap_entries].name = "
\n"; + sysmap_entries++; + + /* To be sure, to be sure :). */ + sysmap_table[sysmap_entries].pc = ~0; + sysmap_table[sysmap_entries++].name = ""; + sysmap_table[sysmap_entries].pc = ~0; + sysmap_table[sysmap_entries++].name = ""; + +/* + * for (i=0; i1) { + middle = first+(last-first)/2; + if (sysmap_table[middle].pc <= pc) + first = middle; + else + last = middle; + } + + return first; +} + +/* The trace table is a ring buffer. Convert 0 <= index < size to the + * corresponding entry, with wraparound as necessary. + */ +static inline int ring(int x) +{ + return ((x) % CONFIG_TRACE_SIZE); +} + +#if defined(CONFIG_TRACE_CPU) && (defined(__SMP__) || defined(CONFIG_SMP)) +#define CPU_PRESENT 1 +#else +#define CPU_PRESENT 0 +#endif + +static ssize_t read_dump(int fd, void *buf, size_t count) +{ + /* Find the start of the hex dump of /proc/trace, read + * and convert hex digits, storing in buf. Any garbage + * nibbles are silently ignored and treated as '0'. + */ + char line[BUFSIZ]; + int start = 0, value; + char *pline, c; + unsigned char *pbuf; + FILE *f = fdopen(fd, "r"); + if (!f) { + perror("read_dump fdopen failed"); + exit(-1); + } + pbuf = (unsigned char *) buf; + while (fgets(line, sizeof(line), f)) { + if (ferror(f)) { + perror("read_dump ferror detected"); + exit(-1); + } + if (strstr(line, "DAL: ktrace start")) { + start = 1; + continue; + } + if (start) { + if (strstr(line, "DAL: ktrace end")) + break; + pline = line; + while (*pline) { + while (*pline == '\r' || *pline == '\n') + ++pline; + if (!(c = *pline++)) + break; + value = 0; + if (c >= '0' && c <= '9') + value = c - '0'; + else if (c >= 'a' && c <= 'f') + value = c - 'a' + 10; + value <<= 4; + if (!(c = *pline++)) + break; + if (c >= '0' && c <= '9') + value += c - '0'; + else if (c >= 'a' && c <= 'f') + value += c - 'a' + 10; + if (count > 0) { + --count; + *(pbuf++) = (unsigned char) value; + } + if (count == 0) + break; + } + } + } + return(pbuf - (unsigned char *)buf); +} + +static void read_proc_info (void) +{ + int bytes, calibrate; + int i, j; +#ifdef CONFIG_TRACE_TIMESTAMP + profiler_timestamp_t min_latency; +#endif + struct trace_entry *tep1 = NULL, *tep2 = NULL; + + char *filename = "/proc/trace"; + int file; + + if (dump) + filename = dump; + + file=open(filename, O_RDONLY); + + if (!file) { + char message[BUFSIZ]; + sprintf(message, "%s missing\n", filename); + perror(message); + exit(-1); + } + if (lock && !dump && flock(file, LOCK_EX)) { + char message[BUFSIZ]; + sprintf(message, "Cannot get exclusive lock on %s\n", filename); + perror(message); + exit(-1); + } + + tt=(struct trace_table *)malloc(sizeof(*trace_table)); + + if (dump) { + printf("Reading dumped /proc/trace from %s ...", dump); + fflush(stdout); + bytes = read_dump(file, tt, sizeof(*trace_table)); + printf(" done\n"); + fflush(stdout); + } + else + bytes = read(file, tt, sizeof(*trace_table)); + + if (sizeof(*trace_table) != bytes) { + printf("something went wrong, bytes read: %d, tried: %d.\n", bytes, sizeof(*trace_table)); + exit(-1); + } + + if (lock && !dump && flock(file, LOCK_UN)) { + char message[BUFSIZ]; + sprintf(message, "Release lock on %s failed\n", filename); + perror(message); + } + + /* + * Pass 1: look for ~0 which signals calibration latencies. + * Since read_trace (fs/proc/array.c) locks the table and turns + * off mcount processing, the calibration entries should be the + * current entry and the previous TRACE_CALIBRATION_CALLS-1. + */ +#define FIRST_CALIBRATE (tt->curr_call-(TRACE_CALIBRATION_CALLS-1)) + +#ifdef CONFIG_TRACE_TIMESTAMP + min_latency = ~0; +#endif + calibrate = 0; + + if (!dump) { + /* look for read_trace in 200 entries before FIRST_CALIBRATE. + * 200 is arbitrary, normally read_trace is immediately before + * the first calibration but there is a small window between + * read_trace starting and tracing being suspended, other cpu's + * and/or interrupts can appear in that window. KAO + */ + for (j = 1; j <= 200; ++j) { + tep1 = &(tt->entries[ring(FIRST_CALIBRATE-j)]); + i = match_pc(tep1->pc); + if (!strcmp(sysmap_table[i].name," read_trace")) + break; + } + if (strcmp(sysmap_table[i].name," read_trace")) { + tep1 = &(tt->entries[ring(FIRST_CALIBRATE-1)]); + i = match_pc(tep1->pc); + fprintf(stderr, + "hmm, no 'read_trace', possibly wrong System.map?.\npc %lx proc %s\n", + tep1->pc, sysmap_table[i].name); + } + } + + for (i = FIRST_CALIBRATE; i < tt->curr_call; i++) { + tep1 = &(tt->entries[ring(i)]); + tep2 = &(tt->entries[ring(i+1)]); + if (tep1->pc == ~0 && tep2->pc == ~0) { +#ifdef CONFIG_TRACE_TIMESTAMP + profiler_timestamp_t delta; + delta = tep2->timestamp - tep1->timestamp; + if (delta < min_latency) + min_latency=delta; +#endif /* CONFIG_TRACE_TIMESTAMP */ + ++calibrate; + } + } + + if (calibrate != TRACE_CALIBRATION_CALLS-1) { + fprintf(stderr,"huh, incorrect number of calibration entries found (%d)?.\n", calibrate); +#ifdef CONFIG_TRACE_TIMESTAMP + fprintf(stderr,"using 0.39 usecs.\n"); + min_latency = 0.39*speed; + } else { + printf("calibration done, estimated measurement latency: %3.2f microseconds.\n", min_latency/(double)speed); + if (min_latency == 0) { + printf("Warning: latency is zero, does your cpu really support timestamps?\n"); + } + else + min_latency -= 10; +#endif /* CONFIG_TRACE_TIMESTAMP */ + } + printf("\n"); + + + /* Pass 2. */ + + for (i = 1; i <= CONFIG_TRACE_SIZE; i++) { + unsigned int idx; +#ifdef CONFIG_TRACE_TIMESTAMP + profiler_timestamp_t delta = -1; +#endif /* CONFIG_TRACE_TIMESTAMP */ + + tep1 = &(tt->entries[ring(tt->curr_call+i)]); + if (tep1->pc == 0) + continue; /* trace table has been cleared */ +#ifdef CONFIG_TRACE_TIMESTAMP +#if CPU_PRESENT + for (j = 1; j <= CONFIG_TRACE_SIZE-i; ++j) { + tep2 = &(tt->entries[ring(tt->curr_call+i+j)]); + if (tep2->pc == 0) + break; + if (tep1->cpu == tep2->cpu) { + delta = tep2->timestamp - tep1->timestamp; + break; + } + } +#else /* CPU_PRESENT */ + tep2 = &(tt->entries[ring(tt->curr_call+i+1)]); + if (tep2->pc != 0 && i < CONFIG_TRACE_SIZE) + delta = tep2->timestamp - tep1->timestamp; +#endif /* CPU_PRESENT */ +#endif /* CONFIG_TRACE_TIMESTAMP */ + + idx = match_pc(tep1->pc); + +#if 0 /* testing only */ +#ifdef CONFIG_TRACE_TIMESTAMP +#ifdef CONFIG_TRACE_TRUNCTIME + printf("%08x ", tep1->timestamp); +#else + printf("%08llx%08llx ", tep1->timestamp >> 32, + tep1->timestamp & 0xffffffff); +#endif +#endif /* CONFIG_TRACE_TIMESTAMP */ +#endif + printf("%08lx %s +<%lx/%lx>", + tep1->pc, + sysmap_table[idx].name, + tep1->pc-sysmap_table[idx].pc, + sysmap_table[idx+1].pc - sysmap_table[idx].pc); +#ifdef CONFIG_TRACE_TIMESTAMP + if (delta == -1) + printf(" (????)"); + else if (tep1->pc == ~0) + printf(" (%3.08f raw)", + (double)delta); + else + printf(" (%3.02f)", + (delta-min_latency)/(double)speed); +#endif /* CONFIG_TRACE_TIMESTAMP */ +#if CPU_PRESENT + printf(" cpu(%d)", tep1->cpu); +#endif +#ifdef CONFIG_TRACE_PID + if (tep1->pid == tep2->pid) + printf(" pid(%d)", tep1->pid); + else + printf(" pid(%d->%d)", tep1->pid, tep2->pid); +#endif /* CONFIG_TRACE_PID */ + printf("\n"); + } + + free(tt); + close(file); + + printf("\n"); +} + +int main(int argc, char * * argv) +{ + int c, option_index = 0; + char *endptr; + struct option long_options[] = { + {"speed", 1, 0, 's'}, + {"map", 1, 0, 'm'}, + {"lock", 0, 0, 'l'}, + {"dump", 1, 0, 'd'}, + {0, 0, 0, 0} + }; + + prog_name = argv[0]; + speed = default_speed; + map = default_map; + + while (1) { + c = getopt_long_only (argc, argv, "s:m:ld:", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 's': + speed = strtol(optarg, &endptr, 0); + if (*endptr) { + fprintf(stderr, "speed is not numeric '%s'\n", + optarg); + usage(); + } + if (speed < 0 || speed > 1000) { + fprintf(stderr, "speed must be 1-1000\n"); + usage(); + } + break; + + case 'm': + map = optarg; + break; + + case 'l': + lock = !lock; + break; + + case 'd': + dump = optarg; + break; + + case '?': + usage(); + exit(-1); + + default: + printf ("?? getopt returned character code 0%o '%c' ??\n", c, c); + } + } + + if (optind < argc) { + fprintf (stderr, "Unknown parameter '%s'\n", argv[optind]); + usage(); + exit(-1); + } + + printf("Speed: %d. Map: %s\n", speed, map); + + read_sysmap(); + read_proc_info(); + return 0; +} + +#else +#warning ktrace does nothing unless CONFIG_TRACE is set +int main(void) { return 0; } +#endif /* CONFIG_TRACE */ diff -urN 2.3.29pre1/scripts/memleak/FAQ 2.3.29pre1-ikd/scripts/memleak/FAQ --- 2.3.29pre1/scripts/memleak/FAQ Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/FAQ Mon Nov 22 16:56:25 1999 @@ -0,0 +1,83 @@ + + + how to find memory leaks + +first, since the kernel is written in C, memory leaks are hard +to find. Most if not all data given by this patch/tools are +heuristic, use common sense and testing before calling something a +'memory leak'. + +terms: + + - 'allocation point': a certain point in the kernel source where + a memory object is allocated via some allocator, eg. kmalloc() + or get_free_pages(). + + - 'allocation count': the number of not-yet-freed allocations + done at a certain allocation point. + + - 'memory leak': a 'forgotten' buffer, too many such buffers + might cause system slowdown/hangups. + + +install the patch and reboot into the new kernel. You should +see the /proc/memleak file, with such contents: + +pc7537:~> head /proc/memleak +<00000000> jiffies.c:0 (8179) +<00001000> vmalloc.c:124 (0) +<00002000> filemap.c:274 (7946) +<00003000> vmalloc.c:124 (0) +<00004000> fork.c:237 (0) +<00005000> fork.c:186 (0) +<00005800> fork.c:186 (0) +<00006000> fork.c:237 (0) +<00007000> vmalloc.c:124 (0) +<00008000> buffer.c:1349 (8156) + +The first entry is a 'special' entry. + +units are seconds since bootup when it was allocated. The 'jiffies' line +shows the current 'elapsed seconds' value. + +eg.: + +<00002000> memory.c:930 (4838) <---------------------- was allocated 4838 + seconds after boot. + ^---------------------- was allocated here + ^------- object address + + +the special entry 'jiffies.c' shows elapsed time since bootup: + +<00000000> jiffies.c:0 (5269) <---------- 5269 seconds elapsed since this + system booted. + + + +the second thing you might want to try is the 'dosum' script: + +774 buffer.c:1349 +9 console.c:322 +9 console.c:325 + +the first number is the 'allocation count', the number of memory objects +allocated in a certain FILE:LINE. If some allocation point shows a constantly +increasing allocation count, it's probably a memory leak. + +NOTE: the VM subsystems usually have very fluctuating allocation counts, +think twice before calling them a memory leak. + +piping /proc/memleak through the 'cutvm' script filters these allocations +out. + +There are other scripts too, read the comments in them to find out what +they do ... and you might want to write custom scripts yourself, if you +have a specific thing to debug. The memcheck.sh script stores the current +allocation map into a RCS tree. RCS is storing 'delta' maps very +effectively. Use "rcsdiff -r{} -r{}" to see the delta quickly. + +thats all for now, + + Ingo + diff -urN 2.3.29pre1/scripts/memleak/Makefile 2.3.29pre1-ikd/scripts/memleak/Makefile --- 2.3.29pre1/scripts/memleak/Makefile Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/Makefile Mon Nov 22 16:56:25 1999 @@ -0,0 +1,9 @@ +all: findaddr + +TMPCFLAGS=$(CFLAGS:%-pg=%) +# True userspace program, remove the __KERNEL__ flag +findaddr: findaddr.c + $(CC) $(TMPCFLAGS:%-g=%) -U__KERNEL__ -o findaddr findaddr.c + +clean: + rm -f findaddr diff -urN 2.3.29pre1/scripts/memleak/doalloc 2.3.29pre1-ikd/scripts/memleak/doalloc --- 2.3.29pre1/scripts/memleak/doalloc Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/doalloc Mon Nov 22 16:56:25 1999 @@ -0,0 +1,11 @@ +#!/bin/bash + +# +# this script post-processes files generated by 'dorun'. +# it lists allocation points and multiple allocation counts in one line +# one line shows how a particular allocation point 'evolves' in time +# + + +for N in `cut -f2 9*| sort| uniq`; do echo $N: `grep $N 9*| cut -d: -f4| cut -f1`; done + diff -urN 2.3.29pre1/scripts/memleak/docutvm 2.3.29pre1-ikd/scripts/memleak/docutvm --- 2.3.29pre1/scripts/memleak/docutvm Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/docutvm Mon Nov 22 16:56:25 1999 @@ -0,0 +1,9 @@ +#!/bin/bash + +# +# this script eliminates 'VM/buffer cache' allocations, these +# are harder to understand and their allocation count fluctuates wildly. +# + +grep -v slab.c | grep -v memory.c | grep -v swap_state.c | grep -v filemap.c | grep -v file_table.c | grep -v buffer.c | grep -v dcache.c | grep -v pgtable | grep -v mmap.c | grep -v fork.c | grep -v exec.c + diff -urN 2.3.29pre1/scripts/memleak/dodelta 2.3.29pre1-ikd/scripts/memleak/dodelta --- 2.3.29pre1/scripts/memleak/dodelta Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/dodelta Mon Nov 22 16:56:25 1999 @@ -0,0 +1,9 @@ +#!/bin/bash + +# +# same as 'doalloc', but it lists delta allocations, not full number +# of allocations +# + +for N in `cut -f2 9*| sort| uniq`; do ( P=0;F=1;for M in `grep $N 9*| cut -d: -f4| cut -f1`; do if [ "$F" = 1 ]; then F=0; FIRST=$M; fi; echo $[$M-$P]; P=$M; done; echo "DELTA: $[$M-$FIRST]";) | xargs echo $N: ; done + diff -urN 2.3.29pre1/scripts/memleak/dofind 2.3.29pre1-ikd/scripts/memleak/dofind --- 2.3.29pre1/scripts/memleak/dofind Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/dofind Mon Nov 22 16:56:25 1999 @@ -0,0 +1,14 @@ +#!/bin/bash + +# +# this script lists wether all 'currently allocated' memory +# objects are actually referenced to in the kernel ... this +# isnt a 100% sure method, but usually a 'used' object has it's address +# listed somewhere, while a 'leaked' object doesnt have any +# references anymore. +# + +cp /proc/memleak /tmp/leak3 + +for N in `cat /tmp/leak3 | cut -c2-9`; do findaddr 0x$N; done + diff -urN 2.3.29pre1/scripts/memleak/dorun 2.3.29pre1-ikd/scripts/memleak/dorun --- 2.3.29pre1/scripts/memleak/dorun Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/dorun Mon Nov 22 16:56:25 1999 @@ -0,0 +1,14 @@ +#!/bin/bash + +# +# this script puts an 'allocation summary' into the current +# directory every 10 seconds. +# +# you can analyze these files via 'doalloc' and 'dodelta', +# to find suspicious allocation points. +# + +while true; do + FILE=`date +'%y-%m-%d__%T'`; sync; sleep 10; echo $FILE; dosum > $FILE; +done + diff -urN 2.3.29pre1/scripts/memleak/dosum 2.3.29pre1-ikd/scripts/memleak/dosum --- 2.3.29pre1/scripts/memleak/dosum Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/dosum Mon Nov 22 16:56:25 1999 @@ -0,0 +1,8 @@ +#!/bin/bash + +# +# generates 'current allocation summary' +# + +(cat /proc/memleak | cut -d'(' -f1 > /tmp/leak; cat /tmp/leak )| cut -c12- | sort | gawk -- 'BEGIN{Y=0;}//{if ($0 == X) {Y=Y+1;} else {if (Y) printf ("%d\t %s\n", Y, X); Y=1;} X=$0}END{ printf ("%d\t %s\n", Y, $0);}' + diff -urN 2.3.29pre1/scripts/memleak/dotimestamp 2.3.29pre1-ikd/scripts/memleak/dotimestamp --- 2.3.29pre1/scripts/memleak/dotimestamp Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/dotimestamp Mon Nov 22 16:56:25 1999 @@ -0,0 +1,10 @@ +#!/bin/bash + +# +# this script generates a timestamp-sorted list of allocations. +# +# 'old' (low timestamp value) allocations have a higher chance +# that they are actually leaked away objects. +# + +cp /proc/memleak /tmp/leak2; sort -n -t'(' +1 /tmp/leak2 diff -urN 2.3.29pre1/scripts/memleak/findaddr.c 2.3.29pre1-ikd/scripts/memleak/findaddr.c --- 2.3.29pre1/scripts/memleak/findaddr.c Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/findaddr.c Mon Nov 22 16:56:25 1999 @@ -0,0 +1,68 @@ + +/* + * find a pointer in /proc/kcore (all system memory) + * + * a leaked object probably hasnt got any references in + * memory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define N 4096 + +char buffer [N]; + +char * fool_libc = "0x0deadbee"; + +int main(int argc, char * * argv) +{ + int file = open("/proc/kcore",O_RDONLY); + int n,i,hits=0; + unsigned int addr, pos=0, fool_addr; + + if (argc != 2) { + fprintf(stderr,"usage: findaddr 0x\n"); + exit(-1); + } + if (file==-1) { + perror("couldn't open /proc/kcore\n"); + exit(-1); + } + sscanf(argv[1],"0x%08x",&addr); + + addr--; + + sscanf(fool_libc,"0x%08x",&fool_addr); + + while ((n = read(file,buffer,N)) > 0) { + for (i=0; i<=n-sizeof(int); i++) { + + if ((*((int *)&(buffer[i])))-1 == addr) { + if (++hits) { + printf("found 0x%08x at %08x\n", addr+1, pos+i*sizeof(int)); + goto out; + } + } + + } + pos += n; + } + if (!n) + printf("0x%08x not found!\n", addr+1); +out: + return (0); +} + + diff -urN 2.3.29pre1/scripts/memleak/memcheck.sh 2.3.29pre1-ikd/scripts/memleak/memcheck.sh --- 2.3.29pre1/scripts/memleak/memcheck.sh Thu Jan 1 01:00:00 1970 +++ 2.3.29pre1-ikd/scripts/memleak/memcheck.sh Mon Nov 22 16:56:25 1999 @@ -0,0 +1,7 @@ +#!/bin/bash +TEMPFILE=`tempfile` +LOGFILE=/var/log/memleak + cat /proc/memleak | cut -c12- | sort | gawk -- 'BEGIN{Y=0;}//{if ($0 == X) {Y=Y+1;} else {if (Y) printf ("%d\t %s\n", Y, X); Y=1;} X=$0}END{printf ("%d\t %s\n", Y, $0);}' > $TEMPFILE +co -l $LOGFILE &>/dev/null +mv $TEMPFILE $LOGFILE +echo "." | ci $LOGFILE &>/dev/null